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 {
201201 // If we were provided a CWD root to resolve against, we try to treat Preopen dirs as
202202 // POSIX paths, relative to "/" or `cwd_root` depending on whether they start with "."
203203 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 };
205205 break :blk fs.path.resolve(self.buffer.allocator, resolve_paths) catch |err| switch (err) {
206206 error.CurrentWorkingDirectoryUnlinked => unreachable, // root is absolute, so CWD not queried
207207 else => |e| return e,
lib/std/x/net/bpf.zig+2-2
......@@ -691,14 +691,14 @@ test "tcpdump filter" {
691691 );
692692}
693693
694fn expectPass(data: anytype, filter: []Insn) !void {
694fn expectPass(data: anytype, filter: []const Insn) !void {
695695 try expectEqual(
696696 @as(u32, 0),
697697 try simulate(mem.asBytes(data), filter, .Big),
698698 );
699699}
700700
701fn expectFail(expected_error: anyerror, data: anytype, filter: []Insn) !void {
701fn expectFail(expected_error: anyerror, data: anytype, filter: []const Insn) !void {
702702 try expectError(
703703 expected_error,
704704 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
1820818208 return sema.analyzeDeclVal(block, src, new_decl_index);
1820918209 },
1821018210 .Fn => {
18211 const struct_val = union_val.val.castTag(.aggregate).?.data;
18211 const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data;
1821218212 // TODO use reflection instead of magic numbers here
1821318213 // calling_convention: CallingConvention,
1821418214 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
1824218242 break :alignment alignment;
1824318243 }
1824418244 };
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
1824518248 var buf: Value.ToTypeBuffer = undefined;
1824618249
1824718250 const args_slice_val = args_val.castTag(.slice).?.data;
1824818251 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);
18250 var comptime_params = try sema.arena.alloc(bool, args_len);
18252
18253 const param_types = try sema.arena.alloc(Type, args_len);
18254 const comptime_params = try sema.arena.alloc(bool, args_len);
18255
1825118256 var noalias_bits: u32 = 0;
1825218257 var i: usize = 0;
1825318258 while (i < args_len) : (i += 1) {
......@@ -18275,11 +18280,9 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
1827518280 return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{});
1827618281
1827718282 param_types[i] = try param_type.toType(&buf).copy(sema.arena);
18283 comptime_params[i] = false;
1827818284 }
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
1828318286 var fn_info = Type.Payload.Function.Data{
1828418287 .param_types = param_types,
1828518288 .comptime_params = comptime_params.ptr,
......@@ -24075,20 +24078,23 @@ fn coerceExtra(
2407524078 },
2407624079 else => {},
2407724080 },
24078 .Slice => {
24079 // pointer to tuple to slice
24080 if (inst_ty.isSinglePointer() and inst_ty.childType().isTuple() and dest_info.size == .Slice and
24081 sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
24082 {
24083 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
24081 .Slice => to_slice: {
24082 if (inst_ty.zigTypeTag() == .Array) {
24083 return sema.fail(
24084 block,
24085 inst_src,
24086 "array literal requires address-of operator (&) to coerce to slice type '{}'",
24087 .{dest_ty.fmt(sema.mod)},
24088 );
2408424089 }
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
2408624095 // empty tuple to zero-length slice
2408724096 // note that this allows coercing to a mutable slice.
24088 if (inst_ty.isSinglePointer() and
24089 inst_ty.childType().tag() == .empty_struct_literal and
24090 dest_info.size == .Slice)
24091 {
24097 if (inst_child_ty.tupleFields().types.len == 0) {
2409224098 const slice_val = try Value.Tag.slice.create(sema.arena, .{
2409324099 .ptr = Value.undef,
2409424100 .len = Value.zero,
......@@ -24096,14 +24102,17 @@ fn coerceExtra(
2409624102 return sema.addConstant(dest_ty, slice_val);
2409724103 }
2409824104
24099 if (inst_ty.zigTypeTag() == .Array) {
24100 return sema.fail(
24101 block,
24102 inst_src,
24103 "array literal requires address-of operator (&) to coerce to slice type '{}'",
24104 .{dest_ty.fmt(sema.mod)},
24105 );
24105 // pointer to tuple to slice
24106 if (dest_info.mutable) {
24107 const err_msg = err_msg: {
24108 const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(sema.mod)});
24109 errdefer err_msg.deinit(sema.gpa);
24110 try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{});
24111 break :err_msg err_msg;
24112 };
24113 return sema.failWithOwnedErrorMsg(err_msg);
2410624114 }
24115 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
2410724116 },
2410824117 .Many => p: {
2410924118 if (!inst_ty.isSlice()) break :p;
test/behavior/packed-struct.zig+1-1
......@@ -410,7 +410,7 @@ test "load pointer from packed struct" {
410410 y: u32,
411411 };
412412 var a: A = .{ .index = 123 };
413 var b_list: []B = &.{.{ .x = &a, .y = 99 }};
413 var b_list: []const B = &.{.{ .x = &a, .y = 99 }};
414414 for (b_list) |b| {
415415 var i = b.x.index;
416416 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