···11+package libghostty
22+33+// Memory allocation helpers wrapping the upstream ghostty_alloc() and
44+// ghostty_free() functions from allocator.h.
55+//
66+// These replace direct C.malloc/C.free calls so that all memory is
77+// allocated and freed through libghostty's allocator. This is critical
88+// on platforms where the library's internal allocator differs from the
99+// consumer's C runtime (e.g. Windows, where Zig's libc and MSVC's CRT
1010+// maintain separate heaps).
1111+1212+/*
1313+#include <ghostty/vt.h>
1414+*/
1515+import "C"
1616+1717+import "unsafe"
1818+1919+// Alloc allocates len bytes through the default libghostty allocator
2020+// (NULL allocator). Returns a pointer to the allocated memory or nil
2121+// if the allocation failed.
2222+//
2323+// The returned memory must be freed with Free using the same length.
2424+// C: ghostty_alloc
2525+func Alloc(len uintptr) unsafe.Pointer {
2626+ return unsafe.Pointer(C.ghostty_alloc(nil, C.size_t(len)))
2727+}
2828+2929+// Free frees memory allocated by Alloc (or returned by a libghostty
3030+// function) using the default libghostty allocator (NULL allocator).
3131+// The len must match the original allocation size. It is safe to pass
3232+// nil.
3333+// C: ghostty_free
3434+func Free(ptr unsafe.Pointer, len uintptr) {
3535+ C.ghostty_free(nil, (*C.uint8_t)(ptr), C.size_t(len))
3636+}
+11-13
get_multi.go
···33// Shared helpers for the get_multi pattern used by multiple types.
44// These helpers solve the cgo pointer-passing rule: Go cannot pass
55// a Go-allocated void** (array of pointers to Go memory) directly
66-// to C. Instead, we allocate the void** array in C heap memory,
77-// copy the Go pointer values in, call the C function, then free.
88-99-/*
1010-#include <stdlib.h>
1111-*/
1212-import "C"
66+// to C. Instead, we allocate the void** array via libghostty's
77+// allocator, copy the Go pointer values in, call the C function,
88+// then free.
1391410import "unsafe"
15111616-// cValuesArray allocates a C-heap array of void* pointers, copies the
1717-// Go unsafe.Pointer values into it, and returns the C array pointer.
1818-// The caller must free the returned pointer with C.free when done.
1919-func cValuesArray(values []unsafe.Pointer) *unsafe.Pointer {
1212+// cValuesArray allocates a C-heap array of void* pointers via the
1313+// libghostty allocator, copies the Go unsafe.Pointer values into it,
1414+// and returns the C array pointer and allocation size. The caller must
1515+// free the returned pointer with Free(ptr, size) when done.
1616+func cValuesArray(values []unsafe.Pointer) (*unsafe.Pointer, uintptr) {
2017 n := len(values)
2121- cArr := (*unsafe.Pointer)(C.malloc(C.size_t(n) * C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)))))
1818+ size := uintptr(n) * unsafe.Sizeof(unsafe.Pointer(nil))
1919+ cArr := (*unsafe.Pointer)(Alloc(size))
2220 dst := unsafe.Slice(cArr, n)
2321 copy(dst, values)
2424- return cArr
2222+ return cArr, size
2523}
···88// recovers the Terminal and dispatches to the user-supplied Go effect handler.
991010/*
1111-#include <stdlib.h>
1211#include <ghostty/vt.h>
13121413// Forward declarations for the Go trampolines so we can take their
···214213 return C.bool(true)
215214}
216215217217-// effectString copies data into C memory, updates effectBuf, and
218218-// returns a GhosttyString pointing to it. The previous effectBuf
219219-// is freed. Returns a zero-length GhosttyString if data is empty.
216216+// effectString copies data into C memory allocated via the libghostty
217217+// allocator, updates effectBuf/effectBufLen, and returns a
218218+// GhosttyString pointing to it. The previous effectBuf is freed.
219219+// Returns a zero-length GhosttyString if data is empty.
220220func (t *Terminal) effectString(data []byte) C.GhosttyString {
221221 if t.effectBuf != nil {
222222- C.free(t.effectBuf)
222222+ Free(t.effectBuf, t.effectBufLen)
223223+ t.effectBuf = nil
224224+ t.effectBufLen = 0
223225 }
224226225227 if len(data) == 0 {
226228 return C.GhosttyString{}
227229 }
228230229229- cmem := C.CBytes(data)
231231+ n := uintptr(len(data))
232232+ cmem := Alloc(n)
233233+ copy(unsafe.Slice((*byte)(cmem), n), data)
230234 t.effectBuf = cmem
235235+ t.effectBufLen = n
231236 return C.GhosttyString{
232237 ptr: (*C.uint8_t)(cmem),
233233- len: C.size_t(len(data)),
238238+ len: C.size_t(n),
234239 }
235240}