Title: [284757] trunk
Revision
284757
Author
[email protected]
Date
2021-10-24 08:32:25 -0700 (Sun, 24 Oct 2021)

Log Message

InternalFunction::createSubclassStructure() should use prototype's global object
https://bugs.webkit.org/show_bug.cgi?id=231874

Patch by Alexey Shvayka <[email protected]> on 2021-10-24
Reviewed by Yusuke Suzuki.

JSTests:

* stress/internal-function-subclass-structure-realm.js: Added.

Source/_javascript_Core:

In case NewTarget has a cross-realm "prototype" object, even though the instance
structure is created with correct [[Prototype]], it's m_globalObject is of NewTarget's
realm instead of prototype's.

That is observable in various places, including when calling CustomAccessor, fast paths
for iteration protocol / collection constructors, isHavingABadTime() handling etc.

This patch fixes structure's global object to be correct: per spec [1], we fallback to
NewTarget's realm only if "prototype" is a primitive.

[1]: https://tc39.es/ecma262/#sec-getprototypefromconstructor (step 3.b)

* runtime/InternalFunction.cpp:
(JSC::InternalFunction::createSubclassStructure):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (284756 => 284757)


--- trunk/JSTests/ChangeLog	2021-10-24 15:18:35 UTC (rev 284756)
+++ trunk/JSTests/ChangeLog	2021-10-24 15:32:25 UTC (rev 284757)
@@ -1,3 +1,12 @@
+2021-10-24  Alexey Shvayka  <[email protected]>
+
+        InternalFunction::createSubclassStructure() should use prototype's global object
+        https://bugs.webkit.org/show_bug.cgi?id=231874
+
+        Reviewed by Yusuke Suzuki.
+
+        * stress/internal-function-subclass-structure-realm.js: Added.
+
 2021-10-23  Phillip Mates  <[email protected]>
 
         update test262

Added: trunk/JSTests/stress/internal-function-subclass-structure-realm.js (0 => 284757)


--- trunk/JSTests/stress/internal-function-subclass-structure-realm.js	                        (rev 0)
+++ trunk/JSTests/stress/internal-function-subclass-structure-realm.js	2021-10-24 15:32:25 UTC (rev 284757)
@@ -0,0 +1,21 @@
+"use strict";
+const r1 = createGlobalObject();
+const r2 = createGlobalObject();
+const r3 = createGlobalObject();
+
+(function() {
+    for (const key of ["Array", "Date", "Error", "Function", "Int8Array", "Map", "Number", "Object", "RegExp", "WeakSet"]) {
+        for (let i = 0; i < 1000; i++) {
+            for (const newTarget of [
+                r2[key].bind(),
+                new r2.Function,
+                new r2.Proxy(new r2.Function, {}),
+            ]) {
+                Object.defineProperty(newTarget, "prototype", { value: new r3.Object });
+                const instance = Reflect.construct(r1[key], [], newTarget);
+                if ($vm.globalObjectForObject(instance) !== r3)
+                    throw new Error(`Structure of ${key} instance has incorrect global object!`);
+            }
+        }
+    }
+})();

Modified: trunk/Source/_javascript_Core/ChangeLog (284756 => 284757)


--- trunk/Source/_javascript_Core/ChangeLog	2021-10-24 15:18:35 UTC (rev 284756)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-10-24 15:32:25 UTC (rev 284757)
@@ -1,3 +1,25 @@
+2021-10-24  Alexey Shvayka  <[email protected]>
+
+        InternalFunction::createSubclassStructure() should use prototype's global object
+        https://bugs.webkit.org/show_bug.cgi?id=231874
+
+        Reviewed by Yusuke Suzuki.
+
+        In case NewTarget has a cross-realm "prototype" object, even though the instance
+        structure is created with correct [[Prototype]], it's m_globalObject is of NewTarget's
+        realm instead of prototype's.
+
+        That is observable in various places, including when calling CustomAccessor, fast paths
+        for iteration protocol / collection constructors, isHavingABadTime() handling etc.
+
+        This patch fixes structure's global object to be correct: per spec [1], we fallback to
+        NewTarget's realm only if "prototype" is a primitive.
+
+        [1]: https://tc39.es/ecma262/#sec-getprototypefromconstructor (step 3.b)
+
+        * runtime/InternalFunction.cpp:
+        (JSC::InternalFunction::createSubclassStructure):
+
 2021-10-22  Justin Michaud  <[email protected]>
 
         Fix nits from 232019

Modified: trunk/Source/_javascript_Core/runtime/InternalFunction.cpp (284756 => 284757)


--- trunk/Source/_javascript_Core/runtime/InternalFunction.cpp	2021-10-24 15:18:35 UTC (rev 284756)
+++ trunk/Source/_javascript_Core/runtime/InternalFunction.cpp	2021-10-24 15:32:25 UTC (rev 284757)
@@ -142,12 +142,11 @@
 
     // newTarget may be an InternalFunction if we were called from Reflect.construct.
     JSFunction* targetFunction = jsDynamicCast<JSFunction*>(vm, newTarget);
-    JSGlobalObject* baseGlobalObject = baseClass->globalObject();
 
     if (LIKELY(targetFunction)) {
         FunctionRareData* rareData = targetFunction->ensureRareData(vm);
         Structure* structure = rareData->internalFunctionAllocationStructure();
-        if (LIKELY(structure && structure->classInfo() == baseClass->classInfo() && structure->globalObject() == baseGlobalObject))
+        if (LIKELY(structure && structure->classInfo() == baseClass->classInfo() && structure->globalObject() == baseClass->globalObject()))
             return structure;
 
         // Note, Reflect.construct might cause the profile to churn but we don't care.
@@ -154,7 +153,7 @@
         JSValue prototypeValue = targetFunction->get(globalObject, vm.propertyNames->prototype);
         RETURN_IF_EXCEPTION(scope, nullptr);
         if (JSObject* prototype = jsDynamicCast<JSObject*>(vm, prototypeValue))
-            return rareData->createInternalFunctionAllocationStructureFromBase(vm, baseGlobalObject, prototype, baseClass);
+            return rareData->createInternalFunctionAllocationStructureFromBase(vm, prototype->globalObject(vm), prototype, baseClass);
     } else {
         JSValue prototypeValue = newTarget->get(globalObject, vm.propertyNames->prototype);
         RETURN_IF_EXCEPTION(scope, nullptr);
@@ -161,7 +160,7 @@
         if (JSObject* prototype = jsDynamicCast<JSObject*>(vm, prototypeValue)) {
             // This only happens if someone Reflect.constructs our builtin constructor with another builtin constructor as the new.target.
             // Thus, we don't care about the cost of looking up the structure from our hash table every time.
-            return vm.structureCache.emptyStructureForPrototypeFromBaseStructure(baseGlobalObject, prototype, baseClass);
+            return vm.structureCache.emptyStructureForPrototypeFromBaseStructure(prototype->globalObject(vm), prototype, baseClass);
         }
     }
     
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to