commit ae7b32eb62cb00a09fe2e0e30b307eb83e9f0a86 (tree) parent 3c73f711771e41e9176e973c64484f0ce5e0eeed Author: Veikka Tuominen <git@vexu.eu> Date: Thu, 30 Jun 2022 17:22:16 +0300 Sema: validate deref operator type and value Diffstat:
25 files changed, 149 insertions(+), 101 deletions(-)
diff --git a/lib/c.zig b/lib/c.zig @@ -82,7 +82,7 @@ fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.C) ?[*]u8 { var d = dest.?; var n = len; while (true) { - d.* = c; + d[0] = c; n -= 1; if (n == 0) break; d += 1; diff --git a/lib/std/os.zig b/lib/std/os.zig @@ -1868,7 +1868,7 @@ pub fn getenv(key: []const u8) ?[]const u8 { } // Search the entire `environ` because we don't have a null terminated pointer. var ptr = std.c.environ; - while (ptr.*) |line| : (ptr += 1) { + while (ptr[0]) |line| : (ptr += 1) { var line_i: usize = 0; while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {} const this_key = line[0..line_i]; diff --git a/lib/std/process.zig b/lib/std/process.zig @@ -313,7 +313,7 @@ pub fn getEnvMap(allocator: Allocator) !EnvMap { return result; } else if (builtin.link_libc) { var ptr = std.c.environ; - while (ptr.*) |line| : (ptr += 1) { + while (ptr[0]) |line| : (ptr += 1) { var line_i: usize = 0; while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {} const key = line[0..line_i]; diff --git a/src/AstGen.zig b/src/AstGen.zig @@ -812,6 +812,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr .deref => { const lhs = try expr(gz, scope, .none, node_datas[node].lhs); + _ = try gz.addUnTok(.validate_deref, lhs, main_tokens[node]); switch (rl) { .ref => return lhs, else => { @@ -2500,6 +2501,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner .memset, .validate_array_init_ty, .validate_struct_init_ty, + .validate_deref, => break :b true, } } else switch (maybe_unused_result) { diff --git a/src/Sema.zig b/src/Sema.zig @@ -1080,6 +1080,11 @@ fn analyzeBodyInner( i += 1; continue; }, + .validate_deref => { + try sema.zirValidateDeref(block, inst); + i += 1; + continue; + }, .@"export" => { try sema.zirExport(block, inst); i += 1; @@ -3849,6 +3854,28 @@ fn zirValidateArrayInit( } } +fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { + const inst_data = sema.code.instructions.items(.data)[inst].un_tok; + const src = inst_data.src(); + const operand_src: LazySrcLoc = .{ .token_offset = inst_data.src_tok + 1 }; + const operand = try sema.resolveInst(inst_data.operand); + const operand_ty = sema.typeOf(operand); + + if (operand_ty.zigTypeTag() != .Pointer) { + return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)}); + } else switch (operand_ty.ptrSize()) { + .One, .C => {}, + .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}), + .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}), + } + + if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { + if (val.isUndef()) { + return sema.fail(block, src, "cannot dereference undefined value", .{}); + } + } +} + fn failWithBadMemberAccess( sema: *Sema, block: *Block, diff --git a/src/Zir.zig b/src/Zir.zig @@ -729,6 +729,9 @@ pub const Inst = struct { /// Same as `validate_array_init` but additionally communicates that the /// resulting array initialization value is within a comptime scope. validate_array_init_comptime, + /// Check that operand type supports the dereference operand (.*). + /// Uses the `un_tok` field. + validate_deref, /// A struct literal with a specified type, with no fields. /// Uses the `un_node` field. struct_init_empty, @@ -1156,6 +1159,7 @@ pub const Inst = struct { .validate_struct_init_comptime, .validate_array_init, .validate_array_init_comptime, + .validate_deref, .struct_init_empty, .struct_init, .struct_init_ref, @@ -1309,6 +1313,7 @@ pub const Inst = struct { .validate_struct_init_comptime, .validate_array_init, .validate_array_init_comptime, + .validate_deref, .@"export", .export_value, .set_cold, @@ -1709,6 +1714,7 @@ pub const Inst = struct { .validate_struct_init_comptime = .pl_node, .validate_array_init = .pl_node, .validate_array_init_comptime = .pl_node, + .validate_deref = .un_tok, .struct_init_empty = .un_node, .field_type = .pl_node, .field_type_ref = .pl_node, diff --git a/src/print_zir.zig b/src/print_zir.zig @@ -242,6 +242,7 @@ const Writer = struct { .ret_tok, .ensure_err_payload_void, .closure_capture, + .validate_deref, => try self.writeUnTok(stream, inst), .bool_br_and, diff --git a/test/cases/compile_errors/assign_to_invalid_dereference.zig b/test/cases/compile_errors/assign_to_invalid_dereference.zig @@ -0,0 +1,9 @@ +export fn entry() void { + 'a'.* = 1; +} + +// error +// backend=stage2 +// target=native +// +// :2:8: error: cannot dereference non-pointer type 'comptime_int' diff --git a/test/cases/compile_errors/deref_on_undefined_value.zig b/test/cases/compile_errors/deref_on_undefined_value.zig @@ -0,0 +1,10 @@ +comptime { + var a: *u8 = undefined; + _ = a.*; +} + +// error +// backend=stage2 +// target=native +// +// :3:10: error: cannot dereference undefined value diff --git a/test/cases/compile_errors/deref_slice_and_get_len_field.zig b/test/cases/compile_errors/deref_slice_and_get_len_field.zig @@ -0,0 +1,10 @@ +export fn entry() void { + var a: []u8 = undefined; + _ = a.*.len; +} + +// error +// backend=stage2 +// target=native +// +// :3:10: error: index syntax required for slice type '[]u8' diff --git a/test/cases/compile_errors/dereference_an_array.zig b/test/cases/compile_errors/dereference_an_array.zig @@ -0,0 +1,14 @@ +var s_buffer: [10]u8 = undefined; +pub fn pass(in: []u8) []u8 { + var out = &s_buffer; + out.*.* = in[0]; + return out.*[0..1]; +} + +export fn entry() usize { return @sizeOf(@TypeOf(&pass)); } + +// error +// backend=stage2 +// target=native +// +// :4:10: error: cannot dereference non-pointer type '[10]u8' diff --git a/test/cases/compile_errors/dereference_slice.zig b/test/cases/compile_errors/dereference_slice.zig @@ -0,0 +1,12 @@ +fn entry(x: []i32) i32 { + return x.*; +} +comptime { + _ = entry; +} + +// error +// backend=stage2 +// target=native +// +// :2:13: error: index syntax required for slice type '[]i32' diff --git a/test/cases/compile_errors/dereference_unknown_length_pointer.zig b/test/cases/compile_errors/dereference_unknown_length_pointer.zig @@ -0,0 +1,9 @@ +export fn entry(x: [*]i32) i32 { + return x.*; +} + +// error +// backend=stage2 +// target=native +// +// :2:13: error: index syntax required for unknown-length pointer type '[*]i32' diff --git a/test/cases/compile_errors/invalid_deref_on_switch_target.zig b/test/cases/compile_errors/invalid_deref_on_switch_target.zig @@ -0,0 +1,17 @@ +comptime { + var tile = Tile.Empty; + switch (tile.*) { + Tile.Empty => {}, + Tile.Filled => {}, + } +} +const Tile = enum { + Empty, + Filled, +}; + +// error +// backend=stage2 +// target=native +// +// :3:17: error: cannot dereference non-pointer type 'tmp.Tile' diff --git a/test/cases/compile_errors/invalid_multiple_dereferences.zig b/test/cases/compile_errors/invalid_multiple_dereferences.zig @@ -0,0 +1,19 @@ +export fn a() void { + var box = Box{ .field = 0 }; + box.*.field = 1; +} +export fn b() void { + var box = Box{ .field = 0 }; + var boxPtr = &box; + boxPtr.*.*.field = 1; +} +pub const Box = struct { + field: i32, +}; + +// error +// backend=stage2 +// target=native +// +// :3:8: error: cannot dereference non-pointer type 'tmp.Box' +// :8:13: error: cannot dereference non-pointer type 'tmp.Box' diff --git a/test/cases/compile_errors/stage1/obj/comptime_ptrcast_of_zero-sized_type.zig b/test/cases/compile_errors/stage1/comptime_ptrcast_of_zero-sized_type.zig diff --git a/test/cases/compile_errors/stage1/deref_on_undefined_value.zig b/test/cases/compile_errors/stage1/deref_on_undefined_value.zig @@ -1,10 +0,0 @@ -comptime { - var a: *u8 = undefined; - _ = a.*; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:9: error: attempt to dereference undefined value diff --git a/test/cases/compile_errors/stage1/obj/assign_to_invalid_dereference.zig b/test/cases/compile_errors/stage1/obj/assign_to_invalid_dereference.zig @@ -1,9 +0,0 @@ -export fn entry() void { - 'a'.* = 1; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int' diff --git a/test/cases/compile_errors/stage1/obj/deref_slice_and_get_len_field.zig b/test/cases/compile_errors/stage1/obj/deref_slice_and_get_len_field.zig @@ -1,10 +0,0 @@ -export fn entry() void { - var a: []u8 = undefined; - _ = a.*.len; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:10: error: attempt to dereference non-pointer type '[]u8' diff --git a/test/cases/compile_errors/stage1/obj/dereference_an_array.zig b/test/cases/compile_errors/stage1/obj/dereference_an_array.zig @@ -1,14 +0,0 @@ -var s_buffer: [10]u8 = undefined; -pub fn pass(in: []u8) []u8 { - var out = &s_buffer; - out.*.* = in[0]; - return out.*[0..1]; -} - -export fn entry() usize { return @sizeOf(@TypeOf(pass)); } - -// error -// backend=stage1 -// target=native -// -// tmp.zig:4:10: error: attempt to dereference non-pointer type '[10]u8' diff --git a/test/cases/compile_errors/stage1/obj/dereference_unknown_length_pointer.zig b/test/cases/compile_errors/stage1/obj/dereference_unknown_length_pointer.zig @@ -1,9 +0,0 @@ -export fn entry(x: [*]i32) i32 { - return x.*; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32' diff --git a/test/cases/compile_errors/stage1/obj/invalid_deref_on_switch_target.zig b/test/cases/compile_errors/stage1/obj/invalid_deref_on_switch_target.zig @@ -1,17 +0,0 @@ -comptime { - var tile = Tile.Empty; - switch (tile.*) { - Tile.Empty => {}, - Tile.Filled => {}, - } -} -const Tile = enum { - Empty, - Filled, -}; - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:17: error: attempt to dereference non-pointer type 'Tile' diff --git a/test/cases/compile_errors/stage1/obj/invalid_multiple_dereferences.zig b/test/cases/compile_errors/stage1/obj/invalid_multiple_dereferences.zig @@ -1,19 +0,0 @@ -export fn a() void { - var box = Box{ .field = 0 }; - box.*.field = 1; -} -export fn b() void { - var box = Box{ .field = 0 }; - var boxPtr = &box; - boxPtr.*.*.field = 1; -} -pub const Box = struct { - field: i32, -}; - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:8: error: attempt to dereference non-pointer type 'Box' -// tmp.zig:8:13: error: attempt to dereference non-pointer type 'Box' diff --git a/test/cases/compile_errors/stage1/obj/take_slice_of_invalid_dereference.zig b/test/cases/compile_errors/stage1/obj/take_slice_of_invalid_dereference.zig @@ -1,10 +0,0 @@ -export fn entry() void { - const x = 'a'.*[0..]; - _ = x; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int' diff --git a/test/cases/compile_errors/take_slice_of_invalid_dereference.zig b/test/cases/compile_errors/take_slice_of_invalid_dereference.zig @@ -0,0 +1,10 @@ +export fn entry() void { + const x = 'a'.*[0..]; + _ = x; +} + +// error +// backend=stage2 +// target=native +// +// :2:18: error: cannot dereference non-pointer type 'comptime_int'