Zig Version
0.12.0-dev.3609+ac21ade66
Steps to Reproduce and Observed Behavior
Given repo.zig:
const std = @import("std");
test {
var buffer = try std.testing.allocator.alloc(u8, 3);
defer std.testing.allocator.free(buffer);
// realloc works as expected
buffer = try std.testing.allocator.realloc(buffer, 2);
try std.testing.expectEqual(2, buffer.len);
std.debug.assert(std.testing.allocator.resize(buffer, 1));
try std.testing.expectEqual(1, buffer.len);
}
Run zig test repo.zig:
Test [1/1] test_0... expected 1, found 2
[gpa] (err): Allocation size 1 bytes does not match free size 2. Allocation:
...\repo.zig:4:49: 0xdd118c in test_0 (test.exe.obj)
var buffer = try std.testing.allocator.alloc(u8, 3);
^
[truncated...]
...\repo.zig:5:37: 0xbb12eb in test_0 (test.exe.obj)
defer std.testing.allocator.free(buffer);
^
[truncated...]
...\repo.zig:12:5: 0x5a12e4 in test_0 (test.exe.obj)
try std.testing.expectEqual(1, buffer.len);
^
I expected resize to have updated buffer.len, but it does not. This makes resize a footgun as buffer[1] will now segfault.
Also note how the free failed. Even the allocator expected a slice of len 1.
The following use case is how I encountered this issue:
extern fn foo(array_ptr: [*c]u8, array_capacity: u32, bytes_written: *u32) callconv(.C) void;
fn allocFoo(allocator: std.mem.Allocator, capacity: u32) ![]u8 {
var buffer = try allocator.alloc(u8, capacity);
errdefer allocator.free(buffer);
var bytes_written: u32 = 0;
foo(buffer.ptr, capacity, &bytes_written);
if (!allocator.resize(buffer, bytes_written)) {
buffer = try allocator.realloc(buffer, bytes_written);
}
return buffer;
}
test {
const bytes = try allocFoo(std.testing.allocator, 10);
defer std.testing.allocator.free(bytes);
for (bytes) |_| {
// segfaults if bytes_written is less than 10 and resize returned true
}
}
The workaround is to use realloc instead.
Expected Behavior
To not shoot myself in the foot.
Zig Version
0.12.0-dev.3609+ac21ade66
Steps to Reproduce and Observed Behavior
Given
repo.zig:Run
zig test repo.zig:I expected
resizeto have updatedbuffer.len, but it does not. This makesresizea footgun asbuffer[1]will now segfault.Also note how the
freefailed. Even the allocator expected a slice oflen1.The following use case is how I encountered this issue:
The workaround is to use
reallocinstead.Expected Behavior
To not shoot myself in the foot.