From 619f4d3e2c75b9117b8f0f13b3bbf499426a7113 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Wed, 5 Aug 2026 23:28:01 +0000 Subject: [PATCH] JSObject::getPropertySlot: reload the structure before the prototype step getOwnNonIndexPropertySlot can reify a static-table lazy property, which transitions the object, and still return false when the PropertyCallback builder throws (setUpStaticFunctionSlot reports the slot as not found so the caller sees the exception). The inlined prototype-chain loop then called storedPrototype(object) on the structure it read before the call, tripping ASSERT(object->structure() == this) in StructureInlinesLight.h on asserts builds. The megamorphic slow paths in JITOperations.cpp already reload the structure after getOwnNonIndexPropertySlot for exactly this reason, and getNonIndexPropertySlot uses getPrototypeDirect() which re-reads it. Do the same in the one caller that reused the stale pointer. Seen by Fuzzilli in Bun: first read of a lazy Bun property whose builder runs JS that touches another lazy property on the same object and then throws, e.g. reading Bun.sql with a hooked Error superclass. --- Source/JavaScriptCore/runtime/JSObject.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 77464eb2cce2f..d8601f54d2942 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -1281,6 +1281,10 @@ ALWAYS_INLINE bool JSObject::getPropertySlot(JSGlobalObject* globalObject, Prope } // FIXME: This doesn't look like it's following the specification: // https://bugs.webkit.org/show_bug.cgi?id=172572 + // Reload the structure: reifying a static lazy property above can transition + // the object and still miss (its PropertyCallback builder threw), like the + // megamorphic slow paths in JITOperations.cpp do. + structure = object->structureID().decode(); JSValue prototype = structure->storedPrototype(object); if (!prototype.isObject()) break;