authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-15 00:24:50-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-16 05:14:38-04:00
loge32454796cb601be8558cd6d078854a7dc2d1a14
tree16014c7be8ba7168701c72451821ab44348b0ac8
parent14caccb4770680fa0eb1fad44bc93089459fe52f

indexOfSentinel: fix ub


1 files changed, 6 insertions(+), 5 deletions(-)

lib/std/mem.zig+6-5
...@@ -1050,15 +1050,16 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co...@@ -1050,15 +1050,16 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co
1050 // as we don't read into a new page. This should be the case for most architectures1050 // as we don't read into a new page. This should be the case for most architectures
1051 // which use paged memory, however should be confirmed before adding a new arch below.1051 // which use paged memory, however should be confirmed before adding a new arch below.
1052 .aarch64, .x86, .x86_64 => if (std.simd.suggestVectorLength(T)) |block_len| {1052 .aarch64, .x86, .x86_64 => if (std.simd.suggestVectorLength(T)) |block_len| {
1053 const block_size = @sizeOf(T) * block_len;
1053 const Block = @Vector(block_len, T);1054 const Block = @Vector(block_len, T);
1054 const mask: Block = @splat(sentinel);1055 const mask: Block = @splat(sentinel);
10551056
1056 comptime std.debug.assert(std.mem.page_size % @sizeOf(Block) == 0);1057 comptime std.debug.assert(std.mem.page_size % block_size == 0);
10571058
1058 // First block may be unaligned1059 // First block may be unaligned
1059 const start_addr = @intFromPtr(&p[i]);1060 const start_addr = @intFromPtr(&p[i]);
1060 const offset_in_page = start_addr & (std.mem.page_size - 1);1061 const offset_in_page = start_addr & (std.mem.page_size - 1);
1061 if (offset_in_page <= std.mem.page_size - @sizeOf(Block)) {1062 if (offset_in_page <= std.mem.page_size - block_size) {
1062 // Will not read past the end of a page, full block.1063 // Will not read past the end of a page, full block.
1063 const block: Block = p[i..][0..block_len].*;1064 const block: Block = p[i..][0..block_len].*;
1064 const matches = block == mask;1065 const matches = block == mask;
...@@ -1066,19 +1067,19 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co...@@ -1066,19 +1067,19 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co
1066 return i + std.simd.firstTrue(matches).?;1067 return i + std.simd.firstTrue(matches).?;
1067 }1068 }
10681069
1069 i += (std.mem.alignForward(usize, start_addr, @alignOf(Block)) - start_addr) / @sizeOf(T);1070 i += @divExact(std.mem.alignForward(usize, start_addr, block_size) - start_addr, @sizeOf(T));
1070 } else {1071 } else {
1071 // Would read over a page boundary. Per-byte at a time until aligned or found.1072 // Would read over a page boundary. Per-byte at a time until aligned or found.
1072 // 0.39% chance this branch is taken for 4K pages at 16b block length.1073 // 0.39% chance this branch is taken for 4K pages at 16b block length.
1073 //1074 //
1074 // An alternate strategy is to do read a full block (the last in the page) and1075 // An alternate strategy is to do read a full block (the last in the page) and
1075 // mask the entries before the pointer.1076 // mask the entries before the pointer.
1076 while ((@intFromPtr(&p[i]) & (@alignOf(Block) - 1)) != 0) : (i += 1) {1077 while ((@intFromPtr(&p[i]) & (block_size - 1)) != 0) : (i += 1) {
1077 if (p[i] == sentinel) return i;1078 if (p[i] == sentinel) return i;
1078 }1079 }
1079 }1080 }
10801081
1081 std.debug.assert(std.mem.isAligned(@intFromPtr(&p[i]), @alignOf(Block)));1082 std.debug.assert(std.mem.isAligned(@intFromPtr(&p[i]), block_size));
1082 while (true) {1083 while (true) {
1083 const block: *const Block = @ptrCast(@alignCast(p[i..][0..block_len]));1084 const block: *const Block = @ptrCast(@alignCast(p[i..][0..block_len]));
1084 const matches = block.* == mask;1085 const matches = block.* == mask;