mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
std.sort.pdq: fix out-of-bounds access in partialInsertionSort (#25253)
* std.sort.pdq: fix out-of-bounds access in partialInsertionSort When sorting a sub-range that doesn't start at index 0, the partialInsertionSort function could access indices below the range start. The loop condition `while (j >= 1)` didn't respect the arbitrary range boundaries [a, b). This changes the condition to `while (j > a)` to ensure indices never go below the range start, fixing the issue where pdqContext would access out-of-bounds indices. Fixes #25250
This commit is contained in:
parent
4314c9653a
commit
6dd0270a19
1 changed files with 48 additions and 1 deletions
|
|
@ -227,7 +227,7 @@ fn partialInsertionSort(a: usize, b: usize, context: anytype) bool {
|
||||||
// shift the smaller element to the left.
|
// shift the smaller element to the left.
|
||||||
if (i - a >= 2) {
|
if (i - a >= 2) {
|
||||||
var j = i - 1;
|
var j = i - 1;
|
||||||
while (j >= 1) : (j -= 1) {
|
while (j > a) : (j -= 1) {
|
||||||
if (!context.lessThan(j, j - 1)) break;
|
if (!context.lessThan(j, j - 1)) break;
|
||||||
context.swap(j, j - 1);
|
context.swap(j, j - 1);
|
||||||
}
|
}
|
||||||
|
|
@ -328,3 +328,50 @@ fn reverseRange(a: usize, b: usize, context: anytype) void {
|
||||||
j -= 1;
|
j -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "pdqContext respects arbitrary range boundaries" {
|
||||||
|
// Regression test for issue #25250
|
||||||
|
// pdqsort should never access indices outside the specified [a, b) range
|
||||||
|
var data: [2000]i32 = @splat(0);
|
||||||
|
|
||||||
|
// Fill with data that triggers the partialInsertionSort path
|
||||||
|
for (0..data.len) |i| {
|
||||||
|
data[i] = @intCast(@mod(@as(i32, @intCast(i)) * 7, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
const TestContext = struct {
|
||||||
|
items: []i32,
|
||||||
|
range_start: usize,
|
||||||
|
range_end: usize,
|
||||||
|
|
||||||
|
pub fn lessThan(ctx: @This(), a: usize, b: usize) bool {
|
||||||
|
// Assert indices are within the expected range
|
||||||
|
testing.expect(a >= ctx.range_start and a < ctx.range_end) catch @panic("index a out of range");
|
||||||
|
testing.expect(b >= ctx.range_start and b < ctx.range_end) catch @panic("index b out of range");
|
||||||
|
return ctx.items[a] < ctx.items[b];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn swap(ctx: @This(), a: usize, b: usize) void {
|
||||||
|
// Assert indices are within the expected range
|
||||||
|
testing.expect(a >= ctx.range_start and a < ctx.range_end) catch @panic("index a out of range");
|
||||||
|
testing.expect(b >= ctx.range_start and b < ctx.range_end) catch @panic("index b out of range");
|
||||||
|
mem.swap(i32, &ctx.items[a], &ctx.items[b]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test sorting a sub-range that doesn't start at 0
|
||||||
|
const start = 1118;
|
||||||
|
const end = 1764;
|
||||||
|
const ctx = TestContext{
|
||||||
|
.items = &data,
|
||||||
|
.range_start = start,
|
||||||
|
.range_end = end,
|
||||||
|
};
|
||||||
|
|
||||||
|
pdqContext(start, end, ctx);
|
||||||
|
|
||||||
|
// Verify the range is sorted
|
||||||
|
for ((start + 1)..end) |i| {
|
||||||
|
try testing.expect(data[i - 1] <= data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue