Bug 552248 - fix crash when JS_EvaluateInStackFrame is called for frame in saved callstack (r=Waldo)

This commit is contained in:
Luke Wagner 2010-03-15 19:24:08 -07:00
Родитель e9a5ed9c7d
Коммит 07a82dbbd3
9 изменённых файлов: 134 добавлений и 42 удалений

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

@ -1925,6 +1925,39 @@ js_CurrentPCIsInImacro(JSContext *cx)
#endif
}
CallStack *
JSContext::containingCallStack(JSStackFrame *target)
{
/* The context may have nothing running. */
CallStack *cs = currentCallStack;
if (!cs)
return NULL;
/* The active callstack's top frame is cx->fp. */
if (fp) {
JS_ASSERT(activeCallStack() == cs);
JSStackFrame *f = fp;
JSStackFrame *stop = cs->getInitialFrame()->down;
for (; f != stop; f = f->down) {
if (f == target)
return cs;
}
cs = cs->getPrevious();
}
/* A suspended callstack's top frame is its suspended frame. */
for (; cs; cs = cs->getPrevious()) {
JSStackFrame *f = cs->getSuspendedFrame();
JSStackFrame *stop = cs->getInitialFrame()->down;
for (; f != stop; f = f->down) {
if (f == target)
return cs;
}
}
return NULL;
}
void
JSContext::checkMallocGCPressure(void *p)
{

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

@ -1363,6 +1363,12 @@ struct JSContext
currentCallStack->restore();
}
/*
* Perform a linear search of all frames in all callstacks in the given context
* for the given frame, returning the callstack, if found, and null otherwise.
*/
js::CallStack *containingCallStack(JSStackFrame *target);
#ifdef JS_THREADSAFE
JSThread *thread;
jsrefcount requestDepth;

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

@ -2101,7 +2101,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSObject *scopeobj = (cg->flags & TCF_IN_FUNCTION)
? FUN_OBJECT(cg->fun)->getParent()
: cg->scopeChain;
if (scopeobj != caller->varobj(cx))
if (scopeobj != cg->compiler->callerVarObj)
return JS_TRUE;
/*
@ -2196,7 +2196,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
JS_ASSERT(evalcg->flags & TCF_COMPILE_N_GO);
JS_ASSERT(caller->fun && caller->varobj(cx) == evalcg->scopeChain);
JS_ASSERT(caller->fun && cg->compiler->callerVarObj == evalcg->scopeChain);
/*
* Don't generate upvars on the left side of a for loop. See

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

@ -231,7 +231,7 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
*/
JS_ASSERT(fp->fun);
JS_ASSERT_IF(fp->fun->flags & JSFUN_HEAVYWEIGHT,
fp->varobj(js_ContainingCallStack(cx, fp)));
fp->varobj(cx->containingCallStack(fp)));
/* Skip eval and debugger frames. */
while (fp->flags & JSFRAME_SPECIAL)

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

@ -1466,33 +1466,6 @@ js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval,
return js_InternalCall(cx, obj, fval, argc, argv, rval);
}
CallStack *
js_ContainingCallStack(JSContext *cx, JSStackFrame *target)
{
JS_ASSERT(cx->fp);
/* The active callstack's top frame is cx->fp. */
CallStack *cs = cx->activeCallStack();
JSStackFrame *f = cx->fp;
JSStackFrame *stop = cs->getInitialFrame()->down;
for (; f != stop; f = f->down) {
if (f == target)
return cs;
}
/* A suspended callstack's top frame is its suspended frame. */
for (cs = cs->getPrevious(); cs; cs = cs->getPrevious()) {
f = cs->getSuspendedFrame();
stop = cs->getInitialFrame()->down;
for (; f != stop; f = f->down) {
if (f == target)
return cs;
}
}
return NULL;
}
JSBool
js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
JSStackFrame *down, uintN flags, jsval *result)
@ -1547,7 +1520,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
if (down == cx->fp) {
callStack.setInitialVarObj(down->varobj(cx));
} else {
CallStack *cs = js_ContainingCallStack(cx, down);
CallStack *cs = cx->containingCallStack(down);
callStack.setInitialVarObj(down->varobj(cs));
}
} else {

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

@ -170,13 +170,6 @@ struct JSStackFrame {
};
#ifdef __cplusplus
/*
* Perform a linear search of all frames in all callstacks in the given context
* for the given frame, returning the callstack, if found, and NULL otherwise.
*/
extern js::CallStack *
js_ContainingCallStack(JSContext *cx, JSStackFrame *target);
static JS_INLINE uintN
FramePCOffset(JSStackFrame* fp)
{

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

@ -919,7 +919,8 @@ struct JSCompiler : private js::AutoGCRooter {
JSTokenStream tokenStream;
void *tempPoolMark; /* initial JSContext.tempPool mark */
JSPrincipals *principals; /* principals associated with source */
JSStackFrame *callerFrame; /* scripted caller frame for eval and dbgapi */
JSStackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */
JSObject *const callerVarObj; /* callerFrame's varObj */
JSParseNode *nodeList; /* list of recyclable parse-node structs */
uint32 functionCount; /* number of functions in current unit */
JSObjectBox *traceListHead; /* list of parsed object for GC tracing */
@ -927,9 +928,9 @@ struct JSCompiler : private js::AutoGCRooter {
JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
: js::AutoGCRooter(cx, COMPILER), context(cx),
aleFreeList(NULL), tokenStream(cx), principals(NULL),
callerFrame(cfp), nodeList(NULL), functionCount(0), traceListHead(NULL),
tc(NULL)
aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp),
callerVarObj(cfp ? cfp->varobj(cx->containingCallStack(cfp)) : NULL),
nodeList(NULL), functionCount(0), traceListHead(NULL), tc(NULL)
{
js::PodArrayZero(tempFreeList);
setPrincipals(prin);

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

@ -3028,6 +3028,54 @@ out:
return ok;
}
static JSBool
EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
{
jsval *argv = JS_ARGV(cx, vp);
if (argc < 2 ||
!JSVAL_IS_INT(argv[0]) ||
!JSVAL_IS_STRING(argv[1])) {
JS_ReportError(cx, "Invalid arguments to evalInFrame");
return JS_FALSE;
}
uint32 upCount = JSVAL_TO_INT(argv[0]);
JSString *str = JSVAL_TO_STRING(argv[1]);
bool saveCurrent = JSVAL_IS_BOOLEAN(argv[2])
? (bool)JSVAL_TO_SPECIAL(argv[2])
: false;
JS_ASSERT(cx->fp);
JSStackFrame *fp = cx->fp;
for (uint32 i = 0; i < upCount; ++i) {
if (!fp->down)
break;
fp = fp->down;
}
if (!fp->script) {
JS_ReportError(cx, "cannot eval in non-script frame");
return JS_FALSE;
}
JSStackFrame *oldfp;
if (saveCurrent)
oldfp = JS_SaveFrameChain(cx);
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
fp->script->filename,
JS_PCToLineNumber(cx, fp->script,
fp->regs->pc),
vp);
if (saveCurrent)
JS_RestoreFrameChain(cx, oldfp);
return ok;
}
static JSBool
ShapeOf(JSContext *cx, uintN argc, jsval *vp)
{
@ -3784,6 +3832,7 @@ static JSFunctionSpec shell_functions[] = {
JS_FN("getslx", GetSLX, 1,0),
JS_FN("toint32", ToInt32, 1,0),
JS_FS("evalcx", EvalInContext, 1,0,0),
JS_FN("evalInFrame", EvalInFrame, 2,0),
JS_FN("shapeOf", ShapeOf, 1,0),
#ifdef MOZ_SHARK
JS_FS("startShark", js_StartShark, 0,0,0),
@ -3885,6 +3934,8 @@ static const char *const shell_help_messages[] = {
" if (s == '' && !o) return new o with eager standard classes\n"
" if (s == 'lazy' && !o) return new o with lazy standard classes\n"
" if (s == 'split' && !o) return new split-object o with lazy standard classes",
"evalInFrame(n,str,save) Evaluate 'str' in the nth up frame.\n"
" If 'save' (default false), save the frame chain",
"shapeOf(obj) Get the shape of obj (an implementation detail)",
#ifdef MOZ_SHARK
"startShark() Start a Shark session.\n"

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

@ -0,0 +1,35 @@
var a = new Array();
function i(save) {
var x = 9;
evalInFrame(0, "a.push(x)", save);
evalInFrame(1, "a.push(z)", save);
evalInFrame(2, "a.push(z)", save);
evalInFrame(3, "a.push(y)", save);
evalInFrame(4, "a.push(x)", save);
}
function h() {
var z = 5;
evalInFrame(0, "a.push(z)");
evalInFrame(1, "a.push(y)");
evalInFrame(2, "a.push(x)");
evalInFrame(0, "i(false)");
evalInFrame(0, "a.push(z)", true);
evalInFrame(1, "a.push(y)", true);
evalInFrame(2, "a.push(x)", true);
evalInFrame(0, "i(true)", true);
}
function g() {
var y = 4;
h();
}
function f() {
var x = 3;
g();
}
f();
assertEq(a+'', [5, 4, 3, 9, 5, 5, 4, 3, 5, 4, 3, 9, 5, 5, 4, 3]+'');