static bool InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message, HandleString filename, unsigned lineno, unsigned column, JSErrorReport *report, int exnType) { JS_ASSERT(exnObject->isError()); JS_ASSERT(!exnObject->getPrivate()); JSCheckAccessOp checkAccess = cx->runtime->securityCallbacks->checkObjectAccess; Vector<JSStackTraceStackElem> frames(cx); { SuppressErrorsGuard seg(cx); for (NonBuiltinScriptFrameIter i(cx); !i.done(); ++i) { /* Ask the crystal CAPS ball whether we can see across compartments. */ if (checkAccess && i.isNonEvalFunctionFrame()) { RootedValue v(cx); RootedId callerid(cx, NameToId(cx->names().caller)); RootedObject obj(cx, i.callee()); if (!checkAccess(cx, obj, callerid, JSACC_READ, &v)) break; } if (!frames.growBy(1)) return false; JSStackTraceStackElem &frame = frames.back(); if (i.isNonEvalFunctionFrame()) { RawAtom atom = i.callee()->displayAtom(); if (atom == NULL) atom = cx->runtime->emptyString; frame.funName = atom; } else { frame.funName = NULL; } RootedScript script(cx, i.script()); const char *cfilename = script->filename(); if (!cfilename) cfilename = ""; frame.filename = cfilename; frame.ulineno = PCToLineNumber(script, i.pc()); } } /* Do not need overflow check: the vm stack is already bigger. */ JS_STATIC_ASSERT(sizeof(JSStackTraceElem) <= sizeof(StackFrame)); size_t nbytes = offsetof(JSExnPrivate, stackElems) + frames.length() * sizeof(JSStackTraceElem); JSExnPrivate *priv = (JSExnPrivate *)cx->malloc_(nbytes); if (!priv) return false; /* Initialize to zero so that write barriers don't witness undefined values. */ memset(priv, 0, nbytes); if (report) { /* * Construct a new copy of the error report struct. We can't use the * error report struct that was passed in, because it's allocated on * the stack, and also because it may point to transient data in the * TokenStream. */ priv->errorReport = CopyErrorReport(cx, report); if (!priv->errorReport) { js_free(priv); return false; } } else { priv->errorReport = NULL; } priv->message.init(message); priv->filename.init(filename); priv->lineno = lineno; priv->column = column; priv->stackDepth = frames.length(); priv->exnType = exnType; for (size_t i = 0; i < frames.length(); ++i) { priv->stackElems[i].funName.init(frames[i].funName); priv->stackElems[i].filename = JS_strdup(cx, frames[i].filename); if (!priv->stackElems[i].filename) return false; priv->stackElems[i].ulineno = frames[i].ulineno; } SetExnPrivate(exnObject, priv); return true; }
static bool InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message, HandleString filename, unsigned lineno, JSErrorReport *report, int exnType) { JS_ASSERT(exnObject->isError()); JS_ASSERT(!exnObject->getPrivate()); JSCheckAccessOp checkAccess = cx->runtime->securityCallbacks->checkObjectAccess; Vector<JSStackTraceStackElem> frames(cx); { SuppressErrorsGuard seg(cx); for (FrameRegsIter i(cx); !i.done(); ++i) { StackFrame *fp = i.fp(); /* * Ask the crystal CAPS ball whether we can see across compartments. * NB: this means 'fp' may point to cross-compartment frames. */ if (checkAccess && fp->isNonEvalFunctionFrame()) { Value v = NullValue(); jsid callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom); if (!checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v)) break; } if (!frames.growBy(1)) return false; JSStackTraceStackElem &frame = frames.back(); if (fp->isNonEvalFunctionFrame()) frame.funName = fp->fun()->atom ? fp->fun()->atom : cx->runtime->emptyString; else frame.funName = NULL; if (fp->isScriptFrame()) { frame.filename = SaveScriptFilename(cx, fp->script()->filename); if (!frame.filename) return false; frame.ulineno = PCToLineNumber(fp->script(), i.pc()); } else { frame.ulineno = 0; frame.filename = NULL; } } } /* Do not need overflow check: the vm stack is already bigger. */ JS_STATIC_ASSERT(sizeof(JSStackTraceElem) <= sizeof(StackFrame)); size_t nbytes = offsetof(JSExnPrivate, stackElems) + frames.length() * sizeof(JSStackTraceElem); JSExnPrivate *priv = (JSExnPrivate *)cx->malloc_(nbytes); if (!priv) return false; /* Initialize to zero so that write barriers don't witness undefined values. */ memset(priv, 0, nbytes); if (report) { /* * Construct a new copy of the error report struct. We can't use the * error report struct that was passed in, because it's allocated on * the stack, and also because it may point to transient data in the * TokenStream. */ priv->errorReport = CopyErrorReport(cx, report); if (!priv->errorReport) { cx->free_(priv); return false; } } else { priv->errorReport = NULL; } priv->message.init(message); priv->filename.init(filename); priv->lineno = lineno; priv->stackDepth = frames.length(); priv->exnType = exnType; for (size_t i = 0; i < frames.length(); ++i) { priv->stackElems[i].funName.init(frames[i].funName); priv->stackElems[i].filename = frames[i].filename; priv->stackElems[i].ulineno = frames[i].ulineno; } SetExnPrivate(cx, exnObject, priv); return true; }