open
https://gitlab.synchro.net/main/sbbs/-/issues/1185
## Summary
`sbbsctrl.exe` (Windows, 32-bit, hosting all servers in-process) crashed with an
access violation deep in the SpiderMonkey GC/mark path while a **web SSJS request** was executing JavaScript. The web server (and with it the whole BBS) went offline until manually restarted ~8 hours later.
This is **not** the previously-fixed `js_rtpool` NULL-deref
(`fab8b1f1d`, which faulted in `JS_TriggerAllOperationCallbacks` after an OOM) —
different signature, and there was **no OOM** preceding this one.
## Environment
- Host: vert.synchro.net, Windows 11, **32-bit** `sbbsctrl.exe` (all servers
in one process), SpiderMonkey 1.8.5 (`mozjs185-1.0.dll`).
- Synchronet 3.22a, `master`, Debug build (the build carrying the web/terminal
teardown fix — the crash is unrelated to that change; see "Ruled out").
- Crash: 2026-07-14 ~02:13 local. WER minidump
`sbbsctrl.exe.233816.dmp` (preserved off-box).
## Fault
Access violation (read), `c0000005`, in `mozjs185-1.0.dll` GC/mark region (nearest exports: between `JS_CompareValues+…` and `js_CloseIterator`).
```
sbbs!js_execfile+0x1099
mozjs185_1_0!JS_ExecuteScript+0x22
mozjs185_1_0!<gc/mark, private> <-- faults here
```
Faulting instructions:
```
mov ecx, dword ptr [eax+0CCh] ; eax = 0x16d45a5a (a JS object), loads ecx
mov eax, dword ptr [ecx+18h] ; ecx = 0xdf6807ff (WILD pointer) -> AV read @ 0xdf680817
```
So a GC object carried a **garbage pointer (`0xdf6807ff`) in a field at `+0xCC`**, and the collector dereferenced it. Classic
use-after-free / heap-corruption manifestation: the GC is the *victim* tripping over corruption some earlier code left behind.
## Context at crash
- Under an ongoing distributed L7 flood; server busy but **not** saturated
(~54 concurrent clients, not at the 100 MaxClients cap).
- Dozens of concurrent HTTPS `<Guest>` sessions all executing the **same
script**, `001-forum.ssjs` (the message-board viewer:
`GET /?page=001-forum.ssjs&sub=…&thread=…`), at the moment of the fault. - **No OOM** — zero "creating JavaScript runtime" / "Failed to create new
context" / "out of memory" errors in the hour before the crash.
Leading (unproven) hypothesis: a GC/rooting or JS-runtime-lifetime issue exposed by **high-concurrency SSJS execution** of the forum page — consistent with "many threads in the same script, no OOM," but not established.
## Ruled out
- **Not** the connection-teardown fix (that touches `close_session_socket` /
node teardown; this is request *execution*, a separate path).
- **Not** the `js_rtpool` OOM NULL-deref (`fab8b1f1d`) — different faulting
function, and no OOM here.
## RCA status: characterized, not root-caused
The WER dump is a **minidump** (flags: `DataSegs | ProcessThreadData`, ~29 MB of
a ~655 MB process) — it captured thread stacks but **not the JS heap**. Every heap address (the corrupted object, the wild pointer's target) reads `????????`, so the offending object can't be inspected. And the code that *wrote* the bad pointer had already returned before the GC tripped over it, so it is on no captured stack. This dump therefore cannot yield the culprit.
## Next steps to get a real RCA
1. **Full-memory dumps now enabled** for `sbbsctrl.exe` via WER `LocalDumps`
(`DumpType=2`) — the next occurrence will include the JS heap, letting us
identify the corrupted object's JSClass (→ which binding/script).
2. If a full dump still isn't conclusive (likely, since the writer has
returned): reproduce under a **page-heap** (`gflags /p /enable sbbsctrl.exe`)
or ASAN build, which traps the bad *write* at the moment it happens.
3. Open question worth recording: how much of this class the **SpiderMonkey 128
migration** is expected to eliminate vs. needing a fix in our bindings /
concurrency handling now.
Filing to track; will attach a full-memory dump if/when the crash recurs.
— *Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)