https://gitlab.synchro.net/main/sbbs/-/issues/1143#note_9007
**Read-only reproduction attempt on a clean copy of the mail base — symptom does not reproduce on FreeBSD**
I took a verbatim copy of your `data/mail.*` files (`mail.shd` + `mail.sdt` + `mail.sda` + `mail.sha` + `mail.sid` + `mail.ini`, all read-only) and ran `probe_to_ext.js` against them on a FreeBSD 14.3 build of the same tree, across three binaries to bracket the fix range.
## Method
- `probe_to_ext_path.js` — byte-identical to the attached `probe_to_ext.js` except the `fetch()` body calls `new MsgBase("/tmp/issue1143/mailbase/mail", true /* is_path */)` instead of `new MsgBase("mail")`, so the test runs against the copy without touching the BBS config.
- All three binaries built from this tree with `gmake` (Clang 19, FreeBSD amd64, debug). Same `JAVASCRIPT_OPTIONS=0x810` (`sbbsdefs.h:69`) — JIT off, as discussed above.
- Same heap size (`-m256000000`), same cwd, same script invocation.
| binary | js_msgbase.cpp content | result | |--------|------------------------|--------|
| `666ff71ce` (current HEAD) | eager-resolve `JSID_VOID` + `defer_listing` | total=7482, cold_undef=213, primed_NULL=213, **BUG mismatches=0**, defined-but-wrong=0 |
| `666ff71ce^` (= ca448cb8b) | eager `JS_DefineProperty("number")` only | total=7482, cold_undef=213, primed_NULL=213, **BUG mismatches=0**, defined-but-wrong=0 |
| `ca448cb8b^` (pre-both fixes) | vanilla lazy resolve, no eager defines | total=7482, cold_undef=213, primed_NULL=213, **BUG mismatches=0**, defined-but-wrong=0 |
`cold_undef == primed_NULL == 213` exactly in every run — i.e. the only `undefined` reads are the genuinely-NULL `to_ext` fields. There are zero spurious undefineds. Both fixes are no-ops on this build, because there is no symptom to fix.
(Investigation lives on local branch `investigate-1143`: two `git revert` commits on top of master.)
## What this tells us
The defect is **not** in the SM-1.8.5 source we share, and it's not in the lazy resolve hook as currently written. On Clang/FreeBSD/debug against Rob's actual mail base, the interpreter PropertyCache behaves exactly the way my earlier source-trace said it should: a fresh-shape header looking up `to_ext` misses the cache (kshape diverges) and goes through resolve normally.
That means whatever is misfiring is environment-specific to Rob's setup in some way the source tree alone doesn't capture. I don't know what platform Rob ran his probe on — his commits are authored `(on Windows 11)` but the `-c /sbbs/ctrl` / `-m<bytes>` invocation style in discussion-4 reads as Unix shell, so I shouldn't assume. Candidates worth narrowing:
- Compiler / build flags. MSVC vs Clang vs gcc codegen on `PropertyCache::test()` / `fill()` / `js_GetPropertyHelperWithShapeInline` — a vectorization, alias-analysis, or signed-overflow assumption that diverges between compilers can land us in a different cache fast path.
- mozjs build configuration. Whether `JS_METHODJIT` / `JS_MONOIC` / `JS_POLYIC` / `DEBUG` / `JS_GC_ZEAL` are compiled into the libjs Rob is linking matches what I tested here. The `3rdp/` mozjs is built once per host config; differences in that build are not visible in the sbbs source tree.
- Release vs Debug. I tested debug here. If Rob's symptom is on a Release build, optimizer-enabled cache paths could behave differently.
- Compile-time options I missed.
## Open questions for Rob
To narrow this further:
1. **What platform / build did your probe runs in discussion-4 actually use?** Specifically: which jsexec binary (path), built on which host, Debug or Release, and which `3rdp/.../mozjs/lib` it links against. I assumed Windows because of the commit author tag and now realize I shouldn't have.
2. What are the build flags on the mozjs library you're linking? `JS_METHODJIT`, `JS_MONOIC`, `JS_POLYIC`, `DEBUG`, `JS_GC_ZEAL`, etc. — anything that affects the cache fast-path is in scope.
3. Does the symptom reproduce on a *fresh local copy* of `data/mail.*` opened by path (`new MsgBase(path, true)`), or only against the live SMB-mounted one? If only against the live one, the SMB-share layer is back in scope as the differentiator.
I can also build a FreeBSD release-optimized jsexec and rerun the probe here, if that helps rule optimization level in or out without waiting on you.
## Side audit (separable from this issue)
While walking `js_get_all_msg_headers` I noticed the read-path smblib errors are swallowed silently:
- `smb_locksmbhdr` failure at `js_msgbase.cpp:1932-1937` → `return JS_TRUE` with the empty `retobj` already set as RVAL. Script sees an empty msgbase, not an error.
- `smb_getmsghdr` failure mid-loop at `js_msgbase.cpp:2010-2015` → silent loop break, partial array returned, script can't tell it was truncated.
- `JS_NewObject` failure mid-loop at `js_msgbase.cpp:2017-2023` → same silent truncation.
- Same pattern in `js_get_msg_header` at lines 1771, 1777, 1783 (single-msg path).
`priv->smb_result` is set in each case, so `mb.last_error` does reflect the failure — but no caller of `get_all_msg_headers` in the tree (msglist.js, hotline.js, the probes themselves) checks `last_error` after the call. Given that Rob's setup accesses the mail base over an SMB-mounted share where locking races have bitten before, this is worth tightening on its own merits.
Doesn't explain the `to_ext`-undef symptom (failed-to-read headers are skipped from the array, not partially populated), but it's a real defect class adjacent to #1144 — file as its own ticket either way.
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)