Bug 1529757 - Add JS::GetFunctionRealm and use it in GetPrototypeFromConstructor. r=jorendorff,bzbarsky

Differential Revision: https://phabricator.services.mozilla.com/D27867

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jan de Mooij 2019-04-26 07:46:04 +00:00
parent 6b925edfbe
commit dcb885cbb7
5 changed files with 112 additions and 13 deletions

View File

@ -116,6 +116,16 @@ extern JS_PUBLIC_API JSObject* GetRealmErrorPrototype(JSContext* cx);
extern JS_PUBLIC_API JSObject* GetRealmIteratorPrototype(JSContext* cx);
// Implements https://tc39.github.io/ecma262/#sec-getfunctionrealm
// 7.3.22 GetFunctionRealm ( obj )
//
// WARNING: may return a realm in a different compartment!
//
// Will throw an exception and return nullptr when a security wrapper or revoked
// proxy is encountered.
extern JS_PUBLIC_API Realm* GetFunctionRealm(JSContext* cx,
HandleObject objArg);
} // namespace JS
#endif // js_Realm_h

View File

@ -355,18 +355,12 @@ skip script test262/language/expressions/prefix-increment/S11.4.4_A5_T5.js
skip script test262/language/expressions/prefix-increment/S11.4.4_A6_T1.js
skip script test262/language/expressions/prefix-increment/S11.4.4_A6_T2.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1288457
skip script test262/built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=944846
skip script test262/built-ins/Number/prototype/toExponential/return-values.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1225839
skip script test262/built-ins/Function/internals/Call/class-ctor-realm.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1288457
skip script test262/built-ins/Function/internals/Construct/base-ctor-revoked-proxy-realm.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1297179
skip script test262/built-ins/Proxy/apply/arguments-realm.js
skip script test262/built-ins/Proxy/apply/trap-is-not-callable-realm.js
@ -399,9 +393,7 @@ skip script test262/built-ins/Function/internals/Construct/derived-return-val-re
skip script test262/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1317416
skip script test262/language/expressions/super/realm.js
skip script test262/built-ins/GeneratorFunction/proto-from-ctor-realm.js
skip script test262/built-ins/Function/prototype/bind/proto-from-ctor-realm.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1317395
skip script test262/built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js

View File

@ -0,0 +1,45 @@
var g1 = newGlobal();
var g1Fun = g1.eval("function Fun() {}; Fun");
// Bound function => cross-realm function.
var bound1 = Function.prototype.bind.call(g1Fun);
assertEq(Object.getPrototypeOf(new bound1()), g1.Fun.prototype);
// Proxy => cross-realm function.
var proxy1 = new Proxy(g1Fun, {
get: function() {} // Ensure "prototype" is |undefined|.
});
assertEq(Object.getPrototypeOf(new proxy1()), g1.Object.prototype);
// Proxy => bound function => cross-realm function.
var proxy2 = new Proxy(bound1, {
get: function() {}
});
assertEq(Object.getPrototypeOf(new proxy2()), g1.Object.prototype);
// Revoked proxy => cross-realm function.
var r1 = Proxy.revocable(g1Fun, {
get: function(t, name) {
assertEq(name, "prototype");
r1.revoke();
}
});
assertThrowsInstanceOf(() => new r1.proxy(), g1.TypeError);
// Bound function => proxy => bound function => cross-realm function.
var bound2 = Function.prototype.bind.call(proxy2);
assertEq(Object.getPrototypeOf(new bound2()), g1.Object.prototype);
// Proxy => cross-realm revoked proxy => cross-realm function.
var r2 = Proxy.revocable(g1Fun, {
get: function(t, name) {
assertEq(name, "prototype");
r2.revoke();
}
});
var g2 = newGlobal();
var proxy3 = new g2.Proxy(r2.proxy, {});
assertThrowsInstanceOf(() => new proxy3(), g1.TypeError);
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -1183,16 +1183,18 @@ bool js::GetPrototypeFromConstructor(JSContext* cx, HandleObject newTarget,
proto.set(nullptr);
} else {
// Step 4.a: Let realm be ? GetFunctionRealm(constructor);
JSObject* unwrappedConstructor = CheckedUnwrapStatic(newTarget);
if (!unwrappedConstructor) {
ReportAccessDenied(cx);
Realm* realm = JS::GetFunctionRealm(cx, newTarget);
if (!realm) {
return false;
}
// Step 4.b: Set proto to realm's intrinsic object named
// intrinsicDefaultProto.
{
AutoRealm ar(cx, unwrappedConstructor);
mozilla::Maybe<AutoRealm> ar;
if (cx->realm() != realm) {
ar.emplace(cx, realm->maybeGlobal());
}
proto.set(GlobalObject::getOrCreatePrototype(cx, intrinsicDefaultProto));
}
if (!proto) {
@ -1209,7 +1211,7 @@ JSObject* js::CreateThisForFunction(JSContext* cx, HandleFunction callee,
HandleObject newTarget,
NewObjectKind newKind) {
RootedObject proto(cx);
if (!GetPrototypeFromConstructor(cx, newTarget, JSProto_Null, &proto)) {
if (!GetPrototypeFromConstructor(cx, newTarget, JSProto_Object, &proto)) {
return nullptr;
}

View File

@ -1037,3 +1037,53 @@ JS_PUBLIC_API JSObject* JS::GetRealmIteratorPrototype(JSContext* cx) {
CHECK_THREAD(cx);
return GlobalObject::getOrCreateIteratorPrototype(cx, cx->global());
}
JS_PUBLIC_API Realm* JS::GetFunctionRealm(JSContext* cx, HandleObject objArg) {
// https://tc39.github.io/ecma262/#sec-getfunctionrealm
// 7.3.22 GetFunctionRealm ( obj )
CHECK_THREAD(cx);
cx->check(objArg);
RootedObject obj(cx, objArg);
while (true) {
obj = CheckedUnwrapStatic(obj);
if (!obj) {
ReportAccessDenied(cx);
return nullptr;
}
// Step 1.
MOZ_ASSERT(IsCallable(obj));
// Steps 2 and 3. We use a loop instead of recursion to unwrap bound
// functions.
if (obj->is<JSFunction>()) {
JSFunction* fun = &obj->as<JSFunction>();
if (!fun->isBoundFunction()) {
return fun->realm();
}
obj = fun->getBoundFunctionTarget();
continue;
}
// Step 4.
if (IsScriptedProxy(obj)) {
// Steps 4.a-b.
JSObject* proxyTarget = GetProxyTargetObject(obj);
if (!proxyTarget) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_PROXY_REVOKED);
return nullptr;
}
// Step 4.c.
obj = proxyTarget;
continue;
}
// Step 5.
return cx->realm();
}
}