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:
Jeff Walden 2014-11-28 02:58:23 -05:00
Родитель ddc5b08c61
Коммит c29c28268a
10 изменённых файлов: 111 добавлений и 20 удалений

Просмотреть файл

@ -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