Fix violation of function prototyping due to cloned function object implementation (300079, r=mrbkap; expecting r=igor after the fact, want to get this in for widespread testing tomorrow).

This commit is contained in:
brendan@mozilla.org 2007-06-19 23:37:15 -07:00
Родитель 810be3dd6c
Коммит b98558a7cd
3 изменённых файлов: 92 добавлений и 38 удалений

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

@ -1267,11 +1267,7 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
js_InitDateClass(cx, obj); js_InitDateClass(cx, obj);
} }
#define ATOM_OFFSET(name) offsetof(JSAtomState,name##Atom) #define CLASP(name) ((JSClass *)&js_##name##Class)
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
#define CLASP(name) (JSClass *)&js_##name##Class
#define EAGER_ATOM(name) ATOM_OFFSET(name), NULL #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
#define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
#define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name) #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
@ -1640,11 +1636,7 @@ JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
return js_SetIdArrayLength(cx, ida, i); return js_SetIdArrayLength(cx, ida, i);
} }
#undef ATOM_OFFSET
#undef CLASS_ATOM_OFFSET
#undef OFFSET_TO_ATOM
#undef CLASP #undef CLASP
#undef EAGER_ATOM #undef EAGER_ATOM
#undef EAGER_CLASS_ATOM #undef EAGER_CLASS_ATOM
#undef EAGER_ATOM_CLASP #undef EAGER_ATOM_CLASP

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

@ -248,6 +248,10 @@ struct JSAtomState {
#endif #endif
}; };
#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
#define CLASS_ATOM(cx,name) \ #define CLASS_ATOM(cx,name) \
((cx)->runtime->atomState.classAtoms[JSProto_##name]) ((cx)->runtime->atomState.classAtoms[JSProto_##name])

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

@ -962,19 +962,32 @@ JSClass js_CallClass = {
* *
* The extensions below other than length, i.e., the ones not in ECMA-262, * The extensions below other than length, i.e., the ones not in ECMA-262,
* are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility
* with ECMA we must allow a delegating object to override them. * with ECMA we must allow a delegating object to override them. Therefore to
* avoid entraining garbage in Function.prototype slots, they must be resolved
* in non-prototype function objects, wherefore the lazy_function_props table
* and fun_resolve's use of it.
*/ */
#define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED) #define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
static JSPropertySpec function_props[] = { static JSPropertySpec function_props[] = {
{js_arguments_str, CALL_ARGUMENTS, JSPROP_PERMANENT, 0,0},
{js_arity_str, FUN_ARITY, JSPROP_PERMANENT, 0,0},
{js_caller_str, FUN_CALLER, JSPROP_PERMANENT, 0,0},
{js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, 0,0}, {js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, 0,0},
{js_name_str, FUN_NAME, JSPROP_PERMANENT, 0,0},
{0,0,0,0,0} {0,0,0,0,0}
}; };
typedef struct LazyFunctionProp {
uint16 atomOffset;
int8 tinyid;
uint8 attrs;
} LazyFunctionProp;
/* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */
static LazyFunctionProp lazy_function_props[] = {
{ATOM_OFFSET(arguments), CALL_ARGUMENTS, JSPROP_PERMANENT},
{ATOM_OFFSET(arity), FUN_ARITY, JSPROP_PERMANENT},
{ATOM_OFFSET(caller), FUN_CALLER, JSPROP_PERMANENT},
{ATOM_OFFSET(name), FUN_NAME, JSPROP_PERMANENT},
};
static JSBool static JSBool
fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{ {
@ -1094,46 +1107,71 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSObject **objp) JSObject **objp)
{ {
JSFunction *fun; JSFunction *fun;
JSString *str; JSAtom *atom;
JSAtom *prototypeAtom; uintN i;
/*
* No need to reflect fun.prototype in 'fun.prototype = ...' or in an
* unqualified reference to prototype, which the emitter looks up as a
* hidden atom when attempting to bind to a formal parameter or local
* variable slot.
*/
if (flags & (JSRESOLVE_ASSIGNING | JSRESOLVE_HIDDEN))
return JS_TRUE;
if (!JSVAL_IS_STRING(id)) if (!JSVAL_IS_STRING(id))
return JS_TRUE; return JS_TRUE;
/* No valid function object should lack private data, but check anyway. */ /* No valid function object should lack private data. */
fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL); fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
if (!fun || !fun->object) JS_ASSERT(fun && fun->object);
/*
* Check for a hidden formal parameter or local variable binding in the
* clone-parent of obj, which would be a different, non-null fun->object.
*/
if (flags & JSRESOLVE_HIDDEN) {
if (fun->object != obj) {
JSObject *pobj;
JSProperty *prop;
atom = js_AtomizeString(cx, JSVAL_TO_STRING(id), 0);
if (!atom)
return JS_FALSE;
if (!js_LookupHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom),
&pobj, &prop)) {
return JS_FALSE;
}
if (prop) {
JS_ASSERT(pobj == fun->object);
*objp = pobj;
OBJ_DROP_PROPERTY(cx, pobj, prop);
}
}
return JS_TRUE;
}
/*
* No need to reflect fun.prototype in 'fun.prototype = ...'. This test
* must come after the JSRESOLVE_HIDDEN test, since call_resolve may look
* for a hidden function object property from an assignment bytecode.
*/
if (flags & JSRESOLVE_ASSIGNING)
return JS_TRUE; return JS_TRUE;
/* /*
* Ok, check whether id is 'prototype' and bootstrap the function object's * Ok, check whether id is 'prototype' and bootstrap the function object's
* prototype property. * prototype property.
*/ */
str = JSVAL_TO_STRING(id); atom = cx->runtime->atomState.classPrototypeAtom;
prototypeAtom = cx->runtime->atomState.classPrototypeAtom; if (id == ATOM_KEY(atom)) {
if (str == ATOM_TO_STRING(prototypeAtom)) {
JSObject *proto, *parentProto; JSObject *proto, *parentProto;
jsval pval; jsval pval;
proto = parentProto = NULL; proto = parentProto = NULL;
if (fun->object != obj && fun->object) { if (fun->object != obj &&
(!cx->runtime->findObjectPrincipals ||
cx->runtime->findObjectPrincipals(cx, obj) ==
cx->runtime->findObjectPrincipals(cx, fun->object))) {
/* /*
* Clone of a function: make its prototype property value have the * Clone of a function where the clone and the object owning fun
* same class as the clone-parent's prototype. * appear to be in the same trust domain: make the cloned function
* object's 'prototype' property value have the same class as the
* clone-parent's 'prototype' value.
*/ */
if (!OBJ_GET_PROPERTY(cx, fun->object, ATOM_TO_JSID(prototypeAtom), if (!OBJ_GET_PROPERTY(cx, fun->object, ATOM_TO_JSID(atom), &pval))
&pval)) {
return JS_FALSE; return JS_FALSE;
}
if (!JSVAL_IS_PRIMITIVE(pval)) { if (!JSVAL_IS_PRIMITIVE(pval)) {
/* /*
* We are about to allocate a new object, so hack the newborn * We are about to allocate a new object, so hack the newborn
@ -1175,6 +1213,24 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
return JS_FALSE; return JS_FALSE;
} }
*objp = obj; *objp = obj;
return JS_TRUE;
}
for (i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) {
LazyFunctionProp *lfp = &lazy_function_props[i];
atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset);
if (id == ATOM_KEY(atom)) {
if (!js_DefineNativeProperty(cx, obj,
ATOM_TO_JSID(atom), JSVAL_VOID,
NULL, NULL, lfp->attrs,
SPROP_HAS_SHORTID, lfp->tinyid,
NULL)) {
return JS_FALSE;
}
*objp = obj;
return JS_TRUE;
}
} }
return JS_TRUE; return JS_TRUE;
@ -1457,8 +1513,10 @@ fun_trace(JSTracer *trc, JSObject *obj)
fun = (JSFunction *) JS_GetPrivate(trc->context, obj); fun = (JSFunction *) JS_GetPrivate(trc->context, obj);
if (fun) { if (fun) {
JS_CALL_TRACER(trc, fun, JSTRACE_FUNCTION, "private"); JS_CALL_TRACER(trc, fun, JSTRACE_FUNCTION, "private");
if (fun->object != obj)
JS_CALL_TRACER(trc, fun->object, JSTRACE_OBJECT, "object");
if (fun->atom) if (fun->atom)
JS_CALL_TRACER(trc, fun->atom, JSTRACE_ATOM, "name"); JS_CALL_TRACER(trc, fun->atom, JSTRACE_ATOM, "atom");
if (FUN_INTERPRETED(fun) && fun->u.i.script) if (FUN_INTERPRETED(fun) && fun->u.i.script)
js_TraceScript(trc, fun->u.i.script); js_TraceScript(trc, fun->u.i.script);
} }
@ -2170,7 +2228,7 @@ js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
JSFunction *fun; JSFunction *fun;
JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass); JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
newfunobj = js_NewObject(cx, &js_FunctionClass, funobj, parent); newfunobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
if (!newfunobj) if (!newfunobj)
return NULL; return NULL;
fun = (JSFunction *) JS_GetPrivate(cx, funobj); fun = (JSFunction *) JS_GetPrivate(cx, funobj);