From 7039f566bb5db987707a9a4fd8637575b595ffaa Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 23 Mar 2026 16:08:25 -0700 Subject: [PATCH] vt: move free_alloc to dedicated allocator.zig Extract the inline free_alloc function from main.zig into a new allocator.zig module in the C API layer. The function is renamed to alloc_free in main.zig (and free in allocator.zig) for consistency with the other C API naming conventions. Add tests for null pointer, allocated memory, and null allocator fallback. --- src/lib_vt.zig | 2 +- src/terminal/c/allocator.zig | 36 ++++++++++++++++++++++++++++++++++++ src/terminal/c/main.zig | 17 +++-------------- 3 files changed, 40 insertions(+), 15 deletions(-) create mode 100644 src/terminal/c/allocator.zig diff --git a/src/lib_vt.zig b/src/lib_vt.zig index 2816befae..0452d5e31 100644 --- a/src/lib_vt.zig +++ b/src/lib_vt.zig @@ -218,7 +218,7 @@ comptime { @export(&c.grid_ref_graphemes, .{ .name = "ghostty_grid_ref_graphemes" }); @export(&c.grid_ref_style, .{ .name = "ghostty_grid_ref_style" }); @export(&c.build_info, .{ .name = "ghostty_build_info" }); - @export(&c.free_alloc, .{ .name = "ghostty_free" }); + @export(&c.alloc_free, .{ .name = "ghostty_free" }); // On Wasm we need to export our allocator convenience functions. if (builtin.target.cpu.arch.isWasm()) { diff --git a/src/terminal/c/allocator.zig b/src/terminal/c/allocator.zig new file mode 100644 index 000000000..b16cf5d25 --- /dev/null +++ b/src/terminal/c/allocator.zig @@ -0,0 +1,36 @@ +const std = @import("std"); +const testing = std.testing; +const lib_alloc = @import("../../lib/allocator.zig"); +const CAllocator = lib_alloc.Allocator; + +/// Free memory that was allocated by a libghostty-vt function. +/// +/// This must be used to free buffers returned by functions like +/// `format_alloc`. Pass the same allocator (or NULL for the default) +/// that was used for the allocation. +pub fn free( + alloc_: ?*const CAllocator, + ptr: ?[*]u8, + len: usize, +) callconv(.c) void { + const mem = ptr orelse return; + const alloc = lib_alloc.default(alloc_); + alloc.free(mem[0..len]); +} + +test "free null pointer" { + free(&lib_alloc.test_allocator, null, 0); +} + +test "free allocated memory" { + const alloc = lib_alloc.default(&lib_alloc.test_allocator); + const mem = try alloc.alloc(u8, 16); + free(&lib_alloc.test_allocator, mem.ptr, mem.len); +} + +test "free with null allocator" { + // null allocator falls back to the default (test allocator in tests) + const alloc = lib_alloc.default(null); + const mem = try alloc.alloc(u8, 8); + free(null, mem.ptr, mem.len); +} diff --git a/src/terminal/c/main.zig b/src/terminal/c/main.zig index b1a87e452..8e6674049 100644 --- a/src/terminal/c/main.zig +++ b/src/terminal/c/main.zig @@ -2,6 +2,7 @@ const lib_alloc = @import("../../lib/allocator.zig"); const CAllocator = lib_alloc.Allocator; const buildpkg = @import("build_info.zig"); +pub const allocator = @import("allocator.zig"); pub const cell = @import("cell.zig"); pub const color = @import("color.zig"); pub const focus = @import("focus.zig"); @@ -115,20 +116,7 @@ pub const mouse_encoder_encode = mouse_encode.encode; pub const paste_is_safe = paste.is_safe; -/// Free memory that was allocated by a libghostty-vt function. -/// -/// This must be used to free buffers returned by functions like -/// `format_alloc`. Pass the same allocator (or NULL for the default) -/// that was used for the allocation. -pub fn free_alloc( - alloc_: ?*const CAllocator, - ptr: ?[*]u8, - len: usize, -) callconv(.c) void { - const mem = ptr orelse return; - const alloc = lib_alloc.default(alloc_); - alloc.free(mem[0..len]); -} +pub const alloc_free = allocator.free; pub const size_report_encode = size_report.encode; @@ -157,6 +145,7 @@ pub const grid_ref_graphemes = grid_ref.grid_ref_graphemes; pub const grid_ref_style = grid_ref.grid_ref_style; test { + _ = allocator; _ = buildpkg; _ = cell; _ = color;