zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 9116e26c1ffb49cf68bebf3af2a019af08474d12 (tree)
parent 5605f6e0e302cbf345a5229ea58aef6757fe139d
Author: Veikka Tuominen <git@vexu.eu>
Date:   Fri,  5 Aug 2022 17:36:45 +0300

Sema: add null check for implicit casts

Diffstat:
Msrc/Sema.zig | 22++++++++++++++++++----
Mtest/cases/safety/pointer casting null to non-optional pointer.zig | 10+++++++---
Atest/cases/safety/slicing null C pointer - runtime len.zig | 20++++++++++++++++++++
Dtest/cases/safety/slicing null C pointer runtime len.zig | 21---------------------
Mtest/cases/safety/slicing null C pointer.zig | 3+--
5 files changed, 46 insertions(+), 30 deletions(-)

diff --git a/src/Sema.zig b/src/Sema.zig @@ -1577,8 +1577,7 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) // st.index = 0; const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true); - const zero = try sema.addConstant(Type.usize, Value.zero); - try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, zero, src, .store); + try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store); // @errorReturnTrace() = &st; _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr); @@ -17134,7 +17133,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); const ok = if (ptr_ty.isSlice()) ok: { const len = try sema.analyzeSliceLen(block, ptr_src, ptr); - const len_zero = try block.addBinOp(.cmp_eq, len, try sema.addConstant(Type.usize, Value.zero)); + const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); break :ok try block.addBinOp(.bit_or, len_zero, is_aligned); } else is_aligned; try sema.addSafetyCheck(block, ok, .incorrect_alignment); @@ -21957,7 +21956,6 @@ fn coerceExtra( .ok => {}, else => break :src_c_ptr, } - // TODO add safety check for null pointer return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); } @@ -24430,6 +24428,22 @@ fn coerceCompatiblePtrs( return sema.addConstant(dest_ty, val); } try sema.requireRuntimeBlock(block, inst_src, null); + const inst_ty = sema.typeOf(inst); + const inst_allows_zero = (inst_ty.zigTypeTag() == .Pointer and inst_ty.ptrAllowsZero()) or true; + if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero()) { + const actual_ptr = if (inst_ty.isSlice()) + try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) + else + inst; + const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); + const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); + const ok = if (inst_ty.isSlice()) ok: { + const len = try sema.analyzeSliceLen(block, inst_src, inst); + const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); + break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); + } else is_non_zero; + try sema.addSafetyCheck(block, ok, .cast_to_null); + } return sema.bitCast(block, dest_ty, inst, inst_src); } diff --git a/test/cases/safety/pointer casting null to non-optional pointer.zig b/test/cases/safety/pointer casting null to non-optional pointer.zig @@ -1,16 +1,20 @@ const std = @import("std"); pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { - _ = message; _ = stack_trace; - std.process.exit(0); + if (std.mem.eql(u8, message, "cast causes pointer to be null")) { + std.process.exit(0); + } + std.process.exit(1); } + pub fn main() !void { var c_ptr: [*c]u8 = 0; var zig_ptr: *u8 = c_ptr; _ = zig_ptr; return error.TestFailed; } + // run -// backend=stage1 +// backend=llvm // target=native diff --git a/test/cases/safety/slicing null C pointer - runtime len.zig b/test/cases/safety/slicing null C pointer - runtime len.zig @@ -0,0 +1,20 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to use null value")) { + std.process.exit(0); + } + std.process.exit(1); +} + +pub fn main() !void { + var ptr: [*c]const u32 = null; + var len: usize = 3; + var slice = ptr[0..len]; + _ = slice; + return error.TestFailed; +} +// run +// backend=llvm +// target=native diff --git a/test/cases/safety/slicing null C pointer runtime len.zig b/test/cases/safety/slicing null C pointer runtime len.zig @@ -1,20 +0,0 @@ -const std = @import("std"); - -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { - _ = stack_trace; - if (std.mem.eql(u8, message, "attempt to use null value")) { - std.process.exit(0); - } - std.process.exit(1); -} - -pub fn main() !void { - var ptr: [*c]const u32 = null; - var len: usize = 3; - var slice = ptr[0..len]; - _ = slice; - return error.TestFailed; -} -// run -// backend=llvm -// target=native -\ No newline at end of file diff --git a/test/cases/safety/slicing null C pointer.zig b/test/cases/safety/slicing null C pointer.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=llvm -// target=native -\ No newline at end of file +// target=native