зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1052139 - Make the [[Prototype]] of all objects on the window object's [[Prototype]] chain be immutable, BUT also disable the code that actually respects immutable-prototype handling. When we want to enable this, it'll then be a one-line change. r=bz
--HG-- extra : rebase_source : e8116d4aed87f03f4e0b91b60c6ccf43f040b31a
This commit is contained in:
Родитель
ddc5b08c61
Коммит
c29c28268a
|
@ -274,13 +274,27 @@ WindowNamedPropertiesHandler::Create(JSContext* aCx,
|
|||
// Note: since the scope polluter proxy lives on the window's prototype
|
||||
// chain, it needs a singleton type to avoid polluting type information
|
||||
// for properties on the window.
|
||||
JS::Rooted<JSObject*> gsp(aCx);
|
||||
js::ProxyOptions options;
|
||||
options.setSingleton(true);
|
||||
options.setClass(&WindowNamedPropertiesClass.mBase);
|
||||
return js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
|
||||
JS::NullHandleValue, aProto,
|
||||
options);
|
||||
|
||||
JS::Rooted<JSObject*> gsp(aCx);
|
||||
gsp = js::NewProxyObject(aCx, WindowNamedPropertiesHandler::getInstance(),
|
||||
JS::NullHandleValue, aProto,
|
||||
options);
|
||||
if (!gsp) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool succeeded;
|
||||
if (!JS_SetImmutablePrototype(aCx, gsp, &succeeded)) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(succeeded,
|
||||
"errors making the [[Prototype]] of the named properties object "
|
||||
"immutable should have been JSAPI failures, not !succeeded");
|
||||
|
||||
return gsp;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -3111,6 +3111,14 @@ CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool succeeded;
|
||||
if (!JS_SetImmutablePrototype(aCx, aGlobal, &succeeded)) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(succeeded,
|
||||
"making a fresh global object's [[Prototype]] immutable can "
|
||||
"internally fail, but it should never be unsuccessful");
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
|
|
|
@ -2946,9 +2946,32 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
else:
|
||||
unforgeableHolderSetup = None
|
||||
|
||||
if (self.descriptor.interface.isOnGlobalProtoChain() and
|
||||
needInterfacePrototypeObject):
|
||||
makeProtoPrototypeImmutable = CGGeneric(fill(
|
||||
"""
|
||||
if (*${protoCache}) {
|
||||
bool succeeded;
|
||||
JS::Handle<JSObject*> prot = GetProtoObjectHandle(aCx, aGlobal);
|
||||
if (!JS_SetImmutablePrototype(aCx, prot, &succeeded)) {
|
||||
$*{failureCode}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(succeeded,
|
||||
"making a fresh prototype object's [[Prototype]] "
|
||||
"immutable can internally fail, but it should "
|
||||
"never be unsuccessful");
|
||||
}
|
||||
""",
|
||||
protoCache=protoCache,
|
||||
failureCode=failureCode))
|
||||
else:
|
||||
makeProtoPrototypeImmutable = None
|
||||
|
||||
return CGList(
|
||||
[getParentProto, CGGeneric(getConstructorProto), initIds,
|
||||
prefCache, CGGeneric(call), defineAliases, unforgeableHolderSetup],
|
||||
prefCache, CGGeneric(call), defineAliases, unforgeableHolderSetup,
|
||||
makeProtoPrototypeImmutable],
|
||||
"\n").define()
|
||||
|
||||
|
||||
|
|
|
@ -1056,6 +1056,13 @@ CreateObjectPrototype(JSContext* cx, JSProtoKey key)
|
|||
if (!objectProto)
|
||||
return nullptr;
|
||||
|
||||
bool succeeded;
|
||||
if (!SetImmutablePrototype(cx, objectProto, &succeeded))
|
||||
return nullptr;
|
||||
MOZ_ASSERT(succeeded,
|
||||
"should have been able to make a fresh Object.prototype's "
|
||||
"[[Prototype]] immutable");
|
||||
|
||||
/*
|
||||
* The default 'new' type of Object.prototype is required by type inference
|
||||
* to have unknown properties, to simplify handling of e.g. heterogenous
|
||||
|
|
|
@ -6320,6 +6320,12 @@ JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length)
|
|||
return funobj;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_SetImmutablePrototype(JSContext *cx, JS::HandleObject obj, bool *succeeded)
|
||||
{
|
||||
return SetImmutablePrototype(cx, obj, succeeded);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::SetAsmJSCacheOps(JSRuntime* rt, const JS::AsmJSCacheOps* ops)
|
||||
{
|
||||
|
|
|
@ -2453,6 +2453,16 @@ JS_FreezeObject(JSContext* cx, JS::Handle<JSObject*> obj);
|
|||
extern JS_PUBLIC_API(bool)
|
||||
JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
|
||||
|
||||
/*
|
||||
* Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt
|
||||
* to modify it will fail. If an error occurs during the attempt, return false
|
||||
* (with a pending exception set, depending upon the nature of the error). If
|
||||
* no error occurs, return true with |*succeeded| set to indicate whether the
|
||||
* attempt successfully made the [[Prototype]] immutable.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args);
|
||||
|
||||
|
|
|
@ -2395,7 +2395,7 @@ JSObject::reportNotExtensible(JSContext* cx, unsigned report)
|
|||
// immutable-prototype behavior is enforced; if it's false, behavior is not
|
||||
// enforced, and immutable-prototype bits stored on objects are completely
|
||||
// ignored.
|
||||
static const bool ImmutablePrototypesEnabled = true;
|
||||
static const bool ImmutablePrototypesEnabled = false;
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
JS_ImmutablePrototypesEnabled()
|
||||
|
@ -2467,6 +2467,15 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object
|
|||
if (!extensible)
|
||||
return result.fail(JSMSG_CANT_SET_PROTO);
|
||||
|
||||
// If this is a global object, resolve the Object class so that its
|
||||
// [[Prototype]] chain is always properly immutable, even in the presence
|
||||
// of lazy standard classes.
|
||||
if (obj->is<GlobalObject>()) {
|
||||
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
||||
if (!GlobalObject::ensureConstructor(cx, global, JSProto_Object))
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* ES6 9.1.2 step 6 forbids generating cyclical prototype chains. But we
|
||||
* have to do this comparison on the observable outer objects, not on the
|
||||
|
@ -3341,6 +3350,7 @@ JSObject::dump()
|
|||
if (obj->hasUncacheableProto()) fprintf(stderr, " has_uncacheable_proto");
|
||||
if (obj->hadElementsAccess()) fprintf(stderr, " had_elements_access");
|
||||
if (obj->wasNewScriptCleared()) fprintf(stderr, " new_script_cleared");
|
||||
if (!obj->hasLazyPrototype() && obj->nonLazyPrototypeIsImmutable()) fprintf(stderr, " immutable_prototype");
|
||||
|
||||
if (obj->isNative()) {
|
||||
NativeObject* nobj = &obj->as<NativeObject>();
|
||||
|
|
|
@ -5760,6 +5760,13 @@ NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
|
|||
return nullptr;
|
||||
#endif
|
||||
|
||||
bool succeeded;
|
||||
if (!JS_SetImmutablePrototype(cx, glob, &succeeded))
|
||||
return nullptr;
|
||||
MOZ_ASSERT(succeeded,
|
||||
"a fresh, unexposed global object is always capable of "
|
||||
"having its [[Prototype]] be immutable");
|
||||
|
||||
#ifdef JS_HAS_CTYPES
|
||||
if (!JS_InitCTypesClass(cx, glob))
|
||||
return nullptr;
|
||||
|
|
|
@ -89,9 +89,6 @@ js::GlobalObject::getTypedObjectModule() const {
|
|||
return v.toObject().as<TypedObjectModuleObject>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* static */ bool
|
||||
GlobalObject::ensureConstructor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey key)
|
||||
{
|
||||
|
|
|
@ -1040,6 +1040,25 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
|
|||
{
|
||||
JSAutoCompartment ac(cx, sandbox);
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sbp =
|
||||
new SandboxPrivate(principal, sandbox);
|
||||
|
||||
// Pass on ownership of sbp to |sandbox|.
|
||||
JS_SetPrivate(sandbox, sbp.forget().take());
|
||||
|
||||
{
|
||||
// Don't try to mirror standard class properties, if we're using a
|
||||
// mirroring sandbox. (This is meaningless for non-mirroring
|
||||
// sandboxes.)
|
||||
AutoSkipPropertyMirroring askip(CompartmentPrivate::Get(sandbox));
|
||||
|
||||
// Resolve standard classes so that |Object.prototype| is
|
||||
// instantiated before any prototype-splicing below. This is
|
||||
// necessary for both kinds of sandboxes.
|
||||
if (!JS_EnumerateStandardClasses(cx, sandbox))
|
||||
return NS_ERROR_XPC_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (options.proto) {
|
||||
bool ok = JS_WrapObject(cx, &options.proto);
|
||||
if (!ok)
|
||||
|
@ -1074,17 +1093,11 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
ok = JS_SetPrototype(cx, sandbox, options.proto);
|
||||
ok = JS_SplicePrototype(cx, sandbox, options.proto);
|
||||
if (!ok)
|
||||
return NS_ERROR_XPC_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sbp =
|
||||
new SandboxPrivate(principal, sandbox);
|
||||
|
||||
// Pass on ownership of sbp to |sandbox|.
|
||||
JS_SetPrivate(sandbox, sbp.forget().take());
|
||||
|
||||
// Don't try to mirror the properties that are set below.
|
||||
AutoSkipPropertyMirroring askip(CompartmentPrivate::Get(sandbox));
|
||||
|
||||
|
@ -1114,10 +1127,6 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
|
|||
// every global.
|
||||
if (!dom::PromiseBinding::GetConstructorObject(cx, sandbox))
|
||||
return NS_ERROR_XPC_UNEXPECTED;
|
||||
|
||||
// Resolve standard classes eagerly to avoid triggering mirroring hooks for them.
|
||||
if (options.writeToGlobalPrototype && !JS_EnumerateStandardClasses(cx, sandbox))
|
||||
return NS_ERROR_XPC_UNEXPECTED;
|
||||
}
|
||||
|
||||
// We handle the case where the context isn't in a compartment for the
|
||||
|
|
Загрузка…
Ссылка в новой задаче