[INFER] Don't collect type objects with unknown properties for mutable __proto__, bug 639126.

This commit is contained in:
Brian Hackett 2011-03-05 21:23:02 -08:00
parent eef5f2fae3
commit 37ffca03a9
5 changed files with 50 additions and 6 deletions

View File

@ -0,0 +1,4 @@
Array.__proto__ = Array.__proto__;
gc();
Array["name" + ""];
Array();

View File

@ -935,7 +935,7 @@ TypeConstraintCall::newType(JSContext *cx, TypeSet *source, jstype type)
TypeFunction *function = NULL;
if (TypeIsObject(type)) {
TypeObject *object = (TypeObject*) type;
if (object->isFunction) {
if (object->isFunction && !object->unknownProperties) {
function = (TypeFunction*) object;
} else {
/* Unknown return value for calls on non-function objects. */
@ -1302,6 +1302,14 @@ TypeSet::getKnownTypeTag(JSContext *cx, JSScript *script)
static inline ObjectKind
CombineObjectKind(TypeObject *object, ObjectKind kind)
{
/*
* All type objects with unknown properties are considered interchangeable
* with one another, as they can be freely exchanged in type sets to handle
* objects whose __proto__ has been changed.
*/
if (object->unknownProperties)
return OBJECT_UNKNOWN;
ObjectKind nkind;
if (object->isFunction)
nkind = object->asFunction()->script ? OBJECT_SCRIPTED_FUNCTION : OBJECT_NATIVE_FUNCTION;
@ -3796,8 +3804,22 @@ CondenseSweepTypeSet(JSContext *cx, TypeCompartment *compartment,
for (unsigned i = 0; i < objectCapacity; i++) {
TypeObject *object = types->objectSet[i];
if (object && !object->marked) {
/*
* If the object has unknown properties, instead of removing it
* replace it with the compartment's empty type object. This is
* needed to handle mutable __proto__ --- the type object in
* the set may no longer be used but there could be a JSObject
* which originally had the type and was changed to a different
* type object with unknown properties.
*/
if (object->unknownProperties) {
types->objectSet[i] = cx->getTypeEmpty();
if (!types->objectSet[i])
compartment->setPendingNukeTypes(cx);
} else {
types->objectSet[i] = NULL;
}
removed = true;
types->objectSet[i] = NULL;
}
}
if (removed) {
@ -3819,8 +3841,14 @@ CondenseSweepTypeSet(JSContext *cx, TypeCompartment *compartment,
} else if (types->objectCount == 1) {
TypeObject *object = (TypeObject*) types->objectSet;
if (!object->marked) {
types->objectSet = NULL;
types->objectCount = 0;
if (object->unknownProperties) {
types->objectSet = (TypeObject**) cx->getTypeEmpty();
if (!types->objectSet)
compartment->setPendingNukeTypes(cx);
} else {
types->objectSet = NULL;
types->objectCount = 0;
}
}
}

View File

@ -383,7 +383,13 @@ struct TypeObject
*/
TypeObject *next;
/* Whether all the properties of this object are unknown. */
/*
* Whether all the properties of this object are unknown. When this object
* appears in a type set, nothing can be assumed about its contents, including
* whether the .proto field is correct. This is needed to handle mutable
* __proto__, which requires us to unify all type objects with unknown
* properties in type sets (see SetProto).
*/
bool unknownProperties;
/* Whether all objects this represents are dense arrays. */

View File

@ -316,8 +316,11 @@ JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Valu
inline js::types::TypeObject *
JSContext::getTypeEmpty()
{
if (!compartment->types.typeEmpty)
if (!compartment->types.typeEmpty) {
compartment->types.typeEmpty = newTypeObject("Empty", NULL);
if (compartment->types.typeEmpty)
compartment->types.typeEmpty->unknownProperties = true;
}
return compartment->types.typeEmpty;
}

View File

@ -4288,6 +4288,9 @@ SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles)
/*
* Setting __proto__ on an object that has escaped and may be referenced by
* other heap objects can only be done if the properties of both objects are unknown.
* Type sets containing this object will contain the original type but not the
* new type of the object, which is OK since we treat objects in type sets with
* unknown properties as interchangeable.
*/
if (!cx->markTypeObjectUnknownProperties(obj->getType()) ||
!cx->markTypeObjectUnknownProperties(type)) {