Not sure if this is a bug or not, I remember some parser leak was fixed in 0.14.x. Trying to handle deprecated config fields in a zon file, but getting a leak I cannot figure how to plug.
All ZON parser calls are freed via parse.free().
pub fn migrateConfig(
allocator: std.mem.Allocator,
config_path: []const u8,
) !void {
const MigrationConfig = MigrationType(Config);
const file = try std.fs.cwd().openFile(config_path, .{});
defer file.close();
// null-terminated
const content = try file.readToEndAllocOptions(
allocator,
1024 * 1024,
null,
@enumFromInt(@alignOf(u8)),
0,
);
defer allocator.free(content);
const old_config = try std.zon.parse.fromSlice(
MigrationConfig,
allocator,
content,
null,
.{},
);
defer std.zon.parse.free(allocator, old_config);
var ignore_list: [][]const u8 = &[_][]const u8{};
if (old_config.ignore_list) |v| {
ignore_list = try allocator.alloc([]const u8, v.len);
var i: usize = 0;
for (v) |item| {
ignore_list[i] = try allocator.dupe(u8, item);
i += 1;
}
}
var new_config = Config{
.repository = if (old_config.repository) |v| v else "",
.source = if (old_config.source) |v| v else "",
.target = if (old_config.target) |v|
v
else if (old_config.destination) |v|
v
else
"",
.logging = if (old_config.logging) |v| v else false,
.ignore_list = ignore_list,
};
try new_config.write(allocator, config_path);
for (ignore_list) |item| {
allocator.free(item);
}
allocator.free(ignore_list);
}
custom migration config type:
fn MigrationType(comptime T: type) type {
const config_fields = std.meta.fields(T);
// deprecated config fields
const deprecated_fields = [_]std.builtin.Type.StructField{
.{
.name = "destination",
.type = ?[]const u8,
.default_value_ptr = &@as(?[]const u8, null),
.is_comptime = false,
.alignment = @alignOf(?[]const u8),
},
};
var fields: [
config_fields.len +
deprecated_fields.len
]std.builtin.Type.StructField =
undefined;
inline for (config_fields, 0..) |field, i| {
const OptionalType = @Type(.{
.optional = .{
.child = field.type,
},
});
const default_value = @as(OptionalType, null);
fields[i] = .{
.name = field.name,
.type = OptionalType,
.default_value_ptr = &default_value,
.is_comptime = false,
.alignment = @alignOf(OptionalType),
};
}
inline for (deprecated_fields, 0..) |field, i| {
fields[config_fields.len + i] = field;
}
return @Type(.{
.@"struct" = .{
.layout = .auto,
.fields = &fields,
.decls = &.{},
.is_tuple = false,
},
});
}
I thought I messed up custom config type, but everything works just fine and values from destination are migrated to target as expected. Everything seems to be fine and final config looks as it should but:
Updating config
Config updated
SYNC STARTED
Source is /home/charlie/test1/
Target is /home/charlie/test2/
TOTAL: 120
UPDATED: 0
TEMPLATES: 0
RENDERS: 107
BINARIES: 13
ERRORS: 0
DONE
error(gpa): memory address 0x37cdc8200000 leaked:
/home/charlie/Downloads/zig-x86_64-freebsd-0.15.1/lib/std/array_list.zig:692:52: 0x10da2dd in toOwnedSlice (std.zig)
const new_memory = try gpa.alignedAlloc(T, alignment, self.items.len);
^
/home/charlie/Downloads/zig-x86_64-freebsd-0.15.1/lib/std/zon/parse.zig:1082:52: 0x1704bb6 in failUnexpected__anon_65322 (std.zig)
.msg = try buf.toOwnedSlice(gpa),
^
/home/charlie/Downloads/zig-x86_64-freebsd-0.15.1/lib/std/zon/parse.zig:767:43: 0x14232d2 in parseStruct__anon_65144 (std.zig)
return self.failUnexpected(T, "field", node, i, name);
^
/home/charlie/Downloads/zig-x86_64-freebsd-0.15.1/lib/std/zon/parse.zig:458:40: 0x142ca01 in parseExprInner__anon_58310 (std.zig)
return self.parseStruct(T, node),
^
/home/charlie/Downloads/zig-x86_64-freebsd-0.15.1/lib/std/zon/parse.zig:417:35: 0x13a56fc in parseExpr__anon_49556 (std.zig)
return self.parseExprInner(T, node) catch |err| switch (err) {
^
/home/charlie/Downloads/zig-x86_64-freebsd-0.15.1/lib/std/zon/parse.zig:333:28: 0x13353af in fromZoirNode__anon_39410 (std.zig)
return parser.parseExpr(T, node);
Tried to configure the parser but ignoring unknown fields does not help.
Rest of the code dfs/src/config.zig at config · charlesrocket/dfs · GitHub
Zig 0.15.1/0.15.2