DOMException: inherit from ErrorInstance for [[ErrorData]] and .stack - #32898
DOMException: inherit from ErrorInstance for [[ErrorData]] and .stack#32898robobun wants to merge 12 commits into
Conversation
Walkthrough
ChangesJSDOMException ErrorInstance Refactor
Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
|
Updated 12:35 AM PT - Aug 11th, 2026
✅ @autofix-ci[bot], your commit d8661f2c152a959069d5c6a35ad247f199fd493e passed in 🧪 To try this PR locally: bunx bun-pr 32898That installs a local version of the PR into your bun-32898 --bun |
|
Found 4 issues this PR may fix:
🤖 Generated with Claude Code |
|
Addressed the review in 5ab3d98.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/jsc/bindings/webcore/JSDOMException.cpp`:
- Around line 251-254: The comment in JSDOMException’s stack-handling block is
too long; shorten the explanatory note around the ErrorInstance behavior in
JSDOMException.cpp to three lines max. Keep the essential point about
native-entry stack traces and the `name: message` header, but trim redundant
wording while preserving clarity near the stack formatting logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 621506c1-0816-417b-bb28-8783f550aa3c
📒 Files selected for processing (10)
src/jsc/bindings/BunClientData.cppsrc/jsc/bindings/BunClientData.hsrc/jsc/bindings/FormatStackTraceForJS.cppsrc/jsc/bindings/JSDOMExceptionHandling.cppsrc/jsc/bindings/JSDOMWrapperCache.hsrc/jsc/bindings/ZigException.cppsrc/jsc/bindings/webcore/JSDOMException.cppsrc/jsc/bindings/webcore/JSDOMException.hsrc/jsc/bindings/webcore/SerializedScriptValue.cpptest/js/node/domexception-node.test.js
|
3c600b9 fixes the Root cause was the shape of one test, not the native change. The The test is now split in two:
19/19 pass against the debug build; 12 fail against stock bun, including both rewritten tests (in 11ms, no hang). |
|
Verified this also fixes #37419 (uncaught DOMException printed as a raw property dump of the legacy constants, with a single unremapped stack line). On this branch the issue's repro now prints: which matches Node's position (12:14) and drops the object dump. Added |
WebIDL requires DOMException to carry the [[ErrorData]] internal slot like native Error types. Bun's JSDOMException was a plain JSDOMWrapper, so Error.isError(new DOMException()) returned false, .stack was undefined for user-constructed DOMExceptions and for AbortSignal.abort().reason / structuredClone results, and console.log printed a 25-line legacy-constant dump instead of an error. JSDOMException now derives from JSC::ErrorInstance while keeping its Ref<DOMException> wrapped impl: - createStructure uses ErrorInstanceType so Error.isError / util.types .isNativeError recognize it and error formatting paths trigger. - finishCreation calls ErrorInstance::finishCreation with a null message/cause so a stack trace is captured but name/message/code stay as prototype accessors backed by the wrapped DOMException. - visitChildren keeps the captured stack frames' callee/codeBlock alive; ErrorInstance normally relies on Heap's errorInstanceSpace finalizeUnconditionally sweep which our DOM subspace does not get. - new IsoHeapCellType in JSHeapData so the larger cell destructs its Ref<DOMException> and ErrorInstance state. Callers that previously branched on ErrorInstance before JSDOMException now check the DOMException case first (ZigException name, stack header in FormatStackTraceForJS, SerializedScriptValue terminal dump). The redundant addErrorInfo in createDOMException is removed since the wrapper now captures a Bun-formatted stack on construction.
…ck fallback getNonObservable in ZigException.cpp did a throwable getNonIndexPropertySlot with no exception check and then called slot.getValue(), which invokes native custom getters (slot.isAccessor() only filters JS getter/setter pairs). This was unreachable while fromErrorInstance only saw plain ErrorInstances; now that JSDOMException is an ErrorInstance, the lookup for 'code' lands on the DOMException prototype's custom accessor and the BUN_JSC_validateExceptionChecks lane aborts at JSDOMAttribute.h:83. Add a ThrowScope with RETURN_IF_EXCEPTION (the caller already clears after each call) and restrict the helper to plain data properties, which is what its name promises. Also: ErrorInstance never materializes a .stack from an empty stack trace, which happens when a DOMException is created from a native entry with no JS frames (AbortSignal.timeout fires from a Zig timer). Put the 'name: message' header eagerly in that case so DOMException.stack is always a string. Move the node:util import in the test to module scope.
…tter through the locked API
JSDOMException::visitChildren iterates m_stackTrace from the GC marker under
the cell lock. Every m_stackTrace mutation inside ErrorInstance.cpp already
pairs with that lock (setStackFrames, captureStackTrace, both finishCreation
overloads, computeErrorInfo, materializeErrorInfoIfNeeded), but two Bun
helpers bypassed the locked API through the raw stackTrace() pointer, which
a concurrent reader turns into a use-after-free:
- errorConstructorFuncAppendStackTrace reallocated the destination's vector
and cleared the source's in place. Build the combined vector locally and
install it with setStackFrames on both.
- errorInstanceLazyStackCustomGetter move-constructed the live buffer out of
m_stackTrace before the locked clear. Copy the frames instead; the
setStackFrames(vm, {}) that follows still releases the originals.
Also guard the JSDOMException branch of retrieveErrorMessage against an
empty message so it does not emit a trailing ': ', matching the header
fallback in JSDOMException::finishCreation.
Tests: Error.captureStackTrace on a DOMException (drives the lazy stack
getter end to end) and the empty-message stack header.
test/js/node/domexception-node.test.js hung for 180s on every Windows test lane. The AbortSignal.timeout test added the abort listener and then awaited only the abort event; on Windows that wedges the event loop (bun:test's own per-test timeout timer never fires either), so the file never progressed past it. The same native path (AbortSignal.timeout -> zig timer -> createDOMException -> JSDOMException::finishCreation with an empty frame list) passes on the same Windows binary in test/js/web/abort/abort.test.ts, which reads signal.reason after a ref'd Bun.sleep instead of awaiting the abort event. Use that shape here: drive the loop with a bounded ref'd-sleep poll of signal.aborted and never attach an abort listener, so a missed abort fails loudly instead of hanging. The property that test was actually named for (a header-only .stack when no JS frames are captured) does not need the native timer at all: Error.stackTraceLimit = undefined yields a null trace and Error.stackTraceLimit = 0 an empty one, both synchronously. Cover both arms, plus the empty-message header, in a subprocess so the global stackTraceLimit mutation is isolated. Also shorten an over-long comment in JSDOMException::finishCreation.
3c600b9 to
0b390eb
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
|
Rebased onto current main (1058 commits, including the WebKit bump in #34373 and the Three conflicts, all mechanical: upstream had removed a neighboring subspace in The Re-verified on the rebased build: For the record, the earlier red on build 65757's successor (65887) was a fleet outage: all 33 build jobs expired unstarted, as did a dozen other PRs' builds in the same window. No code from this PR ran in it. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/js/node/domexception-node.test.js`:
- Around line 121-142: Update the combined assertion in the “gets a header-only
stack when no frames are captured” test to include stderr: "" alongside stdout
and exitCode, preserving the existing concurrent stderr drain and expected
stdout output.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8857fb98-cf41-48fb-9730-5816b096dc22
📒 Files selected for processing (10)
src/jsc/bindings/BunClientData.cppsrc/jsc/bindings/BunClientData.hsrc/jsc/bindings/FormatStackTraceForJS.cppsrc/jsc/bindings/JSDOMExceptionHandling.cppsrc/jsc/bindings/JSDOMWrapperCache.hsrc/jsc/bindings/ZigException.cppsrc/jsc/bindings/webcore/JSDOMException.cppsrc/jsc/bindings/webcore/JSDOMException.hsrc/jsc/bindings/webcore/SerializedScriptValue.cpptest/js/node/domexception-node.test.js
…ack after the subclass structure swap test/js/node/test/parallel/test-structuredClone-domexception.js asserts clone.stack === e.stack. That passed vacuously before this branch, when both were undefined; now the clone captured a fresh trace at the structuredClone call site. Node serializes the stack, so DOMExceptionTag now carries it too: the serializer reads .stack through [[Get]] (a throwing prepareStackTrace propagates out of the clone, matching the ErrorInstance branch) and the deserializer installs it on the new wrapper and marks the stack property materialized so the wrapper's own trace never overwrites it. This is a wire format change, so CurrentVersion goes to 15 and the read is gated on it; FirstVersionWithPooledTerminals is unaffected. The header-only .stack fallback used to be put from finishCreation. For `class Sub extends DOMException` that first put allocates a butterfly (a JSNonFinalObject has no inline slots), and setSubclassStructureIfNeeded then swaps to a capacity-0 structure, tripping the setStructure butterfly assertion in debug builds and leaving the release object inconsistent. finishCreation now puts nothing; toJSNewlyCreated (every internal creation path) puts the header after createWrapper, and the constructor builds the wrapper directly so it can put the header and cause only after the swap. Tests: the clone test now double round-trips and asserts stack equality, and the stackTraceLimit subprocess test adds the subclass case.
The .stack header, the uncaught exception report and retrieveErrorMessage read name and message straight off the wrapped impl, so an own data property defined on the instance was ignored, where a plain Error (via sanitizedNameString) and Node honor it. Reading through sanitizedNameString is not an option because DOMException.prototype's attributes are custom accessors, which it skips before falling back to "Error"; that is why these sites special-case DOMException at all. Add displayName/displayMessage on JSDOMException: an own string property wins, otherwise the impl's value. getDirect never runs JS, and a rope falls back rather than resolving, since the stack header can be computed inside a finalizer. All three sites and the header-stack fallback go through it.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/js/node/domexception-node.test.js`:
- Around line 199-214: Update the DOMException subprocess test around Bun.spawn
to pipe stdout, read it concurrently with proc.stderr.text() and proc.exited,
and include the drained stdout in the combined assertion while preserving the
existing stderr content checks and exitCode assertion.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: eaaf9e0a-f065-45e8-bec3-95659086a2b9
📒 Files selected for processing (7)
src/jsc/bindings/FormatStackTraceForJS.cppsrc/jsc/bindings/JSDOMExceptionHandling.cppsrc/jsc/bindings/ZigException.cppsrc/jsc/bindings/webcore/JSDOMException.cppsrc/jsc/bindings/webcore/JSDOMException.hsrc/jsc/bindings/webcore/SerializedScriptValue.cpptest/js/node/domexception-node.test.js
…ames once a stack string is installed
The header-only .stack and retrieveErrorMessage guarded an empty message
but not an empty name, so new DOMException("boom", "") produced ": boom"
where the framed path (formatStackTrace) and Error.prototype.toString give
"boom". Both now go through displayHeader, which applies the same rule as
formatStackTrace.
setStackString left the frames captured at the deserialize site in
m_stackTrace. Nothing would ever format them (the stack property is pinned),
but visitChildren kept rooting their callees and CodeBlocks for as long as
the clone lived, and reading .line on a clone would have materialized the
clone site's position over the copy. Clear the frames through setStackFrames,
which takes the cell lock visitChildren reads under.
There was a problem hiding this comment.
I reviewed this PR and the bug-hunting pass found no new issues; all earlier inline findings have been addressed in e6f7940. Because this swaps JSDOMException's base class to ErrorInstance with a custom IsoSubspace, hand-rolled visitChildren/cellLock coordination for stack-frame rooting, and a SerializedScriptValue wire-format bump, a human look is still worthwhile.
What was reviewed:
- GC safety:
visitChildrenImplroots frames undercellLock(); mutator-side writes go throughsetStackFrameswhich takes the same lock — the move-to-copy inerrorInstanceLazyStackCustomGetterand vector rebuild inerrorConstructorFuncAppendStackTracewere checked for that race. - Ordering:
JSDOMExceptionbranches precedeErrorInstanceat all three sibling sites (SerializedScriptValue, ZigException, retrieveErrorMessage) so structuredClone still emitsDOMExceptionTag. readDOMException's version-gatedreadNullableStringandsetStackString's frame drop after deserialize.- The
BunClientData.hmember declaration order vs the.cppinitializer-list order differ (Bake/NapiHandleScope swapped), but that predates this PR.
Extended reasoning...
Overview
This PR changes JSDOMException from a plain JSDOMWrapper<DOMException> to a JSC::ErrorInstance subclass so DOMExceptions carry [[ErrorData]] and a captured .stack, matching WebIDL §3.14.1 and Node/Chrome/Firefox. It touches 10 files: the class itself (JSDOMException.{h,cpp}), a new IsoHeapCellType in BunClientData, three call sites that branch on ErrorInstance vs JSDOMException (FormatStackTraceForJS, ZigException, JSDOMExceptionHandling), the structured-clone wire format (SerializedScriptValue, version 14→15), a signature widening in JSDOMWrapperCache.h so createWrapper compiles for a non-JSDOMObject wrapper, and ~180 lines of new tests.
Security risks
None identified. No untrusted-input parsing beyond the existing structured-clone reader, whose only new read is a version-gated readNullableString. No auth/crypto/permissions.
Level of scrutiny
High. This is GC-sensitive C++ in the JSC bindings: a base-class swap on a widely-thrown error type, a custom heap subspace that is not part of vm.errorInstanceSpace() (so ErrorInstance::finalizeUnconditionally never sweeps it — the PR compensates with a visitChildrenImpl that roots StackFrame callees/CodeBlocks under cellLock()), and mutator-side stack-frame mutations rewritten to go through setStackFrames for lock safety. The structured-clone wire-format bump is cross-process/worker-visible. Per the repo's review guidance, native memory safety and GC rooting are the most-blocked category and warrant a maintainer's eyes.
Other factors
The PR has been through five rounds of bot review; every inline finding (subclass-structure butterfly assertion, own-property name/message in the stack header, empty-name header joining, deserialize-site frame retention, subprocess test assertions) was confirmed and fixed with tests. The mechgate evidence shows the test file failing on main (ASAN and release) and passing on the PR. Test coverage is thorough — GC stress loop, subclass + stackTraceLimit=0, structuredClone double round-trip with stack equality, AbortSignal.timeout() native-timer path, uncaught-report subprocess. No outstanding unresolved review threads. The complexity of the GC/subspace interaction is the sole reason for deferring rather than approving.
|
Ready for review. CI is green on the current head (d8661f2, build 92035, 190/190), and every review thread is resolved. For whoever picks this up, the parts that deserve the closest look are the ones the description calls out: the base class swap to Verification is in the description; the short version is |
There was a problem hiding this comment.
I reviewed this revision and the bug hunting pass found no issues; every prior inline finding (one-sided cellLock, subclass butterfly assertion, clone stack round-trip, empty-name header, retained clone-site frames) has been addressed with a targeted fix and a test. Because this re-parents JSDOMException onto ErrorInstance with a custom IsoSubspace, hand-written visitChildren, and a SerializedScriptValue wire-format bump, a maintainer sign-off is still worth having.
What was reviewed
visitChildren/cellLock pairing: mutator sites now go throughsetStackFrames(append, clear, lazy getter copies instead of moving) so the concurrent visitor's lock is not one-sided.setStackStringdrops captured frames before pinning, so clones don't root deserialize-site CodeBlocks and.linecan't materialize the clone site over the copy.DOMExceptionTagv15: read is version-gated,dumpIfTerminalchecksJSDOMExceptionbeforeErrorInstanceso the tag is unchanged, and a throwingprepareStackTracepropagates like the Error branch.getNonObservable'sisValue()guard keepsDOMException.prototype.codefrom being invoked and misread as a Nodesystem_code.
Extended reasoning...
Overview
The PR re-parents JSDOMException from JSDOMWrapper<DOMException> to JSC::ErrorInstance so DOMExceptions carry [[ErrorData]] and a captured stack (WebIDL §3.14.1, matching Node/Chrome/Firefox). Ten files touched: the class itself and its header, a new IsoHeapCellType in BunClientData, JSDOMWrapperCache.h widened to JSC::JSObject* so the non-JSDOMObject wrapper still flows through createWrapper/cacheWrapper, SerializedScriptValue bumped to version 15 to carry the stack string, and three call sites (FormatStackTraceForJS, ZigException, JSDOMExceptionHandling) that now branch on JSDOMException before the generic ErrorInstance path. ~180 lines of new tests cover Error.isError, stack capture from every creation path, structuredClone equality, subclassing under stackTraceLimit=0, own-property overrides, util.inspect, and a GC stress loop.
Security risks
None identified. No untrusted-input parsing was added; the serializer's new stack read goes through [[Get]] (which can run prepareStackTrace) with a RETURN_IF_EXCEPTION, mirroring the existing ErrorInstanceTag branch. The deserializer's version gate keeps older payloads valid. getNonObservable's tightening to slot.isValue() is a strict narrowing that stops native getters from being invoked where they previously could be — a hardening, not a widening.
Level of scrutiny
High. Changing a wrapper's base class to ErrorInstance moves it out of vm.errorInstanceSpace()'s finalizeUnconditionally sweep, which is why the PR adds a custom IsoHeapCellType and a hand-written visitChildren that roots StackFrame callees/CodeBlocks under the cellLock. That is exactly the class of change REVIEW.md flags as most-blocked (GC rooting, concurrent visitor races, cell destruction). The PR history shows several real defects found and fixed across iterations — a debug-build butterfly assertion on subclassing, a one-sided cellLock, clone-site frames retained past setStackString — which is evidence the surface is subtle enough to merit a human look even though the current revision reads correct.
Other factors
The design choices here — visitChildren rooting instead of joining errorInstanceSpace's finalize sweep, putting the header stack post-createWrapper at both entry points rather than in finishCreation, widening the wrapper-cache overload set to JSC::JSObject*, and the displayName/displayMessage/displayHeader helper trio — are all reasonable and well-commented, but they are architectural calls a maintainer should ratify. Test coverage is thorough and the PR's own gate confirms the file fails on main and passes on both debug-ASAN and release. No outstanding reviewer comments remain; all inline threads are resolved.
What
DOMExceptionnow derives fromJSC::ErrorInstance, so it carries the[[ErrorData]]internal slot and a captured stack trace like native Error types. WebIDL §3.14.1 specifies this, and Node.js, Chrome and Firefox all do it.Repro
Bun was also internally inconsistent:
AbortController#abort()produced a reason with a.stack(becausecreateDOMExceptioncalledaddErrorInfoafterwards), whileAbortSignal.abort()and user-constructed DOMExceptions had none.Cause
JSDOMExceptionwas a plainJSDOMWrapper<DOMException>withJSType::ObjectType.Error.isErrorcheckstype() == ErrorInstanceType, and nothing on the wrapper-creation path captured a stack.Fix
JSDOMExceptionnow inherits fromJSC::ErrorInstancewhile keeping itsRef<DOMException>wrapped impl and the existing prototype (accessor-basedname/message/code, legacy constants):createStructureusesErrorInstanceType.finishCreationcallsErrorInstance::finishCreationwith a null message/cause so a stack trace is captured butname/messagestay as prototype accessors backed by the wrapped DOMException.visitChildrenkeeps the captured stack frames' callee/codeBlock alive.ErrorInstancenormally relies on Heap'sfinalizeUnconditionallysweep overerrorInstanceSpace, which our DOM subspace is not part of, so without this a lazy.stackread after GC would touch freedCodeBlocks.IsoHeapCellTypeinJSHeapDataso the larger cell destructs itsRef<DOMException>andErrorInstancestate correctly.AbortSignal.timeout()firing from a native timer),ErrorInstancenever materializes astack, sofinishCreationeagerly puts thename: messageheader. A DOMException.stackis now always a string. This improves No stack trace on AbortSignal.timeout error #25182 and Random TimeoutError is sometimes thrown without a stack trace #21900 (no longerundefined/"") but does not close them: Node shows real async frames there and Bun's native timer has none to capture.Callers that branched on
ErrorInstancebeforeJSDOMExceptionnow check the DOMException case first: the.stackheader inFormatStackTraceForJS, theexcept.nameinZigException, and the terminal-dump path inSerializedScriptValue, sostructuredClonekeeps emittingDOMExceptionTaginstead of falling through toErrorInstanceTag. The redundantaddErrorInfoincreateDOMExceptionis removed now that the wrapper captures a Bun-formatted stack on construction; internally-thrown DOMExceptions now have the same stack format as regular errors instead of JSC's nativefoo@fileformat.Latent exception-check bug this exposed
The
BUN_JSC_validateExceptionChecksCI lane caught an unchecked exception ingetNonObservable(ZigException.cpp):getNonObservablecalled a throwablegetNonIndexPropertySlotwith no exception check, and itsslot.isAccessor()guard only filters JS getter/setter pairs, not native custom accessors, soslot.getValue()would invoke them. That was unreachable whilefromErrorInstanceonly saw plainErrorInstances, whose prototypes have no custom accessors. WithJSDOMExceptionnow anErrorInstance, the lookup forcodelands onDOMException.prototype.codeand invokes the getter. Fixed by adding aThrowScopewithRETURN_IF_EXCEPTION(the caller already clears after each call) and restricting the helper to plain data properties, which is what its name promises. This also stops the DOM legacy code (20) from being misread as a nodesystem_code.structuredClone round-trips the stack (wire format version 15)
test/js/node/test/parallel/test-structuredClone-domexception.jsassertsclone.stack === e.stack. That passed vacuously before (bothundefined); once DOMExceptions had stacks, the clone captured a fresh one at thestructuredClonecall site. Node serializes the stack, soDOMExceptionTagnow carries it: the serializer reads it through[[Get]](a throwingprepareStackTracepropagates out of the clone, as in theErrorInstanceTagbranch) and the deserializer installs it on the new wrapper, drops the frames the wrapper captured at the clone site (so GC does not keep rooting them and.linecannot materialize the clone site's position over the copy), and pins the stack property.CurrentVersionis bumped to 15 and the read is gated on it; older payloads still deserialize.Header stack is put after the subclass structure swap
The header-only
.stackfallback (empty trace, e.g.Error.stackTraceLimit = 0or a native timer firing with no JS frames) was put fromfinishCreation.JSDOMExceptionhas no inline slots, so that allocated a butterfly, andsetSubclassStructureIfNeededthen swappedclass Sub extends DOMExceptioninstances onto a capacity-0 structure, tripping thesetStructurebutterfly assertion on debug builds.finishCreationnow puts nothing; thetoJSNewlyCreatedfree function (every internal creation path) puts the header aftercreateWrapper, and the constructor builds the wrapper directly so the swap happens before the header andcauseare put.Verification
test/js/node/domexception-node.test.jsadds coverage forError.isError,.stackcapture (including theAbortSignal.abort(),AbortSignal.timeout(), andstructuredClonepaths), stack equality through twostructuredClones, the subclass +stackTraceLimit = 0case, prototype-accessor invariants,util.inspectformatting, and a GC stress loop over lazy stack materialization.test-structuredClone-domexception.js,structured-clone.test.ts(including its version 13 payload and cross-process cases) andbun-jsc.test.tspass. The existing.failingtest for.stackis un-failed.fetch.test.tsandabort.test.tspass underBUN_JSC_validateExceptionChecks=1.Fixes #15821
Fixes #17877
Fixes #37419
Refs #25182
Refs #21900
[review] gate passed · iteration 1 · 10 files touched
fails on main (without fix)
passes on PR (with fix)
diff hotspot
gate history · 3 passed · 0 rejected · iteration 1
evidence per changed file