authorgravatar for alex_naskos@hotmail.comAlexandros Naskos <alex_naskos@hotmail.com> 2020-02-29 08:36:42+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-02-29 01:36:42-05:00
log1b41f2d77ea14de27b0655a35a727d664cfc4ca4
treed3e5996e16424fa205a0f8072670254a04147545
parenta5a53a182af3715edd9474fe94cad2223a6c7fb9
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

C pointer slices are no longer allowzero (#4462)

* Slices from C pointers are no longer allowzero but instead insert a runtime assertion. * Added a test, fixed code for cases with non-allowzero C pointers * Create new type when flipping allow_zero, sometimes we get a cached value back from adjust_ptr_len. * Added comments, changed panic message * Added runtime safety test.

4 files changed, 57 insertions(+), 4 deletions(-)

src/codegen.cpp+1-1
...@@ -973,7 +973,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -973,7 +973,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
973 case PanicMsgIdExactDivisionRemainder:973 case PanicMsgIdExactDivisionRemainder:
974 return buf_create_from_str("exact division produced remainder");974 return buf_create_from_str("exact division produced remainder");
975 case PanicMsgIdUnwrapOptionalFail:975 case PanicMsgIdUnwrapOptionalFail:
976 return buf_create_from_str("attempt to unwrap null");976 return buf_create_from_str("attempt to use null value");
977 case PanicMsgIdUnreachable:977 case PanicMsgIdUnreachable:
978 return buf_create_from_str("reached unreachable code");978 return buf_create_from_str("reached unreachable code");
979 case PanicMsgIdInvalidErrorCode:979 case PanicMsgIdInvalidErrorCode:
src/ir.cpp+32-3
...@@ -20412,6 +20412,17 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {...@@ -20412,6 +20412,17 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
20412 ptr_type->data.pointer.allow_zero);20412 ptr_type->data.pointer.allow_zero);
20413}20413}
2041420414
20415static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_zero) {
20416 assert(ptr_type->id == ZigTypeIdPointer);
20417 return get_pointer_to_type_extra(g,
20418 ptr_type->data.pointer.child_type,
20419 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
20420 ptr_type->data.pointer.ptr_len,
20421 ptr_type->data.pointer.explicit_alignment,
20422 ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
20423 allow_zero);
20424}
20425
20415static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {20426static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {
20416 Error err;20427 Error err;
20417 IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;20428 IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;
...@@ -25966,6 +25977,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -25966,6 +25977,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
25966 ZigType *non_sentinel_slice_ptr_type;25977 ZigType *non_sentinel_slice_ptr_type;
25967 ZigType *elem_type;25978 ZigType *elem_type;
2596825979
25980 bool generate_non_null_assert = false;
25981
25969 if (array_type->id == ZigTypeIdArray) {25982 if (array_type->id == ZigTypeIdArray) {
25970 elem_type = array_type->data.array.child_type;25983 elem_type = array_type->data.array.child_type;
25971 bool is_comptime_const = ptr_ptr->value->special == ConstValSpecialStatic &&25984 bool is_comptime_const = ptr_ptr->value->special == ConstValSpecialStatic &&
...@@ -25993,6 +26006,14 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -25993,6 +26006,14 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
25993 elem_type = array_type->data.pointer.child_type;26006 elem_type = array_type->data.pointer.child_type;
25994 if (array_type->data.pointer.ptr_len == PtrLenC) {26007 if (array_type->data.pointer.ptr_len == PtrLenC) {
25995 array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown);26008 array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown);
26009
26010 // C pointers are allowzero by default.
26011 // However, we want to be able to slice them without generating an allowzero slice (see issue #4401).
26012 // To achieve this, we generate a runtime safety check and make the slice type non-allowzero.
26013 if (array_type->data.pointer.allow_zero) {
26014 array_type = adjust_ptr_allow_zero(ira->codegen, array_type, false);
26015 generate_non_null_assert = true;
26016 }
25996 }26017 }
25997 ZigType *maybe_sentineled_slice_ptr_type = array_type;26018 ZigType *maybe_sentineled_slice_ptr_type = array_type;
25998 non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr);26019 non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr);
...@@ -26264,7 +26285,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26264,7 +26285,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
2626426285
26265 IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,26286 IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
26266 return_type, nullptr, true, true);26287 return_type, nullptr, true, true);
26267
26268 if (result_loc != nullptr) {26288 if (result_loc != nullptr) {
26269 if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {26289 if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
26270 return result_loc;26290 return result_loc;
...@@ -26277,8 +26297,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26277,8 +26297,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26277 return ira->codegen->invalid_inst_gen;26297 return ira->codegen->invalid_inst_gen;
26278 }26298 }
2627926299
26280 return ir_build_slice_gen(ira, &instruction->base.base, return_type,26300 if (generate_non_null_assert) {
26281 ptr_ptr, casted_start, end, instruction->safety_check_on, result_loc);26301 IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr);
26302
26303 if (type_is_invalid(ptr_val->value->type))
26304 return ira->codegen->invalid_inst_gen;
26305
26306 ir_build_assert_non_null(ira, &instruction->base.base, ptr_val);
26307 }
26308
26309 return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr,
26310 casted_start, end, instruction->safety_check_on, result_loc);
26282}26311}
2628326312
26284static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) {26313static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) {
test/runtime_safety.zig+13
...@@ -745,4 +745,17 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -745,4 +745,17 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
745 \\ (await p) catch unreachable;745 \\ (await p) catch unreachable;
746 \\}746 \\}
747 );747 );
748
749 // Slicing a C pointer returns a non-allowzero slice, thus we need to emit
750 // a safety check to ensure the pointer is not null.
751 cases.addRuntimeSafety("slicing null C pointer",
752 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
753 \\ @import("std").os.exit(126);
754 \\}
755 \\
756 \\pub fn main() void {
757 \\ var ptr: [*c]const u32 = null;
758 \\ var slice = ptr[0..3];
759 \\}
760 );
748}761}
test/stage1/behavior/slice.zig+11
...@@ -43,6 +43,17 @@ test "C pointer" {...@@ -43,6 +43,17 @@ test "C pointer" {
43 expectEqualSlices(u8, "kjdhfkjdhf", slice);43 expectEqualSlices(u8, "kjdhfkjdhf", slice);
44}44}
4545
46test "C pointer slice access" {
47 var buf: [10]u32 = [1]u32{42} ** 10;
48 const c_ptr = @ptrCast([*c]const u32, &buf);
49
50 comptime expectEqual([]const u32, @TypeOf(c_ptr[0..1]));
51
52 for (c_ptr[0..5]) |*cl| {
53 expectEqual(@as(u32, 42), cl.*);
54 }
55}
56
46fn sliceSum(comptime q: []const u8) i32 {57fn sliceSum(comptime q: []const u8) i32 {
47 comptime var result = 0;58 comptime var result = 0;
48 inline for (q) |item| {59 inline for (q) |item| {