Skip to content

Commit 29f27fb

Browse files
committed
fix(mem): free preserve_chars before overwriting on repeated -P/--preserve
The C FFI CLI (strdup x3) and the Zig CLI (allocator.dupe x4) overwrote opts.preserve_chars on each -P/--preserve without freeing the prior allocation, leaking when the flag was given more than once. Free the previous value first (free(NULL)/optional-unwrap are safe). Lua/Node are GC'd, so N/A there.
1 parent b61f186 commit 29f27fb

2 files changed

Lines changed: 7 additions & 0 deletions

File tree

src/printable_binary_ffi_main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ static options_t parse_options(int argc, char *argv[]) {
227227
if (strncmp(name, "format=", 7) == 0) {
228228
parse_format_spec(&opts, name + 7);
229229
} else if (strncmp(name, "preserve=", 9) == 0) {
230+
free(opts.preserve_chars);
230231
opts.preserve_chars = strdup(name + 9);
231232
} else if (strcmp(name, "decode") == 0) {
232233
opts.decode_mode = true;
@@ -340,9 +341,11 @@ static options_t parse_options(int argc, char *argv[]) {
340341
break;
341342
case 'P':
342343
if (arg[j + 1]) {
344+
free(opts.preserve_chars);
343345
opts.preserve_chars = strdup(arg + j + 1);
344346
j = strlen(arg) - 1;
345347
} else if (i + 1 < argc) {
348+
free(opts.preserve_chars);
346349
opts.preserve_chars = strdup(argv[++i]);
347350
} else {
348351
fprintf(stderr, "Error: -P requires a value\n");

src/zig/main.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,11 +220,13 @@ fn parseArgs(allocator: std.mem.Allocator, args: []const []const u8) !Options {
220220
opts.format_group = parsed.group;
221221
opts.format_groups_per_line = parsed.per_line;
222222
} else if (std.mem.startsWith(u8, name, "preserve=")) {
223+
if (opts.preserve_chars) |old| allocator.free(old);
223224
opts.preserve_chars = try allocator.dupe(u8, name[9..]);
224225
} else if (std.mem.eql(u8, name, "preserve")) {
225226
// --preserve CHARS (space-separated)
226227
if (i + 1 < args.len) {
227228
i += 1;
229+
if (opts.preserve_chars) |old| allocator.free(old);
228230
opts.preserve_chars = try allocator.dupe(u8, args[i]);
229231
} else {
230232
return error.MissingValue;
@@ -327,10 +329,12 @@ fn parseArgs(allocator: std.mem.Allocator, args: []const []const u8) !Options {
327329
},
328330
'P' => {
329331
if (j + 1 < arg.len) {
332+
if (opts.preserve_chars) |old| allocator.free(old);
330333
opts.preserve_chars = try allocator.dupe(u8, arg[j + 1 ..]);
331334
break;
332335
} else if (i + 1 < args.len) {
333336
i += 1;
337+
if (opts.preserve_chars) |old| allocator.free(old);
334338
opts.preserve_chars = try allocator.dupe(u8, args[i]);
335339
} else {
336340
return error.MissingValue;

0 commit comments

Comments
 (0)