jab <projector> leaks the JS context on exit (LSan)
Running a bareword projector through jab — e.g. jab grep:.js#emit — exits under LeakSanitizer with a leak entirely inside libjavascriptcoregtk (fastMalloc/fastRealloc): 640 B direct in 14 objects + 65035 B indirect in 3 objects (17 allocs, 65675 B). Native be grep:.js#emit is clean — the leak is jab-specific: the JS global context (and its JSC heap) is not released on the projector/loop exit path. Same family as JS-054 (error-exit paths leak the whole context) and JS-007 (main script load). The JABC test suite masks this class via the leak:libjavascriptcoregtk suppression; a bareword jab run does not. Method Issues.
be/+beagle/ siblings, ASAN-built jab):
jab grep:.js#emit → ==ERROR: LeakSanitizer: detected memory leaks → SUMMARY: AddressSanitizer: 65675 byte(s) leaked in 17 allocation(s).
libjavascriptcoregtk-4.1.so
WTF::fastRealloc / malloc); no jab frame, so the JS context teardown is the suspect, not a jab-side container.
be grep:.js#emit runs clean (C path, no JSC).jab store.js bare exits rc=1 on14 JSC-internal allocs (the singletons the suppression covers).
jab <projector> (grep:/diff:/etc.) exits with NO LSan leak under ASAN —the JS global context is released on EVERY exit path (success + error).
JSC process-lifetime singletons; if benign, make the suppression/teardown cover the bareword path so a clean jab run is leak-free.
js/main.cpp (+ js/JABC.hpp); build WITH_JS + ASAN per
CLAUDE.md §0/§8. Repro-first (§17): a red→green ASAN check.
a singleton — confirm before declaring benign. Don't blanket-suppress a real leak. ABC/JABC idioms (no pointer arithmetic); funnel exits through one teardown (the JS-054 JABCRunFile-style worker).
projector/loop path DOES reach JSClose→JSGlobalContextRelease (main.cpp:291-298). The leak is benign JSC lazy-init VM singletons — jab --eval 0 (same teardown) is clean; the leak tracks JS features used (RegExp, iterators), does NOT scale with data (ls:. vs ls:beagle same fixed ~12-18 KB), and JSGarbageCollect reclaims nothing. The "65 KB real buffer" suspicion was wrong — process-lifetime VM state, all JSC frames.
js/lsan.supp is applied only by the ctest ENV, so a bareword
end-user jab run has no suppression and reports the singletons. Fix = embed the suppression in the ASAN binary, scoped to JSC frames only.
jab ls:., faster proxy; grep: is verb-independent same class).__lsan_default_suppressions()→leak:libjavascriptcoregtk
(js/main.cpp:11-20, __has_feature(address_sanitizer)-guarded) + repro js/test/run-064.sh + JABCleakLoop (js/CMakeLists.txt:112-113, NOT in the suppression group). RED 18793 B/16 → GREEN exit 0, 16 suppressed.
ctest -R JABC 30/30 incl. JABCleakLoop.leak:libjavascriptcoregtk masks ANY leak whose stack hits JSC
(incl. a hypothetical real JSValue-not-released) — but this only extends the EXISTING js/lsan.supp policy (already used in ctest) to the standalone binary, not a new risk. Flagged for the reviewer.
c9395c2f — landed on beagle trunk: embed __lsan_default_suppressions
(leak:libjavascriptcoregtk, ASAN-only) in js/main.cpp + JABCleakLoop repro (js/test/run-064.sh + js/CMakeLists.txt). Clean 3-way merge with JS-063's js/CMakeLists.txt repoint. JABC 30/30; benign JSC singletons, no real leak. Main tree needs be get to pull c9395c2f.