authorgravatar for inkryption07@gmail.comInKryption <inkryption07@gmail.com> 2022-09-16 18:34:51+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-27 22:00:47-04:00
logbc72ae5e4e6d8f2253aed1316b053ad1022f9f67
treeaa16a922bb65a479409d94c743880b6909b61112
parent1d1c7ae5de3e981099522a8610764a6595b1b7a1

Sema: Prevent coercion from tuple pointer to mutable slice.

Also fix some stdlib code affected by this. Co-authored by: topolarity <topolarity@tapscott.me>

5 files changed, 68 insertions(+), 27 deletions(-)

lib/std/fs/wasi.zig+1-1
...@@ -201,7 +201,7 @@ pub const PreopenList = struct {...@@ -201,7 +201,7 @@ pub const PreopenList = struct {
201 // If we were provided a CWD root to resolve against, we try to treat Preopen dirs as201 // If we were provided a CWD root to resolve against, we try to treat Preopen dirs as
202 // POSIX paths, relative to "/" or `cwd_root` depending on whether they start with "."202 // POSIX paths, relative to "/" or `cwd_root` depending on whether they start with "."
203 const path = if (cwd_root) |cwd| blk: {203 const path = if (cwd_root) |cwd| blk: {
204 const resolve_paths: [][]const u8 = if (raw_path[0] == '.') &.{ cwd, raw_path } else &.{ "/", raw_path };204 const resolve_paths: []const []const u8 = if (raw_path[0] == '.') &.{ cwd, raw_path } else &.{ "/", raw_path };
205 break :blk fs.path.resolve(self.buffer.allocator, resolve_paths) catch |err| switch (err) {205 break :blk fs.path.resolve(self.buffer.allocator, resolve_paths) catch |err| switch (err) {
206 error.CurrentWorkingDirectoryUnlinked => unreachable, // root is absolute, so CWD not queried206 error.CurrentWorkingDirectoryUnlinked => unreachable, // root is absolute, so CWD not queried
207 else => |e| return e,207 else => |e| return e,
lib/std/x/net/bpf.zig+2-2
...@@ -691,14 +691,14 @@ test "tcpdump filter" {...@@ -691,14 +691,14 @@ test "tcpdump filter" {
691 );691 );
692}692}
693693
694fn expectPass(data: anytype, filter: []Insn) !void {694fn expectPass(data: anytype, filter: []const Insn) !void {
695 try expectEqual(695 try expectEqual(
696 @as(u32, 0),696 @as(u32, 0),
697 try simulate(mem.asBytes(data), filter, .Big),697 try simulate(mem.asBytes(data), filter, .Big),
698 );698 );
699}699}
700700
701fn expectFail(expected_error: anyerror, data: anytype, filter: []Insn) !void {701fn expectFail(expected_error: anyerror, data: anytype, filter: []const Insn) !void {
702 try expectError(702 try expectError(
703 expected_error,703 expected_error,
704 simulate(mem.asBytes(data), filter, native_endian),704 simulate(mem.asBytes(data), filter, native_endian),
src/Sema.zig+32-23
...@@ -18208,7 +18208,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in...@@ -18208,7 +18208,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
18208 return sema.analyzeDeclVal(block, src, new_decl_index);18208 return sema.analyzeDeclVal(block, src, new_decl_index);
18209 },18209 },
18210 .Fn => {18210 .Fn => {
18211 const struct_val = union_val.val.castTag(.aggregate).?.data;18211 const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data;
18212 // TODO use reflection instead of magic numbers here18212 // TODO use reflection instead of magic numbers here
18213 // calling_convention: CallingConvention,18213 // calling_convention: CallingConvention,
18214 const cc = struct_val[0].toEnum(std.builtin.CallingConvention);18214 const cc = struct_val[0].toEnum(std.builtin.CallingConvention);
...@@ -18242,12 +18242,17 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in...@@ -18242,12 +18242,17 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
18242 break :alignment alignment;18242 break :alignment alignment;
18243 }18243 }
18244 };18244 };
18245 const return_type = return_type_val.optionalValue() orelse
18246 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
18247
18245 var buf: Value.ToTypeBuffer = undefined;18248 var buf: Value.ToTypeBuffer = undefined;
1824618249
18247 const args_slice_val = args_val.castTag(.slice).?.data;18250 const args_slice_val = args_val.castTag(.slice).?.data;
18248 const args_len = try sema.usizeCast(block, src, args_slice_val.len.toUnsignedInt(mod.getTarget()));18251 const args_len = try sema.usizeCast(block, src, args_slice_val.len.toUnsignedInt(mod.getTarget()));
18249 var param_types = try sema.arena.alloc(Type, args_len);18252
18250 var comptime_params = try sema.arena.alloc(bool, args_len);18253 const param_types = try sema.arena.alloc(Type, args_len);
18254 const comptime_params = try sema.arena.alloc(bool, args_len);
18255
18251 var noalias_bits: u32 = 0;18256 var noalias_bits: u32 = 0;
18252 var i: usize = 0;18257 var i: usize = 0;
18253 while (i < args_len) : (i += 1) {18258 while (i < args_len) : (i += 1) {
...@@ -18275,11 +18280,9 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in...@@ -18275,11 +18280,9 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
18275 return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{});18280 return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{});
1827618281
18277 param_types[i] = try param_type.toType(&buf).copy(sema.arena);18282 param_types[i] = try param_type.toType(&buf).copy(sema.arena);
18283 comptime_params[i] = false;
18278 }18284 }
1827918285
18280 const return_type = return_type_val.optionalValue() orelse
18281 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
18282
18283 var fn_info = Type.Payload.Function.Data{18286 var fn_info = Type.Payload.Function.Data{
18284 .param_types = param_types,18287 .param_types = param_types,
18285 .comptime_params = comptime_params.ptr,18288 .comptime_params = comptime_params.ptr,
...@@ -24075,20 +24078,23 @@ fn coerceExtra(...@@ -24075,20 +24078,23 @@ fn coerceExtra(
24075 },24078 },
24076 else => {},24079 else => {},
24077 },24080 },
24078 .Slice => {24081 .Slice => to_slice: {
24079 // pointer to tuple to slice24082 if (inst_ty.zigTypeTag() == .Array) {
24080 if (inst_ty.isSinglePointer() and inst_ty.childType().isTuple() and dest_info.size == .Slice and24083 return sema.fail(
24081 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))24084 block,
24082 {24085 inst_src,
24083 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);24086 "array literal requires address-of operator (&) to coerce to slice type '{}'",
24087 .{dest_ty.fmt(sema.mod)},
24088 );
24084 }24089 }
2408524090
24091 if (!inst_ty.isSinglePointer()) break :to_slice;
24092 const inst_child_ty = inst_ty.childType();
24093 if (!inst_child_ty.isTuple()) break :to_slice;
24094
24086 // empty tuple to zero-length slice24095 // empty tuple to zero-length slice
24087 // note that this allows coercing to a mutable slice.24096 // note that this allows coercing to a mutable slice.
24088 if (inst_ty.isSinglePointer() and24097 if (inst_child_ty.tupleFields().types.len == 0) {
24089 inst_ty.childType().tag() == .empty_struct_literal and
24090 dest_info.size == .Slice)
24091 {
24092 const slice_val = try Value.Tag.slice.create(sema.arena, .{24098 const slice_val = try Value.Tag.slice.create(sema.arena, .{
24093 .ptr = Value.undef,24099 .ptr = Value.undef,
24094 .len = Value.zero,24100 .len = Value.zero,
...@@ -24096,14 +24102,17 @@ fn coerceExtra(...@@ -24096,14 +24102,17 @@ fn coerceExtra(
24096 return sema.addConstant(dest_ty, slice_val);24102 return sema.addConstant(dest_ty, slice_val);
24097 }24103 }
2409824104
24099 if (inst_ty.zigTypeTag() == .Array) {24105 // pointer to tuple to slice
24100 return sema.fail(24106 if (dest_info.mutable) {
24101 block,24107 const err_msg = err_msg: {
24102 inst_src,24108 const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(sema.mod)});
24103 "array literal requires address-of operator (&) to coerce to slice type '{}'",24109 errdefer err_msg.deinit(sema.gpa);
24104 .{dest_ty.fmt(sema.mod)},24110 try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{});
24105 );24111 break :err_msg err_msg;
24112 };
24113 return sema.failWithOwnedErrorMsg(err_msg);
24106 }24114 }
24115 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
24107 },24116 },
24108 .Many => p: {24117 .Many => p: {
24109 if (!inst_ty.isSlice()) break :p;24118 if (!inst_ty.isSlice()) break :p;
test/behavior/packed-struct.zig+1-1
...@@ -410,7 +410,7 @@ test "load pointer from packed struct" {...@@ -410,7 +410,7 @@ test "load pointer from packed struct" {
410 y: u32,410 y: u32,
411 };411 };
412 var a: A = .{ .index = 123 };412 var a: A = .{ .index = 123 };
413 var b_list: []B = &.{.{ .x = &a, .y = 99 }};413 var b_list: []const B = &.{.{ .x = &a, .y = 99 }};
414 for (b_list) |b| {414 for (b_list) |b| {
415 var i = b.x.index;415 var i = b.x.index;
416 try expect(i == 123);416 try expect(i == 123);
test/cases/compile_errors/stage2/tuple_ptr_to_mut_slice.zig created+32
...@@ -0,0 +1,32 @@
1export fn entry1() void {
2 var a = .{ 1, 2, 3 };
3 _ = @as([]u8, &a);
4}
5export fn entry2() void {
6 var a = .{ @as(u8, 1), @as(u8, 2), @as(u8, 3) };
7 _ = @as([]u8, &a);
8}
9
10// runtime values
11var vals = [_]u7{ 4, 5, 6 };
12export fn entry3() void {
13 var a = .{ vals[0], vals[1], vals[2] };
14 _ = @as([]u8, &a);
15}
16export fn entry4() void {
17 var a = .{ @as(u8, vals[0]), @as(u8, vals[1]), @as(u8, vals[2]) };
18 _ = @as([]u8, &a);
19}
20
21// error
22// backend=stage2
23// target=native
24//
25// :3:19: error: cannot cast pointer to tuple to '[]u8'
26// :3:19: note: pointers to tuples can only coerce to constant pointers
27// :7:19: error: cannot cast pointer to tuple to '[]u8'
28// :7:19: note: pointers to tuples can only coerce to constant pointers
29// :14:19: error: cannot cast pointer to tuple to '[]u8'
30// :14:19: note: pointers to tuples can only coerce to constant pointers
31// :18:19: error: cannot cast pointer to tuple to '[]u8'
32// :18:19: note: pointers to tuples can only coerce to constant pointers