diff --git a/lib/std/sort.zig b/lib/std/sort.zig index 8705d2401730..4decdcd827a9 100644 --- a/lib/std/sort.zig +++ b/lib/std/sort.zig @@ -984,3 +984,32 @@ test isSorted { try testing.expect(isSorted(u8, "ffff", {}, asc_u8)); try testing.expect(isSorted(u8, "ffff", {}, desc_u8)); } + +test "stack overflow" { + var array = [_]u64{math.maxInt(u64)} ** 3789730; + var idx: usize = 0; + var a: usize = 0; + var d: u64 = 0; + while (d < 64) : (d += 1) { + const cur_len = array.len - a; + const left_len = cur_len / 8; + const small_val = 10 * d + 1; + const pivot_val = 10 * d + 2; + const i_pos = a + (cur_len / 4); + const j_pos = a + (cur_len / 4) * 2; + array[i_pos - 1] = small_val; + array[i_pos] = small_val; + array[i_pos + 1] = small_val; + array[j_pos - 1] = pivot_val; + array[j_pos] = small_val; + var fill_len = left_len - 4; + while (fill_len > 0) : (fill_len -= 1) { + while (array[idx] != math.maxInt(u64)) idx += 1; + array[idx] = small_val; + idx += 1; + } + a = a + left_len + 1; + } + pdq(u64, &array, {}, asc(u64)); + try testing.expect(isSorted(u64, &array, {}, asc(u64))); +} diff --git a/lib/std/sort/pdq.zig b/lib/std/sort/pdq.zig index 55bd17ae93e5..d916712162ef 100644 --- a/lib/std/sort/pdq.zig +++ b/lib/std/sort/pdq.zig @@ -41,10 +41,11 @@ const Hint = enum { /// which each take 2 `usize` parameters indicating the index of an item. /// Sorts in ascending order with respect to `lessThan`. pub fn pdqContext(a: usize, b: usize, context: anytype) void { + if (a == b) return; // slices of up to this length get sorted using insertion sort. const max_insertion = 24; // number of allowed imbalanced partitions before switching to heap sort. - const max_limit = std.math.floorPowerOfTwo(usize, b - a) + 1; + const max_limit = math.log2_int(usize, b - a) + 1; // set upper bound on stack memory usage. const Range = struct { a: usize, b: usize, limit: usize }; @@ -113,13 +114,13 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { const left_len = mid - range.a; const right_len = range.b - mid; const balanced_threshold = len / 8; - if (left_len < right_len) { - was_balanced = left_len >= balanced_threshold; + if (right_len < left_len) { + was_balanced = right_len >= balanced_threshold; stack[top] = .{ .a = range.a, .b = mid, .limit = range.limit }; top += 1; range.a = mid + 1; } else { - was_balanced = right_len >= balanced_threshold; + was_balanced = left_len >= balanced_threshold; stack[top] = .{ .a = mid + 1, .b = range.b, .limit = range.limit }; top += 1; range.b = mid;