You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The current documentation example for errdefer only shows it being used at function scope, where its behaviour is pretty intuitive. But the behaviour in if/while/for etc blocks - i.e. that the errdefer goes out of scope at the end of the block - is subtle and could use more documentation.
In particular, blocks silently break the pattern described in the documentation where "The deallocation code is always directly following the allocation code." A couple of footguns:
conststd=@import("std");
constError=error {
FlagrantViolation,
};
// Example 1fnerrdeferAtFunctionScope(allocator: *std.mem.Allocator) !void {
constptr=tryallocator.alloc(u8, 1);
// Does not leak: the errdefer is at the same scope as the return.errdeferallocator.free(ptr);
returnError.FlagrantViolation;
}
// Example 2fnerrdeferInBlock(allocator: *std.mem.Allocator) !void {
{
constptr=tryallocator.alloc(u8, 1);
// Leaks: by the time the error is returned, errdefer has gone out of scope.errdeferallocator.free(ptr);
}
returnError.FlagrantViolation;
}
// Example 3fnerrdeferInLoop(allocator: *std.mem.Allocator) !void {
varcount: usize=0;
while (true) {
constptr=tryallocator.alloc(u8, 1);
// Leaks on the second iteration of the loop: // the errdefer from the first iteration will have gone out of scope.errdeferallocator.free(ptr);
count+=1;
if (count==2) {
returnError.FlagrantViolation;
}
}
}
test"errdefer at function scope" {
// Passesstd.testing.expectError(Error.FlagrantViolation, errdeferAtFunctionScope(std.testing.allocator));
}
test"errdefer in block" {
// Fails with a leakstd.testing.expectError(Error.FlagrantViolation, errdeferInBlock(std.testing.allocator));
}
test"errdefer in loop" {
// Fails with a leakstd.testing.expectError(Error.FlagrantViolation, errdeferInLoop(std.testing.allocator));
}
The specific case that bit me was Example 3: repeatedly allocating in a failable loop, and assuming that I could keep an errdefer next to the alloc call and undo all previous allocations that way. It makes sense in retrospect that it doesn't work that way, but some scope examples in the docs could help users arrive at that mental model.
(Ideally, useless errdefer blocks like 2 could be a compiler error; 3 might be harder for the compiler to spot.)
The text was updated successfully, but these errors were encountered:
The current documentation example for
errdefer
only shows it being used at function scope, where its behaviour is pretty intuitive. But the behaviour in if/while/for etc blocks - i.e. that theerrdefer
goes out of scope at the end of the block - is subtle and could use more documentation.In particular, blocks silently break the pattern described in the documentation where "The deallocation code is always directly following the allocation code." A couple of footguns:
The specific case that bit me was Example 3: repeatedly allocating in a failable loop, and assuming that I could keep an
errdefer
next to thealloc
call and undo all previous allocations that way. It makes sense in retrospect that it doesn't work that way, but some scope examples in the docs could help users arrive at that mental model.(Ideally, useless
errdefer
blocks like 2 could be a compiler error; 3 might be harder for the compiler to spot.)The text was updated successfully, but these errors were encountered: