Hello!
Below I have a piece of code that duplicates memory using an arena and returns a MemObject
type containing the arena and the duplicated value.
There are two functions mem_object
and mem_object_leak
the only difference between them is that mem_object_leak
sets the value of MemObject
in the return while mem_object
first assigns to a variable and then returns.
Both arenas are deinitialized so why does the leaky one leak ?
Edit: compiler version is 0.14.0-dev.3222+8a3aebaee
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = 10 }){};
defer _ = gpa.deinit();
const string: []const u8 = "hello";
var no_leak = try mem_object(gpa.allocator(), string);
var leak = try mem_object_leaky(gpa.allocator(), string);
no_leak.deinit();
leak.deinit();
}
pub fn MemObject(comptime T: type) type {
return struct {
const Self = @This();
arena: std.heap.ArenaAllocator,
value: T,
pub fn deinit(self: *Self) void {
self.arena.deinit();
}
};
}
pub fn mem_object(allocator: std.mem.Allocator, value: []const u8) !MemObject([]const u8) {
var arena = std.heap.ArenaAllocator.init(allocator);
errdefer arena.deinit();
const cloner = .{ .allocator = arena.allocator() };
const cloned = try clone_anytype(cloner, value);
return .{
.arena = arena,
// only difference
.value = cloned,
};
}
pub fn mem_object_leaky(allocator: std.mem.Allocator, value: []const u8) !MemObject([]const u8) {
var arena = std.heap.ArenaAllocator.init(allocator);
errdefer arena.deinit();
const cloner = .{ .allocator = arena.allocator() };
return .{
.arena = arena,
// only difference
.value = try clone_anytype(cloner, value),
};
}
pub fn clone_anytype(cloner: anytype, value: anytype) error{OutOfMemory}!@TypeOf(value) {
return try cloner.allocator.dupe(u8, value);
}