BBS: TELESC.NET.BR
Assunto: get_all_msg_headers(): cold *_NULL fields read undefined via dot-acces
De: Deucе
Data: Thu, 21 May 2026 15:46:07 -0700
-----------------------------------------------------------
https://gitlab.synchro.net/main/sbbs/-/issues/1143#note_8991
Zooming out: unchecked JS_* returns is the broader pattern
The lost-exception trap in LAZY_STRING_TRUNCSP_NULL / LAZY_STRING_TRUNCSP is not unique to those macros. It's how nearly the entire JS binding layer is written.
Quick count in this tree:
- js_msgbase.cpp: 28 JS_DefineProperty calls, 0 with a return-value check.
- Whole tree: 683 JS_DefineProperty calls, ~108 inside any if, and most of those are conditional calls (if (cond) JS_DefineProperty(...)) rather than checks on the return. The actual checked-return rate is well under 10%.
- Same pattern for JS_NewObject, JS_NewStringCopyZ, JS_NewArrayObject, JS_SetProperty, JS_DefineElement.
Any allocation failure in any of those sites sets a pending exception on cx and is silently swallowed. The script proceeds with whatever the default observable is (NULL pointers from JS_GetPrivate, undefined from skipped property defines, no-op'd setup). The exception sits on cx until something else trips on it (or jsexec reports it at script termination).
Suggested test to surface the scope
Run the same get_all_msg_headers fetch under a deliberately undersized heap, read several LAZY-resolved fields per header, count undef per field:
```
// Set JavaScriptMaxBytes very low in jsexec.ini first, e.g. 4M or 2M.
var fields = ["to", "from", "subject", "to_ext", "from_ext",
"to_list", "cc_list", "summary", "tags",
"replyto", "from_org", "editor"];
var u = {};
for (var f = 0; f < fields.length; f++) u[fields[f]] = 0;
var caught = null;
try {
for (var n in headers) {
var h = headers[n];
for (var f = 0; f < fields.length; f++) {
if (h[fields[f]] === undefined)
u[fields[f]]++;
}
}
} catch (e) { caught = e; }
for (var f = 0; f < fields.length; f++)
print(fields[f] + ": " + u[fields[f]] + " undef");
print("caught: " + caught);
// flush any pending exception that lingered past loop end
try { var s = ""; for (var i = 0; i < 50000; i++) s += "x"; }
catch (e) { print("post-loop: " + e); }
```
If OOM under a small heap is the trigger, all these fields should show elevated undef counts, not just the *_NULL ones. to/from/subject are routed through LAZY_STRING_TRUNCSP, which has the same swallow-and-undefine behavior on JS_NewStringCopyZ failure. If only to_ext-shaped fields show it, OOM isn't the (whole) story.
I'll file the unchecked-return audit as a separate issue so it doesn't tangle with the property-cache thread in this one. The point of this comment is just: even after #1143 is closed, the same defect pattern is going to keep producing "mysterious" symptoms across the codebase until it gets swept.
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
-----------------------------------------------------------
[Voltar]