_ulog_open heap-boxes a booked mmap plus its wh128 sidecar and hands the raw pointer to JS as a *Number*. A Number owns nothing: drop it and the mapping, its fd and the sidecar leak for the life of the process — GC cannot reclaim what it was never told about. The reverse cast is unguarded too, so any JS number reaches raw memory. Found while measuring JAB-033; today's two callers happen to close correctly, so this is a LATENT defect of the binding contract, not a live leak.
Read-only inspection of ///jab#8335085b on 2026-08-05, out of the JAB-033 measurement pass; the mmap side of the same question is ABC-020.
ulog.hpp:251 — the box is typedef struct { u8bp data; wh128bp idx; } jabc_ulog: a booked file mapping AND a sidecar index, both real OS resources.ulog.hpp:274-278 — calloc the box, ULOGOpen into it, return JSValueMakeNumber(ctx, (double)(size_t)h). No JSClassRef, no private data, no finalizer callback.io.cpp:632, where a mapping goes out as a typed array WITH a JABCMapFree deallocator — there GC is at least an idempotent backstop. The ULOG handle has none at all.ulog.hpp:281-286 — JABCulogHandle runs JSValueToNumber and casts the result straight to jabc_ulog*, guarded only by d <= 0. A stale, wrong or already-closed number is dereferenced: use-after-free or a wild pointer.ulog.hpp:250 says close "frees the box (idempotent — nulls handle)", but nothing nulls the JS-side Number, so a double close passes the SAME value in twice.be/shared/ulog.js:169-188 closes on a catch arm, :205-220 in a finally. Correctness rests entirely on every future caller repeating that.The handle OWNS its resources: dropping it on the floor is reclaimable, and a bogus value never reaches raw memory.
_ulog_open with the handle dropped, no close — count /proc/self/maps lines and fds; unbounded today, must plateau._ulog_append — must refuse in plain words, never dereference._ulog_close stays THE deterministic release; GC is only the backstop, never the plan.io.cpp:632) — no third handle convention invented for ULOG..c files only; errors in plain words, never bare codes._ulog_open/_append/_close CALL SHAPE that be/shared/ulog.js writes through without landing the JS side in the same pass — a half-migration breaks every put.///jab/ from the main tree per work; stop and report on any clone failure, no improvised fallback._ulog_append/_count/_rowTime/_close)jab/test/ulog_book.js included