From 3d30b1ed248f0173b098c9d7b819c34dab07ac84 Mon Sep 17 00:00:00 2001 From: reugenio Date: Thu, 25 Dec 2025 22:52:51 +0100 Subject: [PATCH] fix(config): Free previous string value before setting new one - Added freeString checks before dupeString in setFieldByDef - Prevents memory leak during hot-reload when same field is set multiple times - Works with Config structs that implement freeString method --- src/zcatconfig.zig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/zcatconfig.zig b/src/zcatconfig.zig index 6d2a746..c537b49 100644 --- a/src/zcatconfig.zig +++ b/src/zcatconfig.zig @@ -390,6 +390,13 @@ pub fn Engine(comptime variables: []const ConfigVariable, comptime ConfigType: t // IMPORTANTE: Duplicar el string porque 'value' apunta a 'content' // que se libera con defer al final de load() if (@hasDecl(ConfigType, "dupeString")) { + // Liberar string anterior si existe (evitar leak en hot-reload) + if (@hasDecl(ConfigType, "freeString")) { + const old_val = @field(config.*, v.name); + if (old_val.len > 0) { + _ = config.freeString(old_val); + } + } // Config tiene método para trackear strings alocados @field(config.*, v.name) = config.dupeString(value) catch value; } else if (@hasField(ConfigType, "allocator")) { @@ -409,6 +416,13 @@ pub fn Engine(comptime variables: []const ConfigVariable, comptime ConfigType: t // String que representa un color (nombre de paleta) // También necesita duplicarse if (@hasDecl(ConfigType, "dupeString")) { + // Liberar string anterior si existe (evitar leak en hot-reload) + if (@hasDecl(ConfigType, "freeString")) { + const old_val = @field(config.*, v.name); + if (old_val.len > 0) { + _ = config.freeString(old_val); + } + } @field(config.*, v.name) = config.dupeString(value) catch value; } else if (@hasField(ConfigType, "allocator")) { @field(config.*, v.name) = config.allocator.dupe(u8, value) catch value;