Fix RELEASE_ASSERT in LazyProperty when node:util fails to load during Bun.inspect#29235
Fix RELEASE_ASSERT in LazyProperty when node:util fails to load during Bun.inspect#29235
Conversation
…g Bun.inspect The m_utilInspectFunction and m_utilInspectStylizeColorFunction lazy property initializers would return early via RETURN_IF_EXCEPTION without calling init.set() when loading node:util threw an exception. LazyProperty requires init.set() to be called to clear the lazyTag bit, otherwise RELEASE_ASSERT(!(m_pointer & lazyTag)) fires in callFunc. On exception, set the property to null via setMayBeNull so the tag bits are cleared and the exception propagates to the caller. Callers of utilInspectFunction() are updated to handle the null case gracefully.
|
Updated 10:18 PM PT - Apr 12th, 2026
❌ @robobun, your commit b857ee6 has some failures in 🧪 To try this PR locally: bunx bun-pr 29235That installs a local version of the PR into your bun-29235 --bun |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughAdjusts custom-inspect callsite to pass Changes
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
|
Re: duplicate detection of #28336 — that PR replaces That assumption doesn't hold: This PR instead sets the property to |
- m_utilInspectStylizeColorFunction: check for null return from utilInspectFunction() (no exception when previously nulled) before appending to args - JSBroadcastChannel: move utilInspect null check before options.toObject() so the fallback string is returned when options is undefined - Bun__REPL__formatValue: add RETURN_IF_EXCEPTION after utilInspectFunction() - Add test for the colors:false-then-colors:true ordering - Add 30s timeouts for slow debug+ASAN subprocess startup
There was a problem hiding this comment.
LGTM — all previously raised issues have been addressed.
Extended reasoning...
Overview
This PR fixes a RELEASE_ASSERT crash triggered when Bun.inspect() is called on an object with a nodejs.util.inspect.custom symbol while node:util fails to load (e.g., due to a poisoned Array.prototype.forEach). Changes touch UtilInspect.cpp, ZigGlobalObject.cpp, bindings.cpp, JSBroadcastChannel.cpp, and a new test file.
Security risks
None. This is purely a crash-recovery fix for an edge case where module loading fails; it converts a hard abort into a catchable JS exception.
Level of scrutiny
The fix is targeted and follows a well-established pattern in the codebase (JSX509Certificate's use of setMayBeNull). The core changes are mechanical: replace empty RETURN_IF_EXCEPTION bodies with setMayBeNull calls, add null guards at call sites, and reorder an existing guard to before a toObject() call that could throw on undefined.
Prior review outcome
All four issues raised in prior inline comments were resolved: the missing null-check for utilInspectFunction() in the stylize-color initializer, the missing RETURN_IF_EXCEPTION in Bun__REPL__formatValue, the misordered null check in JSBroadcastChannel, and the explicit test timeouts. The author also gave a clear, valid justification for not asserting stderr (ASAN startup output on debug builds).
Other factors
Two new tests cover the repro scenario across repeated calls and with BroadcastChannel. The second test's expected output (nocolors caught followed by colors ok) correctly reflects the lazy-init-once semantics: after the first failure clears both lazy properties to null, subsequent calls return gracefully with undefined as the inspect function argument.
|
CI status: all 59 jobs that ran passed (including |
Fuzzilli found a crash with fingerprint
LazyPropertyInlines.h(104):Root cause
Bun.inspect()on an object with a[Symbol.for('nodejs.util.inspect.custom')]method triggers lazy initialization ofm_utilInspectFunction, which loadsnode:util. If evaluatingnode:util(or one of its transitive dependencies) throws, the initializer returned early viaRETURN_IF_EXCEPTION(scope, )without callinginit.set().LazyProperty::callFuncrequires the lazy tag to be cleared before it returns, so it hit theRELEASE_ASSERT.The same issue existed in
m_utilInspectStylizeColorFunction.Repro
Before: aborts with
RELEASE_ASSERT.After: throws a catchable JS error.
Fix
On exception, call
init.property.setMayBeNull(init.vm, init.owner, nullptr)so the tag bits are cleared and the exception propagates to the caller. This matches the pattern already used inJSX509Certificate. Callers ofutilInspectFunction()/utilInspectStylizeColorFunction()are updated to handlenullptron subsequent calls after a failed load (passjsUndefined()to the custom inspect function, and fall back to a plain string forBroadcastChannel's custom inspect).