authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-29 13:41:17-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-12-29 13:41:17-05:00
log271452d225803770d29af1c9401fc610254d23c2
tree9b6f0cba6cafd20bfb071464e02ce63c4e0f7a02
parent45e4b16caf30093bcb98b266b25d1a226efd1641
parent5b6326ec6540d1b7af8de1176f657672be72a1e4
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22344 from Techatrix/slice-of-slice

fix incorrect slicing by length detection cases

4 files changed, 106 insertions(+), 75 deletions(-)

lib/std/zig/AstGen.zig+36-75
...@@ -876,100 +876,61 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -876,100 +876,61 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
876876
877 .for_simple, .@"for" => return forExpr(gz, scope, ri.br(), node, tree.fullFor(node).?, false),877 .for_simple, .@"for" => return forExpr(gz, scope, ri.br(), node, tree.fullFor(node).?, false),
878878
879 .slice_open => {879 .slice_open,
880 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);880 .slice,
881881 .slice_sentinel,
882 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);882 => {
883 const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[node].rhs);883 const full = tree.fullSlice(node).?;
884 try emitDbgStmt(gz, cursor);884 if (full.ast.end != 0 and
885 const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{885 node_tags[full.ast.sliced] == .slice_open and
886 .lhs = lhs,886 nodeIsTriviallyZero(tree, full.ast.start))
887 .start = start,887 {
888 });888 const lhs_extra = tree.sliceOpen(full.ast.sliced).ast;
889 return rvalue(gz, ri, result, node);
890 },
891 .slice => {
892 const extra = tree.extraData(node_datas[node].rhs, Ast.Node.Slice);
893 const lhs_node = node_datas[node].lhs;
894 const lhs_tag = node_tags[lhs_node];
895 const lhs_is_slice_sentinel = lhs_tag == .slice_sentinel;
896 const lhs_is_open_slice = lhs_tag == .slice_open or
897 (lhs_is_slice_sentinel and tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel).end == 0);
898 if (lhs_is_open_slice and nodeIsTriviallyZero(tree, extra.start)) {
899 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[lhs_node].lhs);
900
901 const start = if (lhs_is_slice_sentinel) start: {
902 const lhs_extra = tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel);
903 break :start try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, lhs_extra.start);
904 } else try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[lhs_node].rhs);
905889
890 const lhs = try expr(gz, scope, .{ .rl = .ref }, lhs_extra.sliced);
891 const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, lhs_extra.start);
906 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);892 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
907 const len = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none;893 const len = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.end);
894 const sentinel = if (full.ast.sentinel != 0) try expr(gz, scope, .{ .rl = .none }, full.ast.sentinel) else .none;
908 try emitDbgStmt(gz, cursor);895 try emitDbgStmt(gz, cursor);
909 const result = try gz.addPlNode(.slice_length, node, Zir.Inst.SliceLength{896 const result = try gz.addPlNode(.slice_length, node, Zir.Inst.SliceLength{
910 .lhs = lhs,897 .lhs = lhs,
911 .start = start,898 .start = start,
912 .len = len,899 .len = len,
913 .start_src_node_offset = gz.nodeIndexToRelative(lhs_node),900 .start_src_node_offset = gz.nodeIndexToRelative(full.ast.sliced),
914 .sentinel = .none,901 .sentinel = sentinel,
915 });902 });
916 return rvalue(gz, ri, result, node);903 return rvalue(gz, ri, result, node);
917 }904 }
918 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);905 const lhs = try expr(gz, scope, .{ .rl = .ref }, full.ast.sliced);
919906
920 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);907 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
921 const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.start);908 const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.start);
922 const end = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end);909 const end = if (full.ast.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.end) else .none;
910 const sentinel = if (full.ast.sentinel != 0) try expr(gz, scope, .{ .rl = .none }, full.ast.sentinel) else .none;
923 try emitDbgStmt(gz, cursor);911 try emitDbgStmt(gz, cursor);
924 const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{912 if (sentinel != .none) {
925 .lhs = lhs,913 const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{
926 .start = start,
927 .end = end,
928 });
929 return rvalue(gz, ri, result, node);
930 },
931 .slice_sentinel => {
932 const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel);
933 const lhs_node = node_datas[node].lhs;
934 const lhs_tag = node_tags[lhs_node];
935 const lhs_is_slice_sentinel = lhs_tag == .slice_sentinel;
936 const lhs_is_open_slice = lhs_tag == .slice_open or
937 (lhs_is_slice_sentinel and tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel).end == 0);
938 if (lhs_is_open_slice and nodeIsTriviallyZero(tree, extra.start)) {
939 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[lhs_node].lhs);
940
941 const start = if (lhs_is_slice_sentinel) start: {
942 const lhs_extra = tree.extraData(node_datas[lhs_node].rhs, Ast.Node.SliceSentinel);
943 break :start try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, lhs_extra.start);
944 } else try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[lhs_node].rhs);
945
946 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
947 const len = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none;
948 const sentinel = try expr(gz, scope, .{ .rl = .none }, extra.sentinel);
949 try emitDbgStmt(gz, cursor);
950 const result = try gz.addPlNode(.slice_length, node, Zir.Inst.SliceLength{
951 .lhs = lhs,914 .lhs = lhs,
952 .start = start,915 .start = start,
953 .len = len,916 .end = end,
954 .start_src_node_offset = gz.nodeIndexToRelative(lhs_node),
955 .sentinel = sentinel,917 .sentinel = sentinel,
956 });918 });
957 return rvalue(gz, ri, result, node);919 return rvalue(gz, ri, result, node);
920 } else if (end != .none) {
921 const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{
922 .lhs = lhs,
923 .start = start,
924 .end = end,
925 });
926 return rvalue(gz, ri, result, node);
927 } else {
928 const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{
929 .lhs = lhs,
930 .start = start,
931 });
932 return rvalue(gz, ri, result, node);
958 }933 }
959 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
960
961 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
962 const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.start);
963 const end = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none;
964 const sentinel = try expr(gz, scope, .{ .rl = .none }, extra.sentinel);
965 try emitDbgStmt(gz, cursor);
966 const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{
967 .lhs = lhs,
968 .start = start,
969 .end = end,
970 .sentinel = sentinel,
971 });
972 return rvalue(gz, ri, result, node);
973 },934 },
974935
975 .deref => {936 .deref => {
test/behavior/slice.zig+34
...@@ -98,6 +98,40 @@ test "comptime slice of slice preserves comptime var" {...@@ -98,6 +98,40 @@ test "comptime slice of slice preserves comptime var" {
98 }98 }
99}99}
100100
101test "open slice of open slice with sentinel" {
102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
103
104 var slice: [:0]const u8 = "hello";
105 _ = &slice;
106
107 comptime assert(@TypeOf(slice[0..][0.. :0]) == [:0]const u8);
108 try expect(slice[0..][0.. :0].len == 5);
109 try expect(slice[0..][0.. :0][0] == 'h');
110 try expect(slice[0..][0.. :0][5] == 0);
111
112 comptime assert(@TypeOf(slice[1..][0.. :0]) == [:0]const u8);
113 try expect(slice[1..][0.. :0].len == 4);
114 try expect(slice[1..][0.. :0][0] == 'e');
115 try expect(slice[1..][0.. :0][4] == 0);
116}
117
118test "open slice with sentinel of slice with end index" {
119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120
121 var slice: [:0]const u8 = "hello";
122 _ = &slice;
123
124 comptime assert(@TypeOf(slice[0.. :0][0..5]) == *const [5]u8);
125 try expect(slice[0.. :0][0..5].len == 5);
126 try expect(slice[0.. :0][0..5][0] == 'h');
127 try expect(slice[0.. :0][0..5][4] == 'o');
128
129 comptime assert(@TypeOf(slice[0.. :0][0..5 :0]) == *const [5:0]u8);
130 try expect(slice[0.. :0][0..5 :0].len == 5);
131 try expect(slice[0.. :0][0..5 :0][0] == 'h');
132 try expect(slice[0.. :0][0..5 :0][5] == 0);
133}
134
101test "slice of type" {135test "slice of type" {
102 comptime {136 comptime {
103 var types_array = [_]type{ i32, f64, type };137 var types_array = [_]type{ i32, f64, type };
test/cases/safety/slice by length sentinel mismatch on lhs.zig created+18
...@@ -0,0 +1,18 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "sentinel mismatch: expected 1, found 3")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 var buf: [4:0]u8 = .{ 1, 2, 3, 4 };
12 const slice = buf[0..][0..2 :1];
13 _ = slice;
14 return error.TestFailed;
15}
16// run
17// backend=llvm
18// target=native
test/cases/safety/slice by length sentinel mismatch on rhs.zig created+18
...@@ -0,0 +1,18 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "sentinel mismatch: expected 1, found 0")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 var buf: [4:0]u8 = .{ 1, 2, 3, 4 };
12 const slice = buf[0.. :1][0..2];
13 _ = slice;
14 return error.TestFailed;
15}
16// run
17// backend=llvm
18// target=native