🤖 AI-generated finding. Produced by the memory-leak-fixer agentic workflow + memory-leak-fixer skill. Empirically confirmed with a local red→green probe against the shipped native library.
Focus area
Area 1 — Wrong owns: flag: a borrowed native pointer wrapped as owned, so disposal over-frees a handle it does not own (double-free / premature destroy).
Retention / ownership path
HarfBuzzApi.hb_buffer_get_unicode_funcs(buffer) returns a borrowed (transfer-none) reference owned by the buffer.
binding/HarfBuzzSharp/Buffer.cs:135 wraps that pointer in a plain owning UnicodeFunctions:
var r = new UnicodeFunctions (HarfBuzzApi.hb_buffer_get_unicode_funcs (Handle));
binding/HarfBuzzSharp/UnicodeFunctions.cs DisposeHandler() unconditionally calls hb_unicode_funcs_destroy(Handle).
- Disposing the wrapper returned by the getter therefore decrements the refcount of a handle the still-alive buffer references → premature destroy / double-free.
Evidence (empirical)
A probe creates a custom UnicodeFunctions with a destroy callback, sets it on a Buffer (buffer takes a ref), reads it back via the getter, disposes the wrapper, then disposes the original — while the buffer is still alive:
| Sources |
Result |
| Current (HEAD) |
destroyed=True → over-freed (a using-buffer variant crashed the host: malloc(): unaligned tcache chunk detected) |
| With fix |
destroyed=False → handle stays alive as long as the buffer does |
Proposed fix (managed C#)
Make UnicodeFunctions track ownership and wrap the borrowed getter result owns: false, so Dispose is a no-op for it (matching HarfBuzz's transfer-none contract). No public signature change (ABI-safe).
Scope note
- Type: framework bug (a double-free footgun the binding creates), not just a usage footgun.
- Proof: empirically proven red→green locally against the shipped
HarfBuzzSharp.NativeAssets.Linux native library.
- ABI: internal-only change; no public API modified.
Fix PR opened alongside this issue.
Generated by Fixer - Memory Leak · ● 37.7M · ◷
Focus area
Area 1 — Wrong
owns:flag: a borrowed native pointer wrapped as owned, so disposal over-frees a handle it does not own (double-free / premature destroy).Retention / ownership path
HarfBuzzApi.hb_buffer_get_unicode_funcs(buffer)returns a borrowed (transfer-none) reference owned by the buffer.binding/HarfBuzzSharp/Buffer.cs:135wraps that pointer in a plain owningUnicodeFunctions:binding/HarfBuzzSharp/UnicodeFunctions.csDisposeHandler()unconditionally callshb_unicode_funcs_destroy(Handle).Evidence (empirical)
A probe creates a custom
UnicodeFunctionswith a destroy callback, sets it on aBuffer(buffer takes a ref), reads it back via the getter, disposes the wrapper, then disposes the original — while the buffer is still alive:destroyed=True→ over-freed (ausing-buffer variant crashed the host:malloc(): unaligned tcache chunk detected)destroyed=False→ handle stays alive as long as the buffer doesProposed fix (managed C#)
Make
UnicodeFunctionstrack ownership and wrap the borrowed getter resultowns: false, soDisposeis a no-op for it (matching HarfBuzz's transfer-none contract). No public signature change (ABI-safe).Scope note
HarfBuzzSharp.NativeAssets.Linuxnative library.Fix PR opened alongside this issue.