Bug 515496 - Eliminate extra security check when computing this. r=jorendorff.

This commit is contained in:
Blake Kaplan 2010-02-11 17:04:42 -08:00
parent 6512be25c4
commit 387907ce9f
5 changed files with 17 additions and 60 deletions

View File

@ -1693,7 +1693,7 @@ JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
JS_PUBLIC_API(jsval) JS_PUBLIC_API(jsval)
JS_ComputeThis(JSContext *cx, jsval *vp) JS_ComputeThis(JSContext *cx, jsval *vp)
{ {
if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) if (!js_ComputeThis(cx, vp + 2))
return JSVAL_NULL; return JSVAL_NULL;
return vp[1]; return vp[1];
} }
@ -4285,7 +4285,7 @@ js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp)
* Follow Function.prototype.apply and .call by using the global object as * Follow Function.prototype.apply and .call by using the global object as
* the 'this' param if no args. * the 'this' param if no args.
*/ */
if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) if (!js_ComputeThis(cx, vp + 2))
return JS_FALSE; return JS_FALSE;
/* /*
* Protect against argc underflowing. By calling js_ComputeThis, we made * Protect against argc underflowing. By calling js_ComputeThis, we made
@ -4349,7 +4349,7 @@ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
* Follow Function.prototype.apply and .call by using the global object as * Follow Function.prototype.apply and .call by using the global object as
* the 'this' param if no args. * the 'this' param if no args.
*/ */
if (!js_ComputeThis(cx, JS_TRUE, argv)) if (!js_ComputeThis(cx, argv))
return JS_FALSE; return JS_FALSE;
js_GetTopStackFrame(cx)->thisv = argv[-1]; js_GetTopStackFrame(cx)->thisv = argv[-1];
JS_ASSERT(cx->fp->argv == argv); JS_ASSERT(cx->fp->argv == argv);

View File

@ -1243,7 +1243,7 @@ JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
} }
if (fp->argv) if (fp->argv)
fp->thisv = OBJECT_TO_JSVAL(js_ComputeThis(cx, JS_TRUE, fp->argv)); fp->thisv = OBJECT_TO_JSVAL(js_ComputeThis(cx, fp->argv));
if (afp) { if (afp) {
cx->fp = afp; cx->fp = afp;

View File

@ -399,7 +399,7 @@ CallThisObjectHook(JSContext *cx, JSObject *obj, jsval *argv)
* The alert should display "true". * The alert should display "true".
*/ */
JS_STATIC_INTERPRET JSObject * JS_STATIC_INTERPRET JSObject *
js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv) js_ComputeGlobalThis(JSContext *cx, jsval *argv)
{ {
JSObject *thisp; JSObject *thisp;
@ -407,57 +407,14 @@ js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv)
!JSVAL_TO_OBJECT(argv[-2])->getParent()) { !JSVAL_TO_OBJECT(argv[-2])->getParent()) {
thisp = cx->globalObject; thisp = cx->globalObject;
} else { } else {
jsid id; thisp = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(argv[-2]));
jsval v;
uintN attrs;
JSBool ok;
JSObject *parent;
/*
* Walk up the parent chain, first checking that the running script
* has access to the callee's parent object. Note that if lazy, the
* running script whose principals we want to check is the script
* associated with fp->down, not with fp.
*
* FIXME: 417851 -- this access check should not be required, as it
* imposes a performance penalty on all js_ComputeGlobalThis calls,
* and it represents a maintenance hazard.
*
* When the above FIXME is made fixed, the whole GC reachable frame
* mechanism can be removed as well.
*/
JSStackFrame *fp = js_GetTopStackFrame(cx);
JSGCReachableFrame reachable;
if (lazy) {
JS_ASSERT(fp->argv == argv);
cx->fp = fp->down;
fp->down = NULL;
cx->pushGCReachableFrame(reachable, fp);
}
thisp = JSVAL_TO_OBJECT(argv[-2]);
id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom);
ok = thisp->checkAccess(cx, id, JSACC_PARENT, &v, &attrs);
if (lazy) {
fp->down = cx->fp;
cx->fp = fp;
cx->popGCReachableFrame();
}
if (!ok)
return NULL;
if (v != JSVAL_NULL) {
thisp = JSVAL_IS_VOID(v) ? thisp->getParent() : JSVAL_TO_OBJECT(v);
while ((parent = thisp->getParent()) != NULL)
thisp = parent;
}
} }
return CallThisObjectHook(cx, thisp, argv); return CallThisObjectHook(cx, thisp, argv);
} }
static JSObject * static JSObject *
ComputeThis(JSContext *cx, JSBool lazy, jsval *argv) ComputeThis(JSContext *cx, jsval *argv)
{ {
JSObject *thisp; JSObject *thisp;
@ -471,18 +428,18 @@ ComputeThis(JSContext *cx, JSBool lazy, jsval *argv)
thisp = JSVAL_TO_OBJECT(argv[-1]); thisp = JSVAL_TO_OBJECT(argv[-1]);
if (OBJ_GET_CLASS(cx, thisp) == &js_CallClass || OBJ_GET_CLASS(cx, thisp) == &js_BlockClass) if (OBJ_GET_CLASS(cx, thisp) == &js_CallClass || OBJ_GET_CLASS(cx, thisp) == &js_BlockClass)
return js_ComputeGlobalThis(cx, lazy, argv); return js_ComputeGlobalThis(cx, argv);
return CallThisObjectHook(cx, thisp, argv); return CallThisObjectHook(cx, thisp, argv);
} }
JSObject * JSObject *
js_ComputeThis(JSContext *cx, JSBool lazy, jsval *argv) js_ComputeThis(JSContext *cx, jsval *argv)
{ {
JS_ASSERT(argv[-1] != JSVAL_HOLE); // check for SynthesizeFrame poisoning JS_ASSERT(argv[-1] != JSVAL_HOLE); // check for SynthesizeFrame poisoning
if (JSVAL_IS_NULL(argv[-1])) if (JSVAL_IS_NULL(argv[-1]))
return js_ComputeGlobalThis(cx, lazy, argv); return js_ComputeGlobalThis(cx, argv);
return ComputeThis(cx, lazy, argv); return ComputeThis(cx, argv);
} }
#if JS_HAS_NO_SUCH_METHOD #if JS_HAS_NO_SUCH_METHOD
@ -723,7 +680,7 @@ js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags)
* the appropriate this-computing bytecode, e.g., JSOP_THIS. * the appropriate this-computing bytecode, e.g., JSOP_THIS.
*/ */
if (native && (!fun || !(fun->flags & JSFUN_FAST_NATIVE))) { if (native && (!fun || !(fun->flags & JSFUN_FAST_NATIVE))) {
if (!js_ComputeThis(cx, JS_FALSE, vp + 2)) { if (!js_ComputeThis(cx, vp + 2)) {
ok = JS_FALSE; ok = JS_FALSE;
goto out2; goto out2;
} }

View File

@ -265,7 +265,7 @@ js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp);
* must not be a JSVAL_VOID. * must not be a JSVAL_VOID.
*/ */
extern JSObject * extern JSObject *
js_ComputeThis(JSContext *cx, JSBool lazy, jsval *argv); js_ComputeThis(JSContext *cx, jsval *argv);
extern const uint16 js_PrimitiveTestFlags[]; extern const uint16 js_PrimitiveTestFlags[];
@ -280,7 +280,7 @@ js_ComputeThisForFrame(JSContext *cx, JSStackFrame *fp)
{ {
if (fp->flags & JSFRAME_COMPUTED_THIS) if (fp->flags & JSFRAME_COMPUTED_THIS)
return JSVAL_TO_OBJECT(fp->thisv); /* JSVAL_COMPUTED_THIS invariant */ return JSVAL_TO_OBJECT(fp->thisv); /* JSVAL_COMPUTED_THIS invariant */
JSObject* obj = js_ComputeThis(cx, JS_TRUE, fp->argv); JSObject* obj = js_ComputeThis(cx, fp->argv);
if (!obj) if (!obj)
return NULL; return NULL;
fp->thisv = OBJECT_TO_JSVAL(obj); fp->thisv = OBJECT_TO_JSVAL(obj);
@ -421,7 +421,7 @@ js_FreeRawStack(JSContext *cx, void *mark);
* The alert should display "true". * The alert should display "true".
*/ */
extern JSObject * extern JSObject *
js_ComputeGlobalThis(JSContext *cx, JSBool lazy, jsval *argv); js_ComputeGlobalThis(JSContext *cx, jsval *argv);
extern JS_REQUIRES_STACK JSBool extern JS_REQUIRES_STACK JSBool
js_EnterWith(JSContext *cx, jsint stackIndex); js_EnterWith(JSContext *cx, jsint stackIndex);

View File

@ -9437,7 +9437,7 @@ TraceRecorder::getThis(LIns*& this_ins)
JSObject* thisObj = js_ComputeThisForFrame(cx, cx->fp); JSObject* thisObj = js_ComputeThisForFrame(cx, cx->fp);
if (!thisObj) if (!thisObj)
RETURN_ERROR("js_ComputeThisForName failed"); RETURN_ERROR("js_ComputeThisForFrame failed");
/* In global code, bake in the global object as 'this' object. */ /* In global code, bake in the global object as 'this' object. */
if (!cx->fp->callee()) { if (!cx->fp->callee()) {
@ -10798,7 +10798,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
*/ */
if (!(fun->flags & JSFUN_FAST_NATIVE)) { if (!(fun->flags & JSFUN_FAST_NATIVE)) {
if (JSVAL_IS_NULL(vp[1])) { if (JSVAL_IS_NULL(vp[1])) {
JSObject* thisObj = js_ComputeThis(cx, JS_FALSE, vp + 2); JSObject* thisObj = js_ComputeThis(cx, vp + 2);
if (!thisObj) if (!thisObj)
RETURN_ERROR("error in js_ComputeGlobalThis"); RETURN_ERROR("error in js_ComputeGlobalThis");
this_ins = INS_CONSTOBJ(thisObj); this_ins = INS_CONSTOBJ(thisObj);