ErrorInstance: pass the instance to the GC-time onComputeErrorInfo callback - #509
ErrorInstance: pass the instance to the GC-time onComputeErrorInfo callback#509robobun wants to merge 1 commit into
Conversation
…llback reconcileWeakReferencesAtGCEnd materializes the stack string as soon as one frame's callee or CodeBlock is unmarked. The embedder callback that formats the string received the frames but not the ErrorInstance, so it could not read the error's name and message. Bun formats the stack V8-style with a "name: message" header, and that header came out as a bare "Error". Add the ErrorInstance as a JSObject* parameter, in the same position as in ErrorInfoFunctionJSValue.
|
Warning Review limit reached
On-demand reviews are free for the next 27 days. After that, they cost $0.25 per reviewed file. Or wait 28 minutes for your next included review. View limit detailsLimit details: You’ve used all 5 included reviews currently available. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
There was a problem hiding this comment.
LGTM — adds the ErrorInstance* parameter to ErrorInfoFunction and threads this through the single call site.
What was reviewed:
- Confirmed
ErrorInfoFunctionhas exactly one caller in this repo (ErrorInstance::computeErrorInfo), and it was updated to match the new signature. - New parameter position mirrors the existing
ErrorInfoFunctionJSValuetypedef; the added comment correctly documents the GC-end-phase no-allocation constraint. thisis safe to pass here — the reconcile loop only runs on marked cells, andcomputeErrorInfo's other caller (materializeErrorInfoIfNeeded) is a normal member call on a live instance.
Extended reasoning...
Overview
This PR adds a JSC::JSObject* errorInstance parameter to the ErrorInfoFunction typedef in VM.h (a Bun-specific hook under USE_BUN_JSC_ADDITIONS) and updates its single call site in ErrorInstance::computeErrorInfo to pass this. It also adds a two-line comment above the typedef documenting that the callback runs during the GC end phase and must not allocate on the GC heap or run JS.
Security risks
None. This is a purely additive signature change to an embedder callback typedef. No user-facing input handling, auth, or memory-safety-relevant logic is touched. The pointer being passed (this) is the marked ErrorInstance whose method is executing — it cannot be null or dangling.
Level of scrutiny
Low. The change is mechanical: one parameter added to a WTF::Function typedef, one argument added at the sole call site, plus a documentation comment. I grepped the tree for ErrorInfoFunction and onComputeErrorInfo — the only in-repo usages are the typedef, the VM accessors/member, and the single call in ErrorInstance.cpp, all of which are consistent after this change. The actual callback implementation lives in the Bun repo, and the PR description notes a matching Bun-side change; any signature mismatch there would be a compile error, not a runtime bug.
Other factors
- The new parameter is placed in the same position as in the sibling typedef
ErrorInfoFunctionJSValue, keeping the two hooks symmetric. computeErrorInfohas two callers:reconcileWeakReferencesAtGCEnd(only iterates marked cells, sothisis live) andmaterializeErrorInfoIfNeeded(ordinary method call on a live object). Passingthisis safe in both.- The added comment on the typedef is accurate and useful — it makes the no-GC-allocation constraint explicit for the embedder.
- No prior reviews or outstanding comments on the PR.
Preview Builds
|
|
Closing as a duplicate of #302, which fixes the same bug for oven-sh/bun#34398 and already went through review. This PR took the approach that review rejected (reading the instance inside the GC end phase). |
Problem
ErrorInstance::reconcileWeakReferencesAtGCEndmaterializes the stack string as soon as one frame's callee or CodeBlock is unmarked. It callsvm.onComputeErrorInfo()with the frames, but not with theErrorInstance.error.stackV8-style, with aname: messagefirst line. Without the instance it cannot readnameormessage, so every error that goes through this path gets a bareErrorheader. An async function body runs in a per-call closure, so this hits every error thrown from an async function once a GC runs before the first.stackread (Async-thrown Error loses its message from error.stack when GC runs before first .stack access bun#34398).Fix
JSC::JSObject* errorInstancetoErrorInfoFunction, in the same position as inErrorInfoFunctionJSValue, and passthisfromErrorInstance::computeErrorInfo.