authorgravatar for alexandermitterholzer@noreply.codeberg.orgAlexander Mitterholzer <alexandermitterholzer@noreply.codeberg.org> 2026-10-09 21:55:17+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-09 15:52:15-07:00
log7c793c291683a1ac1758d7cf8cb8a7c239dd6989
tree8013b97615b7be2c644a0f580bcc7f30f8663072
parent2c276c2c753db70b43fadf7d77a3f460008f320c

std.testing: refuse resizes in checkAllAllocationFailures (#37142)

Fixes #37141 With resizes refused every growth goes through alloc, which is what the check counts, so the count no longer depends on the backing allocator. Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37142 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

1 files changed, 22 insertions(+), 1 deletions(-)

lib/std/testing.zig+22-1
......@@ -1149,7 +1149,9 @@ pub fn checkAllAllocationFailures(
11491149) !void {
11501150 // Try it once with unlimited memory, make sure it works
11511151 const needed_alloc_count = x: {
1152 var failing_allocator_inst = std.testing.FailingAllocator.init(backing_allocator, .{});
1152 var failing_allocator_inst = std.testing.FailingAllocator.init(backing_allocator, .{
1153 .resize_fail_index = 0,
1154 });
11531155
11541156 try @call(.auto, test_fn, .{failing_allocator_inst.allocator()} ++ extra_args);
11551157 break :x failing_allocator_inst.alloc_index;
......@@ -1158,6 +1160,7 @@ pub fn checkAllAllocationFailures(
11581160 for (0..needed_alloc_count) |fail_index| {
11591161 var failing_allocator_inst = std.testing.FailingAllocator.init(backing_allocator, .{
11601162 .fail_index = fail_index,
1163 .resize_fail_index = 0,
11611164 });
11621165
11631166 if (@call(.auto, test_fn, .{failing_allocator_inst.allocator()} ++ extra_args)) |_| {
......@@ -1239,6 +1242,24 @@ test "checkAllAllocationFailures provide result type to 'extra_args' argument" {
12391242 );
12401243}
12411244
1245test "checkAllAllocationFailures does not depend on in-place resizes" {
1246 // `std.testing.allocator` never reuses memory, so whether a list can grow in place depends
1247 // on where in its bucket it landed, which differs from one run to the next.
1248 const S = struct {
1249 fn f(gpa: std.mem.Allocator) !void {
1250 var a: std.ArrayList(u8) = .empty;
1251 defer a.deinit(gpa);
1252 var b: std.ArrayList(u8) = .empty;
1253 defer b.deinit(gpa);
1254 for (0..2000) |i| {
1255 try a.append(gpa, @truncate(i));
1256 try b.append(gpa, @truncate(i));
1257 }
1258 }
1259 };
1260 try checkAllAllocationFailures(std.testing.allocator, S.f, .{});
1261}
1262
12421263/// Given a type, references all the declarations inside, so that the semantic analyzer sees them.
12431264pub fn refAllDecls(comptime T: type) void {
12441265 if (!builtin.is_test) return;