- 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);
}
}