Beagle SCM
JS-102: ulog handle is a raw pointer in a JS number — double free / UAF / forgeable
Proposed by the 2026-07-07 jab multi-agent review; confirmed by both skeptic verifiers. The ULOG binding is the only one that hands a raw heap pointer across the JS boundary, so script-level misuse becomes native memory corruption.
Context
- JABCulogOpen returns
(double)(size_t)h (jab ulog.hpp:258); JABCulogHandle casts any positive JS number straight back to jabc_ulog* with no validation (ulog.hpp:261-266).
- JABCulogClose does
ULOGClose(...); free(h); (ulog.hpp:337-338) but nothing is nulled JS-side: ulog._close(h) twice is a double free; _append/_count after close is a UAF.
- Any script can crash the runtime with
abc._ulog_count(12345) — a forged number is dereferenced.
Goals
- Repro first: double-close and forged-handle tests expecting a clean JS throw.
- A validated handle table (small index -> jabc_ulog*, tombstoned on close) in the binding; no raw pointers cross the boundary.
Constraints
- Keep the JS API shape (numeric handle) so be/ lib callers don't change.
WIP
TODOs
- 2026-07-10 revision: still OPEN — raw ptr returned as Number (ulog.hpp:258); JABCulogHandle only checks d>0, no validation/tombstone (ulog.hpp:261-266); close does free(h) with nothing nulled JS-side (ulog.hpp:337-338). No handle table.