From 342bca7f4627454435e9f6c2d12b099f95a2fd47 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 15:31:09 -0500 Subject: C pointer comparison and arithmetic See #1059 --- src/codegen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 4868576b49..605ea59b06 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2657,7 +2657,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) || (op1->value.type->id == ZigTypeIdPointer && (op_id == IrBinOpAdd || op_id == IrBinOpSub) && - op1->value.type->data.pointer.ptr_len == PtrLenUnknown) + op1->value.type->data.pointer.ptr_len != PtrLenSingle) ); ZigType *operand_type = op1->value.type; ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; @@ -2716,7 +2716,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, AddSubMulMul; if (scalar_type->id == ZigTypeIdPointer) { - assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown); + assert(scalar_type->data.pointer.ptr_len != PtrLenSingle); LLVMValueRef subscript_value; if (operand_type->id == ZigTypeIdVector) zig_panic("TODO: Implement vector operations on pointers."); -- cgit v1.2.3 From 90b8cd4a45bcb2ca131b6ed6466f799aaa162d13 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 16:07:40 -0500 Subject: add C pointer type to @typeInfo See #1059 --- src-self-hosted/type.zig | 2 ++ src/codegen.cpp | 1 + src/ir.cpp | 14 +++++++++++++- std/fmt/index.zig | 3 +++ std/meta/index.zig | 9 ++++++--- std/testing.zig | 3 +-- test/stage1/behavior/type_info.zig | 15 +++++++++++++++ 7 files changed, 41 insertions(+), 6 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 8a05594b30..790b51b7be 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -794,6 +794,7 @@ pub const Type = struct { Size.One => "*", Size.Many => "[*]", Size.Slice => "[]", + Size.C => "[*c]", }; const mut_str = switch (self.key.mut) { Mut.Const => "const ", @@ -1088,6 +1089,7 @@ fn hashAny(x: var, comptime seed: u64) u32 { builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed), builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"), builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"), + builtin.TypeInfo.Pointer.Size.C => unreachable, } }, builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed), diff --git a/src/codegen.cpp b/src/codegen.cpp index 605ea59b06..142e8174f5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7309,6 +7309,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " One,\n" " Many,\n" " Slice,\n" + " C,\n" " };\n" " };\n" "\n" diff --git a/src/ir.cpp b/src/ir.cpp index bc37ac9b54..36ea50ed52 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17584,6 +17584,18 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco return ErrorNone; } +static uint32_t ptr_len_to_size_enum_index(PtrLen ptr_len) { + switch (ptr_len) { + case PtrLenSingle: + return 0; + case PtrLenUnknown: + return 1; + case PtrLenC: + return 3; + } + zig_unreachable(); +} + static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_entry) { Error err; ZigType *attrs_type; @@ -17593,7 +17605,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty size_enum_index = 2; } else if (ptr_type_entry->id == ZigTypeIdPointer) { attrs_type = ptr_type_entry; - size_enum_index = (ptr_type_entry->data.pointer.ptr_len == PtrLenSingle) ? 0 : 1; + size_enum_index = ptr_len_to_size_enum_index(ptr_type_entry->data.pointer.ptr_len); } else { zig_unreachable(); } diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 05b028112f..b09fe21032 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -236,6 +236,9 @@ pub fn formatType( const casted_value = ([]const u8)(value); return output(context, casted_value); }, + builtin.TypeInfo.Pointer.Size.C => { + return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)); + }, }, builtin.TypeId.Array => |info| { if (info.child == u8) { diff --git a/std/meta/index.zig b/std/meta/index.zig index 3f8ea762a6..652e2d39ec 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -463,13 +463,16 @@ pub fn eql(a: var, b: @typeOf(a)) bool { builtin.TypeId.Pointer => { const info = @typeInfo(T).Pointer; switch (info.size) { - builtin.TypeInfo.Pointer.Size.One, builtin.TypeInfo.Pointer.Size.Many => return a == b, + builtin.TypeInfo.Pointer.Size.One, + builtin.TypeInfo.Pointer.Size.Many, + builtin.TypeInfo.Pointer.Size.C, + => return a == b, builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len, } }, builtin.TypeId.Optional => { - if(a == null and b == null) return true; - if(a == null or b == null) return false; + if (a == null and b == null) return true; + if (a == null or b == null) return false; return eql(a.?, b.?); }, else => return a == b, diff --git a/std/testing.zig b/std/testing.zig index ade6e8b0dd..f3ce69659d 100644 --- a/std/testing.zig +++ b/std/testing.zig @@ -69,7 +69,7 @@ pub fn expectEqual(expected: var, actual: var) void { } }, - builtin.TypeInfo.Pointer.Size.Slice => { + builtin.TypeInfo.Pointer.Size.Slice => { if (actual.ptr != expected.ptr) { std.debug.panic("expected slice ptr {}, found {}", expected.ptr, actual.ptr); } @@ -122,7 +122,6 @@ pub fn expectEqual(expected: var, actual: var) void { } } }, - } } diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index ce0ad795b4..dc185cc960 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -61,6 +61,21 @@ fn testUnknownLenPtr() void { expect(u32_ptr_info.Pointer.child == f64); } +test "type info: C pointer type info" { + testCPtr(); + comptime testCPtr(); +} + +fn testCPtr() void { + const ptr_info = @typeInfo([*c]align(4) const i8); + expect(TypeId(ptr_info) == TypeId.Pointer); + expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C); + expect(ptr_info.Pointer.is_const); + expect(!ptr_info.Pointer.is_volatile); + expect(ptr_info.Pointer.alignment == 4); + expect(ptr_info.Pointer.child == i8); +} + test "type info: slice type info" { testSlice(); comptime testSlice(); -- cgit v1.2.3 From 59de24817e8538434f35a20a401f40c2f0231a9a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 01:09:33 -0500 Subject: runtime safety check for casting null to pointer see #1059 --- src/all_types.hpp | 3 +++ src/analyze.cpp | 9 +++++++++ src/analyze.hpp | 1 + src/codegen.cpp | 19 +++++++++++++++++- src/ir.cpp | 52 ++++++++++++++++++++++++------------------------- test/runtime_safety.zig | 10 ++++++++++ 6 files changed, 67 insertions(+), 27 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 230dba9a42..bafe316c3d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1488,6 +1488,7 @@ enum PanicMsgId { PanicMsgIdBadUnionField, PanicMsgIdBadEnumValue, PanicMsgIdFloatToInt, + PanicMsgIdPtrCastNull, PanicMsgIdCount, }; @@ -3001,12 +3002,14 @@ struct IrInstructionPtrCastSrc { IrInstruction *dest_type; IrInstruction *ptr; + bool safety_check_on; }; struct IrInstructionPtrCastGen { IrInstruction base; IrInstruction *ptr; + bool safety_check_on; }; struct IrInstructionBitCast { diff --git a/src/analyze.cpp b/src/analyze.cpp index 900def52d4..6a8090a843 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6902,3 +6902,12 @@ const char *container_string(ContainerKind kind) { } zig_unreachable(); } + +bool ptr_allows_addr_zero(ZigType *ptr_type) { + if (ptr_type->id == ZigTypeIdPointer) { + return ptr_type->data.pointer.allow_zero; + } else if (ptr_type->id == ZigTypeIdOptional) { + return true; + } + return false; +} diff --git a/src/analyze.hpp b/src/analyze.hpp index c8141b02ff..50e841baa1 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -45,6 +45,7 @@ void find_libc_lib_path(CodeGen *g); bool type_has_bits(ZigType *type_entry); bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry); +bool ptr_allows_addr_zero(ZigType *ptr_type); ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); diff --git a/src/codegen.cpp b/src/codegen.cpp index 142e8174f5..dbb13ca885 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -950,6 +950,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { return buf_create_from_str("invalid enum value"); case PanicMsgIdFloatToInt: return buf_create_from_str("integer part of floating point value out of bounds"); + case PanicMsgIdPtrCastNull: + return buf_create_from_str("cast causes pointer to be null"); } zig_unreachable(); } @@ -3028,7 +3030,22 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, return nullptr; } LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, ""); + LLVMValueRef result_ptr = LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, ""); + bool want_safety_check = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); + if (!want_safety_check || ptr_allows_addr_zero(wanted_type)) + return result_ptr; + + LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(result_ptr)); + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, result_ptr, zero, ""); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastOk"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_safety_crash(g, PanicMsgIdPtrCastNull); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + return result_ptr; } static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable, diff --git a/src/ir.cpp b/src/ir.cpp index f064adb128..dfbc36e02c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -172,7 +172,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val); static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, - ZigType *dest_type, IrInstruction *dest_type_src); + ZigType *dest_type, IrInstruction *dest_type_src, bool safety_check_on); static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); @@ -2202,12 +2202,13 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo } static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *dest_type, IrInstruction *ptr) + IrInstruction *dest_type, IrInstruction *ptr, bool safety_check_on) { IrInstructionPtrCastSrc *instruction = ir_build_instruction( irb, scope, source_node); instruction->dest_type = dest_type; instruction->ptr = ptr; + instruction->safety_check_on = safety_check_on; ir_ref_instruction(dest_type, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); @@ -2216,12 +2217,13 @@ static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNod } static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, - ZigType *ptr_type, IrInstruction *ptr) + ZigType *ptr_type, IrInstruction *ptr, bool safety_check_on) { IrInstructionPtrCastGen *instruction = ir_build_instruction( &ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value.type = ptr_type; instruction->ptr = ptr; + instruction->safety_check_on = safety_check_on; ir_ref_instruction(ptr, ira->new_irb.current_basic_block); @@ -4505,7 +4507,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value); + IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value, true); return ir_lval_wrap(irb, scope, ptr_cast, lval); } case BuiltinFnIdBitCast: @@ -6740,7 +6742,8 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010 // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst, + false); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -6818,7 +6821,8 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void)); // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst, + false); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -7363,7 +7367,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec u8_ptr_type = ir_build_const_type(irb, coro_scope, node, get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); - IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); + IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, + coro_promise_ptr, false); coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); @@ -7387,7 +7392,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_build_return(irb, coro_scope, node, undef); ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr, + false); irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); @@ -7465,9 +7471,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); - IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); - IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, - irb->exec->coro_result_field_ptr); + IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, + result_ptr, false); + IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, + u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr, false); IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node, fn_entry->type_entry->data.fn.fn_type_id.return_type); IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst); @@ -7517,7 +7524,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, + coro_mem_ptr_maybe, false); IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr); @@ -8644,15 +8652,6 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp return err_set_type; } -static bool ptr_allows_addr_zero(ZigType *ptr_type) { - if (ptr_type->id == ZigTypeIdPointer) { - return ptr_type->data.pointer.allow_zero; - } else if (ptr_type->id == ZigTypeIdOptional) { - return true; - } - return false; -} - static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type, ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable) { @@ -11310,7 +11309,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->data.pointer.host_int_bytes == dest_ptr_type->data.pointer.host_int_bytes && get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, dest_ptr_type)) { - return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr); + return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true); } } @@ -11352,7 +11351,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) { - return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr); + return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true); } // cast from integer to C pointer @@ -20616,7 +20615,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 } static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, - ZigType *dest_type, IrInstruction *dest_type_src) + ZigType *dest_type, IrInstruction *dest_type_src, bool safety_check_on) { Error err; @@ -20685,7 +20684,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ return ira->codegen->invalid_instruction; } - IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr); + IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); if (type_has_bits(dest_type) && !type_has_bits(src_type)) { ErrorMsg *msg = ir_add_error(ira, source_instr, @@ -20722,7 +20721,8 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct if (type_is_invalid(src_type)) return ira->codegen->invalid_instruction; - return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value); + return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value, + instruction->safety_check_on); } static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExprValue *val, size_t len) { diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 821328b7a6..12cac64b3a 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -1,6 +1,16 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompareOutputContext) void { + cases.addRuntimeSafety("pointer casting null to non-optional pointer", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\pub fn main() void { + \\ var c_ptr: [*c]u8 = 0; + \\ var zig_ptr: *u8 = c_ptr; + \\} + ); + cases.addRuntimeSafety("@intToEnum - no matching tag value", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); -- cgit v1.2.3 From df87044fd6588452755014d5909e0db1b776deb2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 16:10:12 -0500 Subject: omit nonnull attribute for C pointers See #1059 --- src/analyze.cpp | 4 ++++ src/analyze.hpp | 1 + src/codegen.cpp | 19 ++++++++++++++++--- src/target.cpp | 4 ++++ src/target.hpp | 1 + 5 files changed, 26 insertions(+), 3 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 90ce3d3371..55deafb3a8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4100,6 +4100,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) { return ty; } +bool type_is_nonnull_ptr(ZigType *type) { + return type_is_codegen_pointer(type) && !ptr_allows_addr_zero(type); +} + bool type_is_codegen_pointer(ZigType *type) { return get_codegen_ptr_type(type) == type; } diff --git a/src/analyze.hpp b/src/analyze.hpp index 50e841baa1..845fb62534 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -46,6 +46,7 @@ void find_libc_lib_path(CodeGen *g); bool type_has_bits(ZigType *type_entry); bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry); bool ptr_allows_addr_zero(ZigType *ptr_type); +bool type_is_nonnull_ptr(ZigType *type); ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); diff --git a/src/codegen.cpp b/src/codegen.cpp index dbb13ca885..bae9abe06d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -617,9 +617,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { unsigned init_gen_i = 0; if (!type_has_bits(return_type)) { // nothing to do - } else if (type_is_codegen_pointer(return_type)) { + } else if (type_is_nonnull_ptr(return_type)) { addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { + // Sret pointers must not be address 0 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); if (cc_want_sret_attr(cc)) { @@ -637,6 +638,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); if (err_ret_trace_arg_index != UINT32_MAX) { + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull"); } @@ -1246,6 +1249,8 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); addLLVMFnAttr(fn_val, "nounwind"); add_uwtable_attr(g, fn_val); + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); if (g->build_mode == BuildModeDebug) { ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); @@ -1320,9 +1325,13 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); addLLVMFnAttr(fn_val, "nounwind"); add_uwtable_attr(g, fn_val); + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); addLLVMArgAttr(fn_val, (unsigned)0, "noalias"); addLLVMArgAttr(fn_val, (unsigned)0, "writeonly"); + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); addLLVMArgAttr(fn_val, (unsigned)1, "noalias"); addLLVMArgAttr(fn_val, (unsigned)1, "readonly"); @@ -1450,6 +1459,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); addLLVMFnAttr(fn_val, "nounwind"); add_uwtable_attr(g, fn_val); + // Error return trace memory is in the stack, which is impossible to be at address 0 + // on any architecture. addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); if (g->build_mode == BuildModeDebug) { ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); @@ -2051,7 +2062,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ case FnWalkIdAttrs: { ZigType *ptr_type = get_codegen_ptr_type(ty); if (ptr_type != nullptr) { - if (ty->id != ZigTypeIdOptional) { + if (type_is_nonnull_ptr(ty)) { addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); } if (ptr_type->data.pointer.is_const) { @@ -2095,6 +2106,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ assert(handle_is_ptr(ty)); switch (fn_walk->id) { case FnWalkIdAttrs: + // arrays passed to C ABI functions may not be at address 0 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty)); fn_walk->data.attrs.gen_i += 1; @@ -2134,6 +2146,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ case FnWalkIdAttrs: addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval"); addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty)); + // Byvalue parameters must not have address 0 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); fn_walk->data.attrs.gen_i += 1; break; @@ -2266,7 +2279,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) { addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly"); } - if (param_type->id == ZigTypeIdPointer) { + if (type_is_nonnull_ptr(param_type)) { addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull"); } break; diff --git a/src/target.cpp b/src/target.cpp index 6fea79518c..b1434c6871 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -807,6 +807,10 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { zig_unreachable(); } +bool target_allows_addr_zero(const ZigTarget *target) { + return target->os == OsFreestanding; +} + const char *target_o_file_ext(ZigTarget *target) { if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows || target->os == OsUefi) { return ".obj"; diff --git a/src/target.hpp b/src/target.hpp index a87b12351a..99d1cadf56 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -135,5 +135,6 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target ZigLLVM_OSType get_llvm_os_type(Os os_type); bool target_is_arm(const ZigTarget *target); +bool target_allows_addr_zero(const ZigTarget *target); #endif -- cgit v1.2.3