зеркало из https://github.com/mozilla/gecko-dev.git
Bug 552248 - fix crash when JS_EvaluateInStackFrame is called for frame in saved callstack (r=Waldo)
This commit is contained in:
Родитель
e9a5ed9c7d
Коммит
07a82dbbd3
|
@ -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]+'');
|
Загрузка…
Ссылка в новой задаче