authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-06-30 17:22:16+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-01 10:22:25+03:00
logae7b32eb62cb00a09fe2e0e30b307eb83e9f0a86
treeabe5edeef5d656feb5dcf82d5a8e93db67fd2afc
parent3c73f711771e41e9176e973c64484f0ce5e0eeed

Sema: validate deref operator type and value


26 files changed, 161 insertions(+), 113 deletions(-)

lib/c.zig+1-1
......@@ -82,7 +82,7 @@ fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.C) ?[*]u8 {
8282 var d = dest.?;
8383 var n = len;
8484 while (true) {
85 d.* = c;
85 d[0] = c;
8686 n -= 1;
8787 if (n == 0) break;
8888 d += 1;
lib/std/os.zig+1-1
......@@ -1868,7 +1868,7 @@ pub fn getenv(key: []const u8) ?[]const u8 {
18681868 }
18691869 // Search the entire `environ` because we don't have a null terminated pointer.
18701870 var ptr = std.c.environ;
1871 while (ptr.*) |line| : (ptr += 1) {
1871 while (ptr[0]) |line| : (ptr += 1) {
18721872 var line_i: usize = 0;
18731873 while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
18741874 const this_key = line[0..line_i];
lib/std/process.zig+1-1
......@@ -313,7 +313,7 @@ pub fn getEnvMap(allocator: Allocator) !EnvMap {
313313 return result;
314314 } else if (builtin.link_libc) {
315315 var ptr = std.c.environ;
316 while (ptr.*) |line| : (ptr += 1) {
316 while (ptr[0]) |line| : (ptr += 1) {
317317 var line_i: usize = 0;
318318 while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
319319 const key = line[0..line_i];
src/AstGen.zig+2
......@@ -812,6 +812,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
812812
813813 .deref => {
814814 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
815 _ = try gz.addUnTok(.validate_deref, lhs, main_tokens[node]);
815816 switch (rl) {
816817 .ref => return lhs,
817818 else => {
......@@ -2500,6 +2501,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
25002501 .memset,
25012502 .validate_array_init_ty,
25022503 .validate_struct_init_ty,
2504 .validate_deref,
25032505 => break :b true,
25042506 }
25052507 } else switch (maybe_unused_result) {
src/Sema.zig+27
......@@ -1080,6 +1080,11 @@ fn analyzeBodyInner(
10801080 i += 1;
10811081 continue;
10821082 },
1083 .validate_deref => {
1084 try sema.zirValidateDeref(block, inst);
1085 i += 1;
1086 continue;
1087 },
10831088 .@"export" => {
10841089 try sema.zirExport(block, inst);
10851090 i += 1;
......@@ -3849,6 +3854,28 @@ fn zirValidateArrayInit(
38493854 }
38503855}
38513856
3857fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
3858 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
3859 const src = inst_data.src();
3860 const operand_src: LazySrcLoc = .{ .token_offset = inst_data.src_tok + 1 };
3861 const operand = try sema.resolveInst(inst_data.operand);
3862 const operand_ty = sema.typeOf(operand);
3863
3864 if (operand_ty.zigTypeTag() != .Pointer) {
3865 return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)});
3866 } else switch (operand_ty.ptrSize()) {
3867 .One, .C => {},
3868 .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}),
3869 .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}),
3870 }
3871
3872 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
3873 if (val.isUndef()) {
3874 return sema.fail(block, src, "cannot dereference undefined value", .{});
3875 }
3876 }
3877}
3878
38523879fn failWithBadMemberAccess(
38533880 sema: *Sema,
38543881 block: *Block,
src/Zir.zig+6
......@@ -729,6 +729,9 @@ pub const Inst = struct {
729729 /// Same as `validate_array_init` but additionally communicates that the
730730 /// resulting array initialization value is within a comptime scope.
731731 validate_array_init_comptime,
732 /// Check that operand type supports the dereference operand (.*).
733 /// Uses the `un_tok` field.
734 validate_deref,
732735 /// A struct literal with a specified type, with no fields.
733736 /// Uses the `un_node` field.
734737 struct_init_empty,
......@@ -1156,6 +1159,7 @@ pub const Inst = struct {
11561159 .validate_struct_init_comptime,
11571160 .validate_array_init,
11581161 .validate_array_init_comptime,
1162 .validate_deref,
11591163 .struct_init_empty,
11601164 .struct_init,
11611165 .struct_init_ref,
......@@ -1309,6 +1313,7 @@ pub const Inst = struct {
13091313 .validate_struct_init_comptime,
13101314 .validate_array_init,
13111315 .validate_array_init_comptime,
1316 .validate_deref,
13121317 .@"export",
13131318 .export_value,
13141319 .set_cold,
......@@ -1709,6 +1714,7 @@ pub const Inst = struct {
17091714 .validate_struct_init_comptime = .pl_node,
17101715 .validate_array_init = .pl_node,
17111716 .validate_array_init_comptime = .pl_node,
1717 .validate_deref = .un_tok,
17121718 .struct_init_empty = .un_node,
17131719 .field_type = .pl_node,
17141720 .field_type_ref = .pl_node,
src/print_zir.zig+1
......@@ -242,6 +242,7 @@ const Writer = struct {
242242 .ret_tok,
243243 .ensure_err_payload_void,
244244 .closure_capture,
245 .validate_deref,
245246 => try self.writeUnTok(stream, inst),
246247
247248 .bool_br_and,
test/cases/compile_errors/assign_to_invalid_dereference.zig created+9
......@@ -0,0 +1,9 @@
1export fn entry() void {
2 'a'.* = 1;
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:8: error: cannot dereference non-pointer type 'comptime_int'
test/cases/compile_errors/deref_on_undefined_value.zig created+10
......@@ -0,0 +1,10 @@
1comptime {
2 var a: *u8 = undefined;
3 _ = a.*;
4}
5
6// error
7// backend=stage2
8// target=native
9//
10// :3:10: error: cannot dereference undefined value
test/cases/compile_errors/deref_slice_and_get_len_field.zig created+10
......@@ -0,0 +1,10 @@
1export fn entry() void {
2 var a: []u8 = undefined;
3 _ = a.*.len;
4}
5
6// error
7// backend=stage2
8// target=native
9//
10// :3:10: error: index syntax required for slice type '[]u8'
test/cases/compile_errors/dereference_an_array.zig created+14
......@@ -0,0 +1,14 @@
1var s_buffer: [10]u8 = undefined;
2pub fn pass(in: []u8) []u8 {
3 var out = &s_buffer;
4 out.*.* = in[0];
5 return out.*[0..1];
6}
7
8export fn entry() usize { return @sizeOf(@TypeOf(&pass)); }
9
10// error
11// backend=stage2
12// target=native
13//
14// :4:10: error: cannot dereference non-pointer type '[10]u8'
test/cases/compile_errors/dereference_slice.zig created+12
......@@ -0,0 +1,12 @@
1fn entry(x: []i32) i32 {
2 return x.*;
3}
4comptime {
5 _ = entry;
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:13: error: index syntax required for slice type '[]i32'
test/cases/compile_errors/dereference_unknown_length_pointer.zig created+9
......@@ -0,0 +1,9 @@
1export fn entry(x: [*]i32) i32 {
2 return x.*;
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:13: error: index syntax required for unknown-length pointer type '[*]i32'
test/cases/compile_errors/invalid_deref_on_switch_target.zig created+17
......@@ -0,0 +1,17 @@
1comptime {
2 var tile = Tile.Empty;
3 switch (tile.*) {
4 Tile.Empty => {},
5 Tile.Filled => {},
6 }
7}
8const Tile = enum {
9 Empty,
10 Filled,
11};
12
13// error
14// backend=stage2
15// target=native
16//
17// :3:17: error: cannot dereference non-pointer type 'tmp.Tile'
test/cases/compile_errors/invalid_multiple_dereferences.zig created+19
......@@ -0,0 +1,19 @@
1export fn a() void {
2 var box = Box{ .field = 0 };
3 box.*.field = 1;
4}
5export fn b() void {
6 var box = Box{ .field = 0 };
7 var boxPtr = &box;
8 boxPtr.*.*.field = 1;
9}
10pub const Box = struct {
11 field: i32,
12};
13
14// error
15// backend=stage2
16// target=native
17//
18// :3:8: error: cannot dereference non-pointer type 'tmp.Box'
19// :8:13: error: cannot dereference non-pointer type 'tmp.Box'
test/cases/compile_errors/stage1/comptime_ptrcast_of_zero-sized_type.zig created+12
......@@ -0,0 +1,12 @@
1fn foo() void {
2 const node: struct {} = undefined;
3 const vla_ptr = @ptrCast([*]const u8, &node);
4 _ = vla_ptr;
5}
6comptime { foo(); }
7
8// error
9// backend=stage1
10// target=native
11//
12// tmp.zig:3:21: error: '*const struct:2:17' and '[*]const u8' do not have the same in-memory representation
test/cases/compile_errors/stage1/deref_on_undefined_value.zig deleted-10
......@@ -1,10 +0,0 @@
1comptime {
2 var a: *u8 = undefined;
3 _ = a.*;
4}
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:3:9: error: attempt to dereference undefined value
test/cases/compile_errors/stage1/obj/assign_to_invalid_dereference.zig deleted-9
......@@ -1,9 +0,0 @@
1export fn entry() void {
2 'a'.* = 1;
3}
4
5// error
6// backend=stage1
7// target=native
8//
9// tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'
test/cases/compile_errors/stage1/obj/comptime_ptrcast_of_zero-sized_type.zig deleted-12
......@@ -1,12 +0,0 @@
1fn foo() void {
2 const node: struct {} = undefined;
3 const vla_ptr = @ptrCast([*]const u8, &node);
4 _ = vla_ptr;
5}
6comptime { foo(); }
7
8// error
9// backend=stage1
10// target=native
11//
12// tmp.zig:3:21: error: '*const struct:2:17' and '[*]const u8' do not have the same in-memory representation
test/cases/compile_errors/stage1/obj/deref_slice_and_get_len_field.zig deleted-10
......@@ -1,10 +0,0 @@
1export fn entry() void {
2 var a: []u8 = undefined;
3 _ = a.*.len;
4}
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:3:10: error: attempt to dereference non-pointer type '[]u8'
test/cases/compile_errors/stage1/obj/dereference_an_array.zig deleted-14
......@@ -1,14 +0,0 @@
1var s_buffer: [10]u8 = undefined;
2pub fn pass(in: []u8) []u8 {
3 var out = &s_buffer;
4 out.*.* = in[0];
5 return out.*[0..1];
6}
7
8export fn entry() usize { return @sizeOf(@TypeOf(pass)); }
9
10// error
11// backend=stage1
12// target=native
13//
14// tmp.zig:4:10: error: attempt to dereference non-pointer type '[10]u8'
test/cases/compile_errors/stage1/obj/dereference_unknown_length_pointer.zig deleted-9
......@@ -1,9 +0,0 @@
1export fn entry(x: [*]i32) i32 {
2 return x.*;
3}
4
5// error
6// backend=stage1
7// target=native
8//
9// tmp.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32'
test/cases/compile_errors/stage1/obj/invalid_deref_on_switch_target.zig deleted-17
......@@ -1,17 +0,0 @@
1comptime {
2 var tile = Tile.Empty;
3 switch (tile.*) {
4 Tile.Empty => {},
5 Tile.Filled => {},
6 }
7}
8const Tile = enum {
9 Empty,
10 Filled,
11};
12
13// error
14// backend=stage1
15// target=native
16//
17// tmp.zig:3:17: error: attempt to dereference non-pointer type 'Tile'
test/cases/compile_errors/stage1/obj/invalid_multiple_dereferences.zig deleted-19
......@@ -1,19 +0,0 @@
1export fn a() void {
2 var box = Box{ .field = 0 };
3 box.*.field = 1;
4}
5export fn b() void {
6 var box = Box{ .field = 0 };
7 var boxPtr = &box;
8 boxPtr.*.*.field = 1;
9}
10pub const Box = struct {
11 field: i32,
12};
13
14// error
15// backend=stage1
16// target=native
17//
18// tmp.zig:3:8: error: attempt to dereference non-pointer type 'Box'
19// tmp.zig:8:13: error: attempt to dereference non-pointer type 'Box'
test/cases/compile_errors/stage1/obj/take_slice_of_invalid_dereference.zig deleted-10
......@@ -1,10 +0,0 @@
1export fn entry() void {
2 const x = 'a'.*[0..];
3 _ = x;
4}
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'
test/cases/compile_errors/take_slice_of_invalid_dereference.zig created+10
......@@ -0,0 +1,10 @@
1export fn entry() void {
2 const x = 'a'.*[0..];
3 _ = x;
4}
5
6// error
7// backend=stage2
8// target=native
9//
10// :2:18: error: cannot dereference non-pointer type 'comptime_int'