Fix crash in Bun.inspect when Proxy prototype trap throws - #29965
Conversation
When inspecting an object whose prototype chain contains a Proxy, exceptions from the Proxy's get trap could leak past the getPropertySlot() check (because the exception was only cleared when getPropertySlot returned true). Additionally, if a Proxy's getPrototypeOf trap threw, getPrototype() returned an empty JSValue and calling .getObject() on it dereferenced a null JSCell. Both paths now clear the pending exception and handle the empty return, matching the existing handling in the fast path above.
|
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 (2)
WalkthroughThe changes refactor property enumeration and prototype-chain traversal logic to explicitly handle property resolution state and clear exceptions from proxy traps, with corresponding test additions covering edge cases in prototype access and property lookup. Changes
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Review rate limit: 1/5 review remaining, refill in 44 minutes and 17 seconds. Comment |
|
Found 3 issues this PR may fix:
🤖 Generated with Claude Code |
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
What does this PR do?
Fixes a null pointer dereference in
JSC__JSValue__forEachPropertyImplthat crashed the process when inspecting /console.log-ing an object whose prototype chain contains a Proxy with a throwing trap.Repro
or
Root cause
Two related issues in the slow-path prototype walk of
forEachPropertyImpl:getPropertySlotwithInternalMethodType::Getgoes through a Proxy and a getter on the target throws,getPropertySlotreturnsfalse. The code then didcontinuebefore theCLEAR_IF_EXCEPTIONcall, leaking the exception into subsequent iterations.iterating = iterating->getPrototype(globalObject).getObject()calls.getObject()unconditionally on the result. IfgetPrototypethrows (either directly via a ProxygetPrototypeOftrap, or because an exception was already pending from (1)), it returns an emptyJSValue, and.getObject()on an emptyJSValuecalls a method on a nullJSCell*.The fast path directly above already handled both of these cases; this brings the slow path to parity.
How did you verify your code works?
test/js/bun/util/inspect.test.js.bun bd test test/js/bun/util/inspect.test.js— 75 pass, 0 fail.Found by Fuzzilli (fingerprint
3b2a3201fb5f71c3).