| ... | ... | @@ -227,7 +227,7 @@ fn partialInsertionSort(a: usize, b: usize, context: anytype) bool { |
| 227 | 227 | // shift the smaller element to the left. |
| 228 | 228 | if (i - a >= 2) { |
| 229 | 229 | var j = i - 1; |
| 230 | | while (j >= 1) : (j -= 1) { |
| 230 | while (j > a) : (j -= 1) { |
| 231 | 231 | if (!context.lessThan(j, j - 1)) break; |
| 232 | 232 | context.swap(j, j - 1); |
| 233 | 233 | } |
| ... | ... | @@ -328,3 +328,50 @@ fn reverseRange(a: usize, b: usize, context: anytype) void { |
| 328 | 328 | j -= 1; |
| 329 | 329 | } |
| 330 | 330 | } |
| 331 | |
| 332 | test "pdqContext respects arbitrary range boundaries" { |
| 333 | // Regression test for issue #25250 |
| 334 | // pdqsort should never access indices outside the specified [a, b) range |
| 335 | var data: [2000]i32 = @splat(0); |
| 336 | |
| 337 | // Fill with data that triggers the partialInsertionSort path |
| 338 | for (0..data.len) |i| { |
| 339 | data[i] = @intCast(@mod(@as(i32, @intCast(i)) * 7, 100)); |
| 340 | } |
| 341 | |
| 342 | const TestContext = struct { |
| 343 | items: []i32, |
| 344 | range_start: usize, |
| 345 | range_end: usize, |
| 346 | |
| 347 | pub fn lessThan(ctx: @This(), a: usize, b: usize) bool { |
| 348 | // Assert indices are within the expected range |
| 349 | testing.expect(a >= ctx.range_start and a < ctx.range_end) catch @panic("index a out of range"); |
| 350 | testing.expect(b >= ctx.range_start and b < ctx.range_end) catch @panic("index b out of range"); |
| 351 | return ctx.items[a] < ctx.items[b]; |
| 352 | } |
| 353 | |
| 354 | pub fn swap(ctx: @This(), a: usize, b: usize) void { |
| 355 | // Assert indices are within the expected range |
| 356 | testing.expect(a >= ctx.range_start and a < ctx.range_end) catch @panic("index a out of range"); |
| 357 | testing.expect(b >= ctx.range_start and b < ctx.range_end) catch @panic("index b out of range"); |
| 358 | mem.swap(i32, &ctx.items[a], &ctx.items[b]); |
| 359 | } |
| 360 | }; |
| 361 | |
| 362 | // Test sorting a sub-range that doesn't start at 0 |
| 363 | const start = 1118; |
| 364 | const end = 1764; |
| 365 | const ctx = TestContext{ |
| 366 | .items = &data, |
| 367 | .range_start = start, |
| 368 | .range_end = end, |
| 369 | }; |
| 370 | |
| 371 | pdqContext(start, end, ctx); |
| 372 | |
| 373 | // Verify the range is sorted |
| 374 | for ((start + 1)..end) |i| { |
| 375 | try testing.expect(data[i - 1] <= data[i]); |
| 376 | } |
| 377 | } |