JSString* jsd_ValToStringInStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe, jsval val) { JSBool valid; JSString* retval; JSExceptionState* exceptionState; JSContext* cx; JSD_LOCK_THREADSTATES(jsdc); valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe); JSD_UNLOCK_THREADSTATES(jsdc); if( ! valid ) return NULL; cx = jsdthreadstate->context; JS_ASSERT(cx); exceptionState = JS_SaveExceptionState(cx); retval = JS_ValueToString(cx, val); JS_RestoreExceptionState(cx, exceptionState); return retval; }
JSString* jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JSExceptionState* exceptionState; if(!jsdval->string) { /* if the jsval is a string, then we don't need to double root it */ if(JSVAL_IS_STRING(jsdval->val)) jsdval->string = JSVAL_TO_STRING(jsdval->val); else { JS_BeginRequest(cx); exceptionState = JS_SaveExceptionState(cx); jsdval->string = JS_ValueToString(cx, jsdval->val); JS_RestoreExceptionState(cx, exceptionState); if(jsdval->string) { if(!JS_AddNamedRoot(cx, &jsdval->string, "ValueString")) jsdval->string = NULL; } JS_EndRequest(cx); } } return jsdval->string; }
JSBool jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JSFunction* fun; JSExceptionState* exceptionState; JSCrossCompartmentCall *call = NULL; if(jsd_IsValueFunction(jsdc, jsdval)) { JSBool ok = JS_FALSE; JS_BeginRequest(cx); call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val)); if(!call) { JS_EndRequest(cx); return JS_FALSE; } exceptionState = JS_SaveExceptionState(cx); fun = JSD_GetValueFunction(jsdc, jsdval); JS_RestoreExceptionState(cx, exceptionState); if(fun) ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE; JS_LeaveCrossCompartmentCall(call); JS_EndRequest(cx); JS_ASSERT(fun); return ok; } return !JSVAL_IS_PRIMITIVE(jsdval->val); }
JSString* jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JSFunction* fun; JSExceptionState* exceptionState; JSCrossCompartmentCall *call = NULL; if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval)) { JS_BeginRequest(cx); call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val)); if(!call) { JS_EndRequest(cx); return NULL; } exceptionState = JS_SaveExceptionState(cx); fun = JSD_GetValueFunction(jsdc, jsdval); JS_RestoreExceptionState(cx, exceptionState); JS_LeaveCrossCompartmentCall(call); JS_EndRequest(cx); if(!fun) return NULL; jsdval->funName = JS_GetFunctionId(fun); /* For compatibility we return "anonymous", not an empty string here. */ if (!jsdval->funName) jsdval->funName = JS_GetAnonymousString(jsdc->jsrt); } return jsdval->funName; }
JSDScript* jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JS::RootedValue val(cx, jsdval->val); JSFunction* fun = NULL; JSExceptionState* exceptionState; JS::RootedScript script(cx); JSDScript* jsdscript; JSCompartment* oldCompartment = NULL; if (!jsd_IsValueFunction(jsdc, jsdval)) return NULL; JS_BeginRequest(cx); oldCompartment = JS_EnterCompartment(cx, JSVAL_TO_OBJECT(val)); exceptionState = JS_SaveExceptionState(cx); fun = JSD_GetValueFunction(jsdc, jsdval); JS_RestoreExceptionState(cx, exceptionState); if (fun) script = JS_GetFunctionScript(cx, fun); JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); if (!script) return NULL; JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindJSDScript(jsdc, script); JSD_UNLOCK_SCRIPTS(jsdc); return jsdscript; }
JSBool jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JS::RootedFunction fun(cx); JSExceptionState* exceptionState; JSCompartment* oldCompartment = NULL; if(jsd_IsValueFunction(jsdc, jsdval)) { JSBool ok = JS_FALSE; JS_BeginRequest(cx); oldCompartment = JS_EnterCompartment(cx, JSVAL_TO_OBJECT(jsdval->val)); exceptionState = JS_SaveExceptionState(cx); fun = JSD_GetValueFunction(jsdc, jsdval); JS_RestoreExceptionState(cx, exceptionState); if(fun) ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE; JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); JS_ASSERT(fun); return ok; } return !JSVAL_IS_PRIMITIVE(jsdval->val); }
JSDScript* jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; jsval val = jsdval->val; JSFunction* fun; JSExceptionState* exceptionState; JSScript* script = NULL; JSDScript* jsdscript; if (!jsd_IsValueFunction(jsdc, jsdval)) return NULL; JS_BeginRequest(cx); exceptionState = JS_SaveExceptionState(cx); fun = JS_ValueToFunction(cx, val); JS_RestoreExceptionState(cx, exceptionState); if (fun) script = JS_GetFunctionScript(cx, fun); JS_EndRequest(cx); if (!script) return NULL; JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindJSDScript(jsdc, script); JSD_UNLOCK_SCRIPTS(jsdc); return jsdscript; }
JSString* jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JSExceptionState* exceptionState; JSCrossCompartmentCall *call = NULL; jsval stringval; JSString *string; JSBool needWrap; JSObject *scopeObj; if(jsdval->string) return jsdval->string; /* Reuse the string without copying or re-rooting it */ if(JSVAL_IS_STRING(jsdval->val)) { jsdval->string = JSVAL_TO_STRING(jsdval->val); return jsdval->string; } JS_BeginRequest(cx); /* Objects call JS_ValueToString in their own compartment. */ scopeObj = JSVAL_IS_OBJECT(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob; call = JS_EnterCrossCompartmentCall(cx, scopeObj); if(!call) { JS_EndRequest(cx); return NULL; } exceptionState = JS_SaveExceptionState(cx); string = JS_ValueToString(cx, jsdval->val); JS_RestoreExceptionState(cx, exceptionState); JS_LeaveCrossCompartmentCall(call); call = NULL; if(string) { stringval = STRING_TO_JSVAL(string); call = JS_EnterCrossCompartmentCall(cx, jsdc->glob); } if(!string || !call || !JS_WrapValue(cx, &stringval)) { if(call) JS_LeaveCrossCompartmentCall(call); JS_EndRequest(cx); return NULL; } jsdval->string = JSVAL_TO_STRING(stringval); if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString")) jsdval->string = NULL; JS_LeaveCrossCompartmentCall(call); JS_EndRequest(cx); return jsdval->string; }
static JSBool gjs_print_parse_args(JSContext *context, uintN argc, jsval *argv, char **buffer) { GString *str; gchar *s; guint n; JS_BeginRequest(context); str = g_string_new(""); (void)JS_EnterLocalRootScope(context); for (n = 0; n < argc; ++n) { JSExceptionState *exc_state; JSString *jstr; /* JS_ValueToString might throw, in which we will only * log that the value could be converted to string */ exc_state = JS_SaveExceptionState(context); jstr = JS_ValueToString(context, argv[n]); if (jstr != NULL) argv[n] = STRING_TO_JSVAL(jstr); // GC root JS_RestoreExceptionState(context, exc_state); if (jstr != NULL) { if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) { JS_LeaveLocalRootScope(context); JS_EndRequest(context); g_string_free(str, TRUE); return JS_FALSE; } g_string_append(str, s); g_free(s); if (n < (argc-1)) g_string_append_c(str, ' '); } else { JS_LeaveLocalRootScope(context); JS_EndRequest(context); *buffer = g_string_free(str, TRUE); if (!*buffer) *buffer = g_strdup("<invalid string>"); return JS_TRUE; } } JS_LeaveLocalRootScope(context); *buffer = g_string_free(str, FALSE); JS_EndRequest(context); return JS_TRUE; }
JSString* jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JSExceptionState* exceptionState; JSCompartment* oldCompartment = NULL; jsval stringval; JS::RootedString string(cx); JS::RootedObject scopeObj(cx); if(jsdval->string) return jsdval->string; /* Reuse the string without copying or re-rooting it */ if(JSVAL_IS_STRING(jsdval->val)) { jsdval->string = JSVAL_TO_STRING(jsdval->val); return jsdval->string; } JS_BeginRequest(cx); /* Objects call JS_ValueToString in their own compartment. */ scopeObj = !JSVAL_IS_PRIMITIVE(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob; oldCompartment = JS_EnterCompartment(cx, scopeObj); exceptionState = JS_SaveExceptionState(cx); string = JS_ValueToString(cx, jsdval->val); JS_RestoreExceptionState(cx, exceptionState); JS_LeaveCompartment(cx, oldCompartment); oldCompartment = NULL; if(string) { stringval = STRING_TO_JSVAL(string); oldCompartment = JS_EnterCompartment(cx, jsdc->glob); } if(!string || !JS_WrapValue(cx, &stringval)) { if(oldCompartment) JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); return NULL; } jsdval->string = JSVAL_TO_STRING(stringval); if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString")) jsdval->string = NULL; JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); return jsdval->string; }
static JSBool gjs_log_error(JSContext *context, uintN argc, jsval *vp) { jsval *argv = JS_ARGV(context, vp); char *s; JSExceptionState *exc_state; JSString *jstr; jsval exc; if (argc != 2) { gjs_throw(context, "Must pass an exception and message string to logError()"); return JS_FALSE; } JS_BeginRequest(context); exc = argv[0]; /* JS_ValueToString might throw, in which we will only *log that the value could be converted to string */ exc_state = JS_SaveExceptionState(context); jstr = JS_ValueToString(context, argv[1]); if (jstr != NULL) argv[1] = STRING_TO_JSVAL(jstr); // GC root JS_RestoreExceptionState(context, exc_state); if (jstr == NULL) { gjs_debug(GJS_DEBUG_ERROR, "<cannot convert value to string>"); gjs_log_exception_props(context, exc); JS_EndRequest(context); return JS_TRUE; } if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) { JS_EndRequest(context); return JS_FALSE; } gjs_debug(GJS_DEBUG_ERROR, "%s", s); gjs_log_exception_props(context, exc); g_free(s); JS_EndRequest(context); JS_SET_RVAL(context, vp, JSVAL_VOID); return JS_TRUE; }
JSBool xpc_DumpEvalInJSStackFrame(JSContext* cx, JSUint32 frameno, const char* text) { JSStackFrame* fp; JSStackFrame* iter = nsnull; JSUint32 num = 0; if(!cx || !text) { puts("invalid params passed to xpc_DumpEvalInJSStackFrame!"); return JS_FALSE; } printf("js[%d]> %s\n", frameno, text); while(nsnull != (fp = JS_FrameIterator(cx, &iter))) { if(num == frameno) break; num++; } if(!fp) { puts("invalid frame number!"); return JS_FALSE; } JSAutoRequest ar(cx); JSExceptionState* exceptionState = JS_SaveExceptionState(cx); JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter); jsval rval; JSString* str; JSAutoByteString bytes; if(JS_EvaluateInStackFrame(cx, fp, text, strlen(text), "eval", 1, &rval) && nsnull != (str = JS_ValueToString(cx, rval)) && bytes.encode(cx, str)) { printf("%s\n", bytes.ptr()); } else puts("eval failed!"); JS_SetErrorReporter(cx, older); JS_RestoreExceptionState(cx, exceptionState); return JS_TRUE; }
JSBool xpc_DumpEvalInJSStackFrame(JSContext* cx, uint32_t frameno, const char* text) { if (!cx || !text) { DebugDump("%s", "invalid params passed to xpc_DumpEvalInJSStackFrame!\n"); return false; } DebugDump("js[%d]> %s\n", frameno, text); uint32_t num = 0; JSAbstractFramePtr frame = JSNullFramePtr(); JSBrokenFrameIterator iter(cx); while (!iter.done()) { if (num == frameno) { frame = iter.abstractFramePtr(); break; } ++iter; num++; } if (!frame) { DebugDump("%s", "invalid frame number!\n"); return false; } JSAutoRequest ar(cx); JSExceptionState* exceptionState = JS_SaveExceptionState(cx); JSErrorReporter older = JS_SetErrorReporter(cx, xpcDumpEvalErrorReporter); jsval rval; JSString* str; JSAutoByteString bytes; if (frame.evaluateInStackFrame(cx, text, strlen(text), "eval", 1, &rval) && nullptr != (str = JS_ValueToString(cx, rval)) && bytes.encode(cx, str)) { DebugDump("%s\n", bytes.ptr()); } else DebugDump("%s", "eval failed!\n"); JS_SetErrorReporter(cx, older); JS_RestoreExceptionState(cx, exceptionState); return true; }
char* xpc_PrintJSStack(JSContext* cx, JSBool showArgs, JSBool showLocals, JSBool showThisProps) { char* buf; JSExceptionState *state = JS_SaveExceptionState(cx); if(!state) puts("Call to a debug function modifying state!"); JS_ClearPendingException(cx); buf = FormatJSStackDump(cx, nsnull, showArgs, showLocals, showThisProps); if(!buf) puts("Failed to format JavaScript stack for dump"); JS_RestoreExceptionState(cx, state); return buf; }
const char* jsd_GetValueFunctionName(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JSFunction* fun; JSExceptionState* exceptionState; if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval)) { JS_BeginRequest(cx); exceptionState = JS_SaveExceptionState(cx); fun = JS_ValueToFunction(cx, jsdval->val); JS_RestoreExceptionState(cx, exceptionState); JS_EndRequest(cx); if(!fun) return NULL; jsdval->funName = JS_GetFunctionName(fun); } return jsdval->funName; }
JSBool xpc_DumpJSStack(JSContext* cx, JSBool showArgs, JSBool showLocals, JSBool showThisProps) { char* buf; JSExceptionState *state = JS_SaveExceptionState(cx); if(!state) puts("Call to a debug function modifying state!"); JS_ClearPendingException(cx); buf = FormatJSStackDump(cx, nsnull, showArgs, showLocals, showThisProps); if(buf) { fputs(buf, stdout); JS_smprintf_free(buf); } else puts("Failed to format JavaScript stack for dump"); JS_RestoreExceptionState(cx, state); return JS_TRUE; }
JSDScript* jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; jsval val = jsdval->val; JSFunction* fun = NULL; JSExceptionState* exceptionState; JSScript* script = NULL; JSDScript* jsdscript; JSCrossCompartmentCall *call = NULL; if (!jsd_IsValueFunction(jsdc, jsdval)) return NULL; JS_BeginRequest(cx); call = JS_EnterCrossCompartmentCall(cx, JSVAL_TO_OBJECT(val)); if (!call) { JS_EndRequest(cx); return NULL; } exceptionState = JS_SaveExceptionState(cx); fun = JSD_GetValueFunction(jsdc, jsdval); JS_RestoreExceptionState(cx, exceptionState); if (fun) script = JS_GetFunctionScript(cx, fun); JS_LeaveCrossCompartmentCall(call); JS_EndRequest(cx); if (!script) return NULL; JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindJSDScript(jsdc, script); JSD_UNLOCK_SCRIPTS(jsdc); return jsdscript; }
JSBool jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; jsval val = jsdval->val; JSFunction* fun; JSExceptionState* exceptionState; if(jsd_IsValueFunction(jsdc, jsdval)) { JSBool ok = JS_FALSE; JS_BeginRequest(cx); exceptionState = JS_SaveExceptionState(cx); fun = JS_ValueToFunction(cx, val); JS_RestoreExceptionState(cx, exceptionState); if(fun) ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE; JS_EndRequest(cx); JS_ASSERT(fun); return ok; } return !JSVAL_IS_PRIMITIVE(val); }
/* Checks whether an object has a property; unlike JS_GetProperty(), * never sets an exception. Treats a property with a value of JSVAL_VOID * the same as an absent property and returns false in both cases. * Always initializes *value_p, if only to JSVAL_VOID, even if it * returns FALSE. */ gboolean gjs_object_get_property(JSContext *context, JSObject *obj, const char *property_name, jsval *value_p) { jsval value; JSExceptionState *state; JS_BeginRequest(context); value = JSVAL_VOID; state = JS_SaveExceptionState(context); JS_GetProperty(context, obj, property_name, &value); JS_RestoreExceptionState(context, state); if (value_p) *value_p = value; JS_EndRequest(context); return value != JSVAL_VOID; }
JSBool jsd_EvaluateScriptInStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDStackFrameInfo* jsdframe, const char *bytes, uintN length, const char *filename, uintN lineno, JSBool eatExceptions, jsval *rval) { JSBool retval; JSBool valid; JSExceptionState* exceptionState = NULL; JSContext *cx; JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread); JSD_LOCK_THREADSTATES(jsdc); valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe); JSD_UNLOCK_THREADSTATES(jsdc); if (!valid) return JS_FALSE; cx = jsdthreadstate->context; JS_ASSERT(cx); if (eatExceptions) exceptionState = JS_SaveExceptionState(cx); JS_ClearPendingException(cx); jsd_StartingEvalUsingFilename(jsdc, filename); retval = JS_EvaluateInStackFrame(cx, jsdframe->fp, bytes, length, filename, lineno, rval); jsd_FinishedEvalUsingFilename(jsdc, filename); if (eatExceptions) JS_RestoreExceptionState(cx, exceptionState); return retval; }
static JSBool InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, JSString *filename, uintN lineno, JSErrorReport *report) { JSCheckAccessOp checkAccess; JSErrorReporter older; JSExceptionState *state; jsval callerid, v; JSStackFrame *fp, *fpstop; size_t stackDepth, valueCount, size; JSBool overflow; JSExnPrivate *priv; JSStackTraceElem *elem; jsval *values; JS_ASSERT(OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass); /* * Prepare stack trace data. * * Set aside any error reporter for cx and save its exception state * so we can suppress any checkAccess failures. Such failures should stop * the backtrace procedure, not result in a failure of this constructor. */ checkAccess = cx->runtime->checkObjectAccess; older = JS_SetErrorReporter(cx, NULL); state = JS_SaveExceptionState(cx); callerid = ATOM_KEY(cx->runtime->atomState.callerAtom); stackDepth = 0; valueCount = 0; for (fp = cx->fp; fp; fp = fp->down) { if (fp->fun && fp->argv) { v = JSVAL_NULL; if (checkAccess && !checkAccess(cx, fp->callee, callerid, JSACC_READ, &v)) { break; } valueCount += fp->argc; } ++stackDepth; } JS_RestoreExceptionState(cx, state); JS_SetErrorReporter(cx, older); fpstop = fp; size = offsetof(JSExnPrivate, stackElems); overflow = (stackDepth > ((size_t)-1 - size) / sizeof(JSStackTraceElem)); size += stackDepth * sizeof(JSStackTraceElem); overflow |= (valueCount > ((size_t)-1 - size) / sizeof(jsval)); size += valueCount * sizeof(jsval); if (overflow) { js_ReportAllocationOverflow(cx); return JS_FALSE; } priv = (JSExnPrivate *)JS_malloc(cx, size); if (!priv) return JS_FALSE; /* * We initialize errorReport with a copy of report after setting the * private slot, to prevent GC accessing a junk value we clear the field * here. */ priv->errorReport = NULL; priv->message = message; priv->filename = filename; priv->lineno = lineno; priv->stackDepth = stackDepth; values = GetStackTraceValueBuffer(priv); elem = priv->stackElems; for (fp = cx->fp; fp != fpstop; fp = fp->down) { if (!fp->fun) { elem->funName = NULL; elem->argc = 0; } else { elem->funName = fp->fun->atom ? ATOM_TO_STRING(fp->fun->atom) : cx->runtime->emptyString; elem->argc = fp->argc; memcpy(values, fp->argv, fp->argc * sizeof(jsval)); values += fp->argc; } elem->ulineno = 0; elem->filename = NULL; if (fp->script) { elem->filename = fp->script->filename; if (fp->regs) elem->ulineno = js_PCToLineNumber(cx, fp->script, fp->regs->pc); } ++elem; } JS_ASSERT(priv->stackElems + stackDepth == elem); JS_ASSERT(GetStackTraceValueBuffer(priv) + valueCount == values); STOBJ_SET_SLOT(exnObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(priv)); 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 * JSTokenStream. */ priv->errorReport = CopyErrorReport(cx, report); if (!priv->errorReport) { /* The finalizer realeases priv since it is in the private slot. */ return JS_FALSE; } } return JS_TRUE; }
static JSBool InitExceptionObject(JSContext *cx, JSObject *obj, JSString *message, JSString *filename, uintN lineno) { JSCheckAccessOp checkAccess; JSErrorReporter older; JSExceptionState *state; jschar *stackbuf; size_t stacklen, stackmax; JSStackFrame *fp; jsval callerid, v; JSBool ok; JSString *argsrc, *stack; uintN i, ulineno; const char *cp; char ulnbuf[11]; if (!JS_DefineProperty(cx, obj, js_message_str, STRING_TO_JSVAL(message), NULL, NULL, JSPROP_ENUMERATE)) { return JS_FALSE; } if (!JS_DefineProperty(cx, obj, js_filename_str, STRING_TO_JSVAL(filename), NULL, NULL, JSPROP_ENUMERATE)) { return JS_FALSE; } if (!JS_DefineProperty(cx, obj, js_lineno_str, INT_TO_JSVAL(lineno), NULL, NULL, JSPROP_ENUMERATE)) { return JS_FALSE; } /* * Set the 'stack' property. * * First, set aside any error reporter for cx and save its exception state * so we can suppress any checkAccess failures. Such failures should stop * the backtrace procedure, not result in a failure of this constructor. */ checkAccess = cx->runtime->checkObjectAccess; if (checkAccess) { older = JS_SetErrorReporter(cx, NULL); state = JS_SaveExceptionState(cx); } #ifdef __GNUC__ /* suppress bogus gcc warnings */ else { older = NULL; state = NULL; } #endif callerid = ATOM_KEY(cx->runtime->atomState.callerAtom); /* * Prepare to allocate a jschar buffer at stackbuf, where stacklen indexes * the next free jschar slot, and with room for at most stackmax non-null * jschars. If stackbuf is non-null, it always contains an extra slot for * the null terminator we'll store at the end, as a backstop. * * All early returns must goto done after this point, till the after-loop * cleanup code has run! */ stackbuf = NULL; stacklen = stackmax = 0; ok = JS_TRUE; #define APPEND_CHAR_TO_STACK(c) \ JS_BEGIN_MACRO \ if (stacklen == stackmax) { \ void *ptr_; \ stackmax = stackmax ? 2 * stackmax : 64; \ ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \ if (!ptr_) { \ ok = JS_FALSE; \ goto done; \ } \ stackbuf = ptr_; \ } \ stackbuf[stacklen++] = (c); \ JS_END_MACRO #define APPEND_STRING_TO_STACK(str) \ JS_BEGIN_MACRO \ JSString *str_ = str; \ size_t length_ = JSSTRING_LENGTH(str_); \ if (stacklen + length_ > stackmax) { \ void *ptr_; \ stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \ ptr_ = JS_realloc(cx, stackbuf, (stackmax+1) * sizeof(jschar)); \ if (!ptr_) { \ ok = JS_FALSE; \ goto done; \ } \ stackbuf = ptr_; \ } \ js_strncpy(stackbuf + stacklen, JSSTRING_CHARS(str_), length_); \ stacklen += length_; \ JS_END_MACRO for (fp = cx->fp; fp; fp = fp->down) { if (checkAccess) { v = (fp->fun && fp->argv) ? fp->argv[-2] : JSVAL_NULL; if (!JSVAL_IS_PRIMITIVE(v)) { ok = checkAccess(cx, fp->fun->object, callerid, JSACC_READ, &v); if (!ok) { ok = JS_TRUE; break; } } } if (fp->fun) { if (fp->fun->atom) APPEND_STRING_TO_STACK(ATOM_TO_STRING(fp->fun->atom)); APPEND_CHAR_TO_STACK('('); for (i = 0; i < fp->argc; i++) { argsrc = js_ValueToSource(cx, fp->argv[i]); if (!argsrc) { ok = JS_FALSE; goto done; } if (i > 0) APPEND_CHAR_TO_STACK(','); APPEND_STRING_TO_STACK(argsrc); } APPEND_CHAR_TO_STACK(')'); } APPEND_CHAR_TO_STACK('@'); if (fp->script && fp->script->filename) { for (cp = fp->script->filename; *cp; cp++) APPEND_CHAR_TO_STACK(*cp); } APPEND_CHAR_TO_STACK(':'); if (fp->script && fp->pc) { ulineno = js_PCToLineNumber(fp->script, fp->pc); JS_snprintf(ulnbuf, sizeof ulnbuf, "%u", ulineno); for (cp = ulnbuf; *cp; cp++) APPEND_CHAR_TO_STACK(*cp); } else { APPEND_CHAR_TO_STACK('0'); } APPEND_CHAR_TO_STACK('\n'); } #undef APPEND_CHAR_TO_STACK #undef APPEND_STRING_TO_STACK done: if (checkAccess) { if (ok) JS_RestoreExceptionState(cx, state); else JS_DropExceptionState(cx, state); JS_SetErrorReporter(cx, older); } if (!ok) { JS_free(cx, stackbuf); return JS_FALSE; } if (!stackbuf) { stack = cx->runtime->emptyString; } else { /* NB: if stackbuf was allocated, it has room for the terminator. */ JS_ASSERT(stacklen <= stackmax); if (stacklen < stackmax) { /* * Realloc can fail when shrinking on some FreeBSD versions, so * don't use JS_realloc here; simply let the oversized allocation * be owned by the string in that rare case. */ void *shrunk = realloc(stackbuf, (stacklen+1) * sizeof(jschar)); if (shrunk) stackbuf = shrunk; } stackbuf[stacklen] = 0; stack = js_NewString(cx, stackbuf, stacklen, 0); if (!stack) { JS_free(cx, stackbuf); return JS_FALSE; } } return JS_DefineProperty(cx, obj, js_stack_str, STRING_TO_JSVAL(stack), NULL, NULL, JSPROP_ENUMERATE); }
/* void CompileFile (in nsILocalFile aFile, in PRBool strict); */ NS_IMETHODIMP nsXPCToolsCompiler::CompileFile(nsILocalFile *aFile, PRBool strict) { // use the xpccallcontext stuff to get the current JSContext // get the xpconnect service nsresult rv; nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); if(NS_FAILED(rv)) return NS_ERROR_FAILURE; // get the xpconnect native call context nsCOMPtr<nsIXPCNativeCallContext> callContext; xpc->GetCurrentNativeCallContext(getter_AddRefs(callContext)); if(!callContext) return NS_ERROR_FAILURE; // verify that we are being called from JS (i.e. the current call is // to this object - though we don't verify that it is to this exact method) nsCOMPtr<nsISupports> callee; callContext->GetCallee(getter_AddRefs(callee)); if(!callee || callee.get() != (nsISupports*)this) return NS_ERROR_FAILURE; // Get JSContext of current call JSContext* cx; rv = callContext->GetJSContext(&cx); if(NS_FAILED(rv) || !cx) return NS_ERROR_FAILURE; FILE* handle; if(NS_FAILED(aFile->OpenANSIFileDesc("r", &handle))) return NS_ERROR_FAILURE; JSObject* glob = JS_NewObject(cx, &global_class, NULL, NULL); if (!glob) return NS_ERROR_FAILURE; if (!JS_InitStandardClasses(cx, glob)) return NS_ERROR_FAILURE; nsCAutoString path; if(NS_FAILED(aFile->GetNativePath(path))) return NS_ERROR_FAILURE; uint32 oldoptions = JS_GetOptions(cx); JS_SetOptions(cx, JSOPTION_WERROR | (strict ? JSOPTION_STRICT : 0)); JSErrorReporter older = JS_SetErrorReporter(cx, ErrorReporter); JSExceptionState *es =JS_SaveExceptionState(cx); if(!JS_CompileFileHandle(cx, glob, path.get(), handle)) { jsval v; JSErrorReport* report; if(JS_GetPendingException(cx, &v) && nsnull != (report = JS_ErrorFromException(cx, v))) { JSString* str; const char* msg = "Error"; str = JS_ValueToString(cx, v); if(str) msg = JS_GetStringBytes(str); printf("%s [%s,%d]\n\n", msg, report->filename, (int)report->lineno); } else { printf("no script and no error report!\n"); } } JS_RestoreExceptionState(cx, es); JS_SetErrorReporter(cx, older); JS_SetOptions(cx, oldoptions); return NS_OK; }