diff --git a/src/jsc/bindings/bindings.cpp b/src/jsc/bindings/bindings.cpp index 22ac38063376..c8df5aa8f44d 100644 --- a/src/jsc/bindings/bindings.cpp +++ b/src/jsc/bindings/bindings.cpp @@ -5369,10 +5369,11 @@ static void JSC__JSValue__forEachPropertyImpl(JSC::EncodedJSValue JSValue0, JSC: } JSC::PropertySlot slot(object, PropertySlot::InternalMethodType::Get); - if (!object->getPropertySlot(globalObject, property, slot)) - continue; + bool hasProperty = object->getPropertySlot(globalObject, property, slot); // Ignore exceptions from "Get" proxy traps. CLEAR_IF_EXCEPTION(scope); + if (!hasProperty) + continue; if ((slot.attributes() & PropertyAttribute::DontEnum) != 0) { if (property == propertyNames->underscoreProto @@ -5444,7 +5445,10 @@ static void JSC__JSValue__forEachPropertyImpl(JSC::EncodedJSValue JSValue0, JSC: break; if (iterating == globalObject) break; - iterating = iterating->getPrototype(globalObject).getObject(); + JSValue proto = iterating->getPrototype(globalObject); + // Ignore exceptions from Proxy "getPrototypeOf" trap. + CLEAR_IF_EXCEPTION(scope); + iterating = proto ? proto.getObject() : nullptr; } } diff --git a/test/js/bun/util/inspect.test.js b/test/js/bun/util/inspect.test.js index 32a70af30183..aeee77fd535f 100644 --- a/test/js/bun/util/inspect.test.js +++ b/test/js/bun/util/inspect.test.js @@ -772,3 +772,36 @@ it("CustomEvent", () => { }" `); }); + +describe("Proxy in prototype chain", () => { + it("does not crash when a getter throws through a Proxy prototype", () => { + const proto = {}; + Object.defineProperty(proto, "thrower", { + get() { + throw new Error("getter threw"); + }, + enumerable: true, + configurable: true, + }); + proto.foo = function () {}; + proto.bar = function () {}; + + const obj = Object.create(proto); + Object.setPrototypeOf(obj, new Proxy(proto, {})); + expect(Bun.inspect(obj)).toContain("foo"); + }); + + it("does not crash when a Proxy getPrototypeOf trap throws", () => { + const proto = { foo: 1, bar: 2 }; + const obj = {}; + Object.setPrototypeOf( + obj, + new Proxy(proto, { + getPrototypeOf() { + throw new Error("trap threw"); + }, + }), + ); + expect(Bun.inspect(obj)).toContain("foo"); + }); +});