JSBool report_ruby_error_in_js(JohnsonRuntime* runtime, int state, VALUE old_errinfo) { JSContext * context = johnson_get_current_context(runtime); assert(state); switch (state) { case TAG_RAISE: { VALUE local_error = ruby_errinfo; jsval js_err; ruby_errinfo = old_errinfo; if (!convert_to_js(runtime, local_error, &js_err)) return JS_FALSE; JS_SetPendingException(context, js_err); return JS_FALSE; } case TAG_THROW: // FIXME: This should be propagated to JS... as an exception? default: { JSString* str = JS_NewStringCopyZ(context, "Unexpected longjmp from ruby!"); if (str) JS_SetPendingException(context, STRING_TO_JSVAL(str)); return JS_FALSE; } } }
JSBool gjs_move_exception(JSContext *src_context, JSContext *dest_context) { JSBool success; JS_BeginRequest(src_context); JS_BeginRequest(dest_context); /* NOTE: src and dest could be the same. */ jsval exc; if (JS_GetPendingException(src_context, &exc)) { if (src_context != dest_context) { /* try to add the current stack of dest_context to the * stack trace of exc */ try_to_chain_stack_trace(src_context, dest_context, exc); /* move the exception to dest_context */ JS_SetPendingException(dest_context, exc); JS_ClearPendingException(src_context); } success = JS_TRUE; } else { success = JS_FALSE; } JS_EndRequest(dest_context); JS_EndRequest(src_context); return success; }
/* void throwArg (); */ NS_IMETHODIMP xpctestEcho::ThrowArg(void) { GET_CALL_CONTEXT; if(NS_FAILED(rv) || !cc) return NS_ERROR_FAILURE; nsCOMPtr<nsISupports> callee; if(NS_FAILED(cc->GetCallee(getter_AddRefs(callee))) || callee != static_cast<nsIEcho*>(this)) return NS_ERROR_FAILURE; PRUint32 argc; if(NS_FAILED(cc->GetArgc(&argc)) || !argc) return NS_OK; jsval* argv; JSContext* cx; if(NS_FAILED(cc->GetArgvPtr(&argv)) || NS_FAILED(cc->GetJSContext(&cx))) return NS_ERROR_FAILURE; JS_SetPendingException(cx, argv[0]); return NS_OK; }
JSBool report_ruby_error_in_js(JohnsonRuntime* runtime, int state, VALUE old_errinfo) { JSContext * context = johnson_get_current_context(runtime); assert(state); switch (state) { case TAG_RAISE: { VALUE local_error = ruby_errinfo; ruby_errinfo = old_errinfo; local_error = rb_funcall(local_error, rb_intern("inspect"), 0); JS_ReportError(context, StringValuePtr(local_error)); return JS_FALSE ; } case TAG_THROW: // FIXME: This should be propagated to JS... as an exception? default: { JSString* str = JS_NewStringCopyZ(context, "Unexpected longjmp from ruby!"); if (str) JS_SetPendingException(context, STRING_TO_JSVAL(str)); return JS_FALSE; } } }
/* * Common subroutine of generator_(next|send|throw|close) methods. */ static JSBool generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp, uintN argc) { JSObject *obj; JSGenerator *gen; jsval arg; obj = JS_THIS_OBJECT(cx, vp); if (!JS_InstanceOf(cx, obj, &js_GeneratorClass, vp + 2)) return JS_FALSE; gen = (JSGenerator *) JS_GetPrivate(cx, obj); if (gen == NULL) { /* This happens when obj is the generator prototype. See bug 352885. */ goto closed_generator; } if (gen->state == JSGEN_NEWBORN) { switch (op) { case JSGENOP_NEXT: case JSGENOP_THROW: break; case JSGENOP_SEND: if (argc >= 1 && !JSVAL_IS_VOID(vp[2])) { js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND, JSDVG_SEARCH_STACK, vp[2], NULL); return JS_FALSE; } break; default: JS_ASSERT(op == JSGENOP_CLOSE); gen->state = JSGEN_CLOSED; return JS_TRUE; } } else if (gen->state == JSGEN_CLOSED) { closed_generator: switch (op) { case JSGENOP_NEXT: case JSGENOP_SEND: return js_ThrowStopIteration(cx); case JSGENOP_THROW: JS_SetPendingException(cx, argc >= 1 ? vp[2] : JSVAL_VOID); return JS_FALSE; default: JS_ASSERT(op == JSGENOP_CLOSE); return JS_TRUE; } } arg = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0) ? vp[2] : JSVAL_VOID; if (!SendToGenerator(cx, op, obj, gen, arg)) return JS_FALSE; *vp = gen->frame.rval; return JS_TRUE; }
// static JSBool XPCThrower::ThrowExceptionObject(JSContext* cx, nsIException* e) { JSBool success = JS_FALSE; if(e) { nsCOMPtr<nsIXPCException> xpcEx; jsval thrown; nsXPConnect* xpc; // If we stored the original thrown JS value in the exception // (see XPCConvert::ConstructException) and we are in a web // context (i.e., not chrome), rethrow the original value. if(!IsCallerChrome(cx) && (xpcEx = do_QueryInterface(e)) && NS_SUCCEEDED(xpcEx->StealJSVal(&thrown))) { if (!JS_WrapValue(cx, &thrown)) return JS_FALSE; JS_SetPendingException(cx, thrown); success = JS_TRUE; } else if((xpc = nsXPConnect::GetXPConnect())) { JSObject* glob = JS_GetScopeChain(cx); if(!glob) return JS_FALSE; glob = JS_GetGlobalForObject(cx, glob); nsCOMPtr<nsIXPConnectJSObjectHolder> holder; nsresult rv = xpc->WrapNative(cx, glob, e, NS_GET_IID(nsIException), getter_AddRefs(holder)); if(NS_SUCCEEDED(rv) && holder) { JSObject* obj; if(NS_SUCCEEDED(holder->GetJSObject(&obj))) { JS_SetPendingException(cx, OBJECT_TO_JSVAL(obj)); success = JS_TRUE; } } } } return success; }
/* * Class: com_google_gwt_dev_shell_moz_LowLevelMoz * Method: _raiseJavaScriptException * Signature: ()Z */ extern "C" JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1raiseJavaScriptException (JNIEnv* env, jclass) { Tracer tracer("LowLevelMoz._raiseJavaScriptException"); JS_SetPendingException(JsRootedValue::currentContext(), JSVAL_NULL); return JNI_TRUE; }
void AutoJSAPI::ReportException() { MOZ_ASSERT(OwnsErrorReporting(), "This is not our exception to report!"); if (!HasException()) { return; } // AutoJSAPI uses a JSAutoNullableCompartment, and may be in a null // compartment when the destructor is called. However, the JS engine // requires us to be in a compartment when we fetch the pending exception. // In this case, we enter the privileged junk scope and don't dispatch any // error events. JS::Rooted<JSObject*> errorGlobal(cx(), JS::CurrentGlobalOrNull(cx())); if (!errorGlobal) { if (mIsMainThread) { errorGlobal = xpc::PrivilegedJunkScope(); } else { errorGlobal = workers::GetCurrentThreadWorkerGlobal(); } } JSAutoCompartment ac(cx(), errorGlobal); JS::Rooted<JS::Value> exn(cx()); js::ErrorReport jsReport(cx()); if (StealException(&exn) && jsReport.init(cx(), exn)) { if (mIsMainThread) { RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport(); RefPtr<nsGlobalWindow> win = xpc::WindowGlobalOrNull(errorGlobal); nsPIDOMWindowInner* inner = win ? win->AsInner() : nullptr; xpcReport->Init(jsReport.report(), jsReport.message(), nsContentUtils::IsCallerChrome(), inner ? inner->WindowID() : 0); if (inner) { DispatchScriptErrorEvent(inner, JS_GetRuntime(cx()), xpcReport, exn); } else { xpcReport->LogToConsole(); } } else { // On a worker, we just use the worker error reporting mechanism and don't // bother with xpc::ErrorReport. This will ensure that all the right // events (which are a lot more complicated than in the window case) get // fired. workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); MOZ_ASSERT(worker->GetJSContext() == cx()); // Before invoking ReportError, put the exception back on the context, // because it may want to put it in its error events and has no other way // to get hold of it. After we invoke ReportError, clear the exception on // cx(), just in case ReportError didn't. JS_SetPendingException(cx(), exn); worker->ReportError(cx(), jsReport.message(), jsReport.report()); ClearException(); } } else { NS_WARNING("OOMed while acquiring uncaught exception from JSAPI"); ClearException(); } }
JSBool js_ThrowStopIteration(JSContext *cx) { jsval v; JS_ASSERT(!JS_IsExceptionPending(cx)); if (js_FindClassObject(cx, NULL, INT_TO_JSID(JSProto_StopIteration), &v)) JS_SetPendingException(cx, v); return JS_FALSE; }
void ThrowDOMExceptionForNSResult(JSContext* aCx, nsresult aNSResult) { JSObject* exception = DOMException::Create(aCx, aNSResult); if (!exception) { return; } JS_SetPendingException(aCx, OBJECT_TO_JSVAL(exception)); }
static JSBool DriverManager_getConnection(JSContext *cx, unsigned argc, jsval *vp) { jsval drivers; JS_LookupProperty(cx, JS_THIS_OBJECT(cx, vp), "drivers", &drivers); // FIXME check return code; check that drivers is an array JSObject *obj = JSVAL_TO_OBJECT(drivers); uint32_t len, i; JS_GetArrayLength(cx, obj, &len); jsval connect_argv[2] = {JS_ARGV(cx, vp)[0]}; if (argc == 2) { /* Caller passed "info" object, so we forward it as-is */ connect_argv[1] = JS_ARGV(cx, vp)[1]; } else { JSObject *info = JS_NewObject(cx, NULL, NULL, NULL); // FIXME root it to avoid GC if (argc > 1) JS_DefineProperty(cx, info, "user", JS_ARGV(cx, vp)[1], NULL, NULL, JSPROP_ENUMERATE); if (argc > 2) JS_DefineProperty(cx, info, "password", JS_ARGV(cx, vp)[2], NULL, NULL, JSPROP_ENUMERATE); connect_argv[1] = OBJECT_TO_JSVAL(info); }; jsval reason = JSVAL_NULL; for (i = 0; i < len; i++) { jsval driver, rval; JS_GetElement(cx, obj, i, &driver); if (!JS_CallFunctionName(cx, JSVAL_TO_OBJECT(driver), "connect", 2, &connect_argv[0], &rval)) { if (JSVAL_IS_NULL(reason)) JS_GetPendingException(cx, &reason); continue; } if (JSVAL_IS_NULL(rval)) continue; JS_SET_RVAL(cx, vp, rval); return JS_TRUE; } if (JSVAL_IS_NULL(reason)) { JSString *url_str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]); // FIXME check return value // FIXME root url_str (protect from GC) -> https://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JS_ValueToString char *url = JS_EncodeString(cx, url_str); JS_ReportError(cx, "No suitable driver found for %s", url); JS_free(cx, url); } else JS_SetPendingException(cx, reason); JS_SET_RVAL(cx, vp, JSVAL_NULL); return JS_FALSE; }
void ScriptInterface::ReportError(const char* msg) { // JS_ReportError by itself doesn't seem to set a JS-style exception, and so // script callers will be unable to catch anything. So use JS_SetPendingException // to make sure there really is a script-level exception. But just set it to undefined // because there's not much value yet in throwing a real exception object. JS_SetPendingException(m->m_cx, JSVAL_VOID); // And report the actual error JS_ReportError(m->m_cx, "%s", msg); // TODO: Why doesn't JS_ReportPendingException(m->m_cx); work? }
static void js_txn_deadlock(JSContext *cx, js_db_t *jd) { if(JS_IsExceptionPending(cx)) return; if(jd->jd_debug) TRACE(TRACE_DEBUG, "JS", "Raising deadlock exception"); JSObject *obj = JS_NewObjectWithGivenProto(cx, &db_deadlock_exn, NULL, NULL); JS_SetPendingException(cx, OBJECT_TO_JSVAL(obj)); }
/** * Calls a method on a Java object and returns a two-element JS array, with * the first element being a boolean flag indicating an exception was thrown, * and the second element is the actual return value or exception. */ JSBool JavaObject::invokeJava(JSContext* ctx, SessionData* data, const gwt::Value& javaThis, int dispId, int numArgs, const jsval* jsargs, jsval* rval) { HostChannel* channel = data->getHostChannel(); SessionHandler* handler = data->getSessionHandler(); scoped_array<gwt::Value> args(new gwt::Value[numArgs]); for (int i = 0; i < numArgs; ++i) { data->makeValueFromJsval(args[i], ctx, jsargs[i]); } bool isException = false; gwt::Value returnValue; if (!InvokeMessage::send(*channel, javaThis, dispId, numArgs, args.get())) { Debug::log(Debug::Debugging) << "JavaObject::call failed to send invoke message" << Debug::flush; } else { Debug::log(Debug::Spam) << " return from invoke" << Debug::flush; scoped_ptr<ReturnMessage> retMsg(channel->reactToMessagesWhileWaitingForReturn(handler)); if (!retMsg.get()) { Debug::log(Debug::Debugging) << "JavaObject::call failed to get return value" << Debug::flush; } else { isException = retMsg->isException(); returnValue = retMsg->getReturnValue(); } } // Since we can set exceptions normally, we always return false to the // wrapper function and set the exception ourselves if one occurs. // TODO: cleanup exception case jsval retvalArray[] = {JSVAL_FALSE, JSVAL_VOID}; JSObject* retval = JS_NewArrayObject(ctx, 2, retvalArray); *rval = OBJECT_TO_JSVAL(retval); jsval retJsVal; Debug::log(Debug::Spam) << " result is " << returnValue << Debug::flush; data->makeJsvalFromValue(retJsVal, ctx, returnValue); if (isException) { JS::MutableHandleValue argHandle = JS::MutableHandleValue::fromMarkedLocation(&retJsVal); JS_SetPendingException(ctx, argHandle); return false; } #if GECKO_VERSION >= 26000 JS::Rooted<JS::Value> tmp(ctx); tmp = retJsVal; #else jsval tmp = retJsVal; #endif if (!JS_SetElement(ctx, retval, 1, &tmp)) { Debug::log(Debug::Error) << "Error setting return value element in array" << Debug::flush; return false; } return true; }
JSBool jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate, JSDValue* jsdval) { JSContext* cx; if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate))) return JS_FALSE; if(jsdval) JS_SetPendingException(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval)); else JS_ClearPendingException(cx); return JS_TRUE; }
/* void CanAccess (in PRUint32 aAction, in nsIXPCNativeCallContext aCallContext, in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in nsISupports aObj, in nsIClassInfo aClassInfo, in jsid aName, inout voidPtr aPolicy); */ NS_IMETHODIMP MySecMan::CanAccess(PRUint32 aAction, nsAXPCNativeCallContext *aCallContext, JSContext * aJSContext, JSObject * aJSObject, nsISupports *aObj, nsIClassInfo *aClassInfo, jsid aName, void * *aPolicy) { switch(mMode) { case OK_ALL: return NS_OK; case VETO_ALL: JS_SetPendingException(aJSContext, STRING_TO_JSVAL(JS_NewStringCopyZ(aJSContext, "security exception"))); return NS_ERROR_FAILURE; default: NS_ERROR("bad case"); return NS_OK; } }
NS_IMETHODIMP MySecMan::CanGetService(JSContext * aJSContext, const nsCID & aCID) { switch(mMode) { case OK_ALL: return NS_OK; case VETO_ALL: JS_SetPendingException(aJSContext, STRING_TO_JSVAL(JS_NewStringCopyZ(aJSContext, "security exception"))); return NS_ERROR_FAILURE; default: NS_ERROR("bad case"); return NS_OK; } }
NS_IMETHODIMP MySecMan::CanCreateWrapper(JSContext * aJSContext, const nsIID & aIID, nsISupports *aObj, nsIClassInfo *aClassInfo, void * *aPolicy) { switch(mMode) { case OK_ALL: return NS_OK; case VETO_ALL: JS_SetPendingException(aJSContext, STRING_TO_JSVAL(JS_NewStringCopyZ(aJSContext, "security exception"))); return NS_ERROR_FAILURE; default: NS_ERROR("bad case"); return NS_OK; } }
/** * gjs_throw_g_error: * * Convert a GError into a JavaScript Exception, and * frees the GError. Differently from gjs_throw(), it * will overwrite an existing exception, as it is used * to report errors from C functions. */ void gjs_throw_g_error (JSContext *context, GError *error) { JSObject *err_obj; if (error == NULL) return; JS_BeginRequest(context); err_obj = gjs_error_from_gerror(context, error, TRUE); if (err_obj) JS_SetPendingException(context, OBJECT_TO_JSVAL(err_obj)); JS_EndRequest(context); }
void propagate2JS( pTHX_ PJS_Context *pcx, JSObject *obj ) { JSContext *cx = PJS_getJScx(pcx); if(PJS_getFlag(pcx, "ReflectExceptions")) { jsval rval; SV* cp = newSVsv(ERRSV); if(!PJS_ReflectPerl2JS(aTHX_ cx, obj, cp, &rval)) croak("Can't convert perl error into JSVAL"); JS_SetPendingException(cx, rval); sv_setsv(ERRSV, &PL_sv_undef); sv_free(cp); } else { JS_ClearPendingException(cx); } }
END_FUNCTION_SPEC END_CLASS NEVER_INLINE bool FASTCALL ThrowIoErrorArg( JSContext *cx, PRErrorCode errorCode, PRInt32 osError ) { JS::RootedObject error(cx, jl::newObjectWithGivenProto( cx, JL_CLASS(IoError), JL_CLASS_PROTOTYPE(cx, IoError))); JS::RootedValue tmp(cx); JL_ASSERT_ALLOC( error ); tmp.setObject(*error); JS_SetPendingException( cx, tmp ); tmp.setInt32(errorCode); JL_CHK( JL_SetReservedSlot( error, 0, tmp ) ); tmp.setInt32(osError); JL_CHK( JL_SetReservedSlot( error, 1, tmp ) ); JL_SAFE( jl::addScriptLocation(cx, &error) ); JL_BAD; }
JSBool js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp) { JSErrNum errorNumber; const JSErrorFormatString *errorString; JSExnType exn; jsval tv[4]; JSTempValueRooter tvr; JSBool ok; JSObject *errProto, *errObject; JSString *messageStr, *filenameStr; /* * Tell our caller to report immediately if cx has no active frames, or if * this report is just a warning. */ JS_ASSERT(reportp); if (!cx->fp || JSREPORT_IS_WARNING(reportp->flags)) return JS_FALSE; /* Find the exception index associated with this error. */ errorNumber = (JSErrNum) reportp->errorNumber; errorString = js_GetLocalizedErrorMessage(cx, NULL, NULL, errorNumber); exn = errorString ? (JSExnType) errorString->exnType : JSEXN_NONE; JS_ASSERT(exn < JSEXN_LIMIT); #if defined( DEBUG_mccabe ) && defined ( PRINTNAMES ) /* Print the error name and the associated exception name to stderr */ fprintf(stderr, "%s\t%s\n", errortoexnname[errorNumber].name, errortoexnname[errorNumber].exception); #endif /* * Return false (no exception raised) if no exception is associated * with the given error number. */ if (exn == JSEXN_NONE) return JS_FALSE; /* * Prevent runaway recursion, via cx->generatingError. If an out-of-memory * error occurs, no exception object will be created, but we don't assume * that OOM is the only kind of error that subroutines of this function * called below might raise. */ if (cx->generatingError) return JS_FALSE; /* After this point the control must flow through the label out. */ cx->generatingError = JS_TRUE; /* Protect the newly-created strings below from nesting GCs. */ memset(tv, 0, sizeof tv); JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(tv), tv, &tvr); /* * Try to get an appropriate prototype by looking up the corresponding * exception constructor name in the scope chain of the current context's * top stack frame, or in the global object if no frame is active. */ ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(exceptions[exn].key), &errProto); if (!ok) goto out; tv[0] = OBJECT_TO_JSVAL(errProto); errObject = js_NewObject(cx, &js_ErrorClass, errProto, NULL, 0); if (!errObject) { ok = JS_FALSE; goto out; } tv[1] = OBJECT_TO_JSVAL(errObject); messageStr = JS_NewStringCopyZ(cx, message); if (!messageStr) { ok = JS_FALSE; goto out; } tv[2] = STRING_TO_JSVAL(messageStr); filenameStr = JS_NewStringCopyZ(cx, reportp->filename); if (!filenameStr) { ok = JS_FALSE; goto out; } tv[3] = STRING_TO_JSVAL(filenameStr); ok = InitExnPrivate(cx, errObject, messageStr, filenameStr, reportp->lineno, reportp); if (!ok) goto out; JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject)); /* Flag the error report passed in to indicate an exception was raised. */ reportp->flags |= JSREPORT_EXCEPTION; out: JS_POP_TEMP_ROOT(cx, &tvr); cx->generatingError = JS_FALSE; return ok; }
void gjstest_test_func_gjs_jsapi_util_error_throw(void) { GjsUnitTestFixture fixture; JSContext *context; jsval exc, value, previous; char *s = NULL; int strcmp_result; _gjs_unit_test_fixture_begin(&fixture); context = fixture.context; /* Test that we can throw */ gjs_throw(context, "This is an exception %d", 42); g_assert(JS_IsExceptionPending(context)); exc = JSVAL_VOID; JS_GetPendingException(context, &exc); g_assert(!JSVAL_IS_VOID(exc)); value = JSVAL_VOID; JS_GetProperty(context, JSVAL_TO_OBJECT(exc), "message", &value); g_assert(JSVAL_IS_STRING(value)); gjs_string_get_binary_data (context, value, &s, NULL); g_assert(s != NULL); strcmp_result = strcmp(s, "This is an exception 42"); free(s); if (strcmp_result != 0) g_error("Exception has wrong message '%s'", s); /* keep this around before we clear it */ previous = exc; JS_AddValueRoot(context, &previous); JS_ClearPendingException(context); g_assert(!JS_IsExceptionPending(context)); /* Check that we don't overwrite a pending exception */ JS_SetPendingException(context, previous); g_assert(JS_IsExceptionPending(context)); gjs_throw(context, "Second different exception %s", "foo"); g_assert(JS_IsExceptionPending(context)); exc = JSVAL_VOID; JS_GetPendingException(context, &exc); g_assert(!JSVAL_IS_VOID(exc)); g_assert(exc == previous); JS_RemoveValueRoot(context, &previous); _gjs_unit_test_fixture_finish(&fixture); }
JSBool js_destroy(JSContext *context) { JS_SetPendingException(context, STRING_TO_JSVAL(JS_NewStringCopyZ(context, "timeout"))); return JS_FALSE; }
JSBool js_ReportUncaughtException(JSContext *cx) { jsval exn; JSObject *exnObject; jsval roots[5]; JSTempValueRooter tvr; JSErrorReport *reportp, report; JSString *str; const char *bytes; JSBool ok; if (!JS_IsExceptionPending(cx)) return JS_TRUE; if (!JS_GetPendingException(cx, &exn)) return JS_FALSE; memset(roots, 0, sizeof roots); JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); /* * Because js_ValueToString below could error and an exception object * could become unrooted, we must root exnObject. Later, if exnObject is * non-null, we need to root other intermediates, so allocate an operand * stack segment to protect all of these values. */ if (JSVAL_IS_PRIMITIVE(exn)) { exnObject = NULL; } else { exnObject = JSVAL_TO_OBJECT(exn); roots[0] = exn; } JS_ClearPendingException(cx); reportp = js_ErrorFromException(cx, exn); /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */ str = js_ValueToString(cx, exn); if (!str) { bytes = "unknown (can't convert to string)"; } else { roots[1] = STRING_TO_JSVAL(str); bytes = js_GetStringBytes(cx, str); if (!bytes) { ok = JS_FALSE; goto out; } } ok = JS_TRUE; if (!reportp && exnObject && OBJ_GET_CLASS(cx, exnObject) == &js_ErrorClass) { const char *filename; uint32 lineno; ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]); if (!ok) goto out; if (JSVAL_IS_STRING(roots[2])) { bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); if (!bytes) { ok = JS_FALSE; goto out; } } ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); if (!ok) goto out; str = js_ValueToString(cx, roots[3]); if (!str) { ok = JS_FALSE; goto out; } filename = StringToFilename(cx, str); if (!filename) { ok = JS_FALSE; goto out; } ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); if (!ok) goto out; lineno = js_ValueToECMAUint32 (cx, &roots[4]); ok = !JSVAL_IS_NULL(roots[4]); if (!ok) goto out; reportp = &report; memset(&report, 0, sizeof report); report.filename = filename; report.lineno = (uintN) lineno; } if (!reportp) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNCAUGHT_EXCEPTION, bytes); } else { /* Flag the error as an exception. */ reportp->flags |= JSREPORT_EXCEPTION; /* Pass the exception object. */ JS_SetPendingException(cx, exn); js_ReportErrorAgain(cx, bytes, reportp); JS_ClearPendingException(cx); } out: JS_POP_TEMP_ROOT(cx, &tvr); return ok; }
/* * This is a wrapper around JS_ReportError(), useful when an error condition * is the result of a JVM failure or exception condition. It appends the * message associated with the pending Java exception to the passed in * printf-style format string and arguments. */ static void vreport_java_error(JSContext *cx, JNIEnv *jEnv, const char *format, va_list ap) { jobject java_obj; jclass java_class; JavaClassDescriptor *class_descriptor; jthrowable java_exception; JSType wrapped_exception_type; jsval js_exception; java_obj = NULL; class_descriptor = NULL; /* Get the exception out of the java environment. */ java_exception = (*jEnv)->ExceptionOccurred(jEnv); if (!java_exception) { JSString *err_jsstr; char *err = JS_vsmprintf(format, ap); if (!err) return; err_jsstr = JS_NewString(cx, err, strlen(err)); if (!err_jsstr) return; JS_SetPendingException(cx, STRING_TO_JSVAL(err_jsstr)); return; } (*jEnv)->ExceptionClear(jEnv); /* Check for JSException */ if (njJSException && (*jEnv)->IsInstanceOf(jEnv, java_exception, njJSException)) { wrapped_exception_type = (*jEnv)->GetIntField(jEnv, java_exception, njJSException_wrappedExceptionType); /* (int) to suppress warning */ if ((int)wrapped_exception_type != JSTYPE_EMPTY) { java_obj = (*jEnv)->GetObjectField(jEnv, java_exception, njJSException_wrappedException); if ((java_obj == NULL) && (wrapped_exception_type == JSTYPE_OBJECT)) { js_exception = JSVAL_NULL; } else { java_class = (*jEnv)->GetObjectClass(jEnv, java_obj); class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class); /* OK to delete ref, since above call adds global ref */ (*jEnv)->DeleteLocalRef(jEnv, java_class); /* Convert native JS values back to native types. */ switch(wrapped_exception_type) { case JSTYPE_NUMBER: if (!jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, &js_exception)) goto error; break; case JSTYPE_BOOLEAN: if (!jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, &js_exception)) goto error; break; case JSTYPE_STRING: if (!jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, &js_exception)) goto error; break; case JSTYPE_VOID: js_exception = JSVAL_VOID; break; case JSTYPE_OBJECT: case JSTYPE_FUNCTION: default: if ((*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) { js_exception = OBJECT_TO_JSVAL(jsj_UnwrapJSObjectWrapper(jEnv, java_obj)); if (!js_exception) goto error; } else { if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_exception)) goto error; } } } } /* Check for internal exception */ } else { if (!JSJ_ConvertJavaObjectToJSValue(cx, java_exception, &js_exception)) { goto error; } } /* Set pending JS exception and clear the java exception. */ JS_SetPendingException(cx, js_exception); goto done; error: JS_ASSERT(0); jsj_LogError("Out of memory while attempting to throw JSException\n"); done: if (class_descriptor) jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor); if (java_obj) (*jEnv)->DeleteLocalRef(jEnv, java_obj); if (java_exception) (*jEnv)->DeleteLocalRef(jEnv, java_exception); }
void _sptInvoker::_reportError( JSContext *cx, INT32 rc, const bson::BSONObj &detail ) { sdbSetErrno( rc ) ; if ( SDB_OK != rc ) { stringstream ss ; BSONObjIterator itr( detail) ; INT32 fieldNum = detail.nFields() ; INT32 count = 0 ; while ( itr.more() ) { if ( count > 0 ) { ss << ", " ; } BSONElement e = itr.next() ; if ( fieldNum > 1 || 0 != ossStrcmp( SPT_ERR, e.fieldName() ) ) { ss << e.fieldName() << ": " ; } if ( String == e.type() ) { ss << e.valuestr() ; } else if ( NumberInt == e.type() ) { ss << e.numberInt() ; } else if ( NumberLong == e.type() ) { ss << e.numberLong() ; } else if ( NumberDouble == e.type() ) { ss << e.numberDouble() ; } else if ( Bool == e.type() ) { ss << ( e.boolean() ? "true" : "false" ) ; } else { ss << e.toString( false, false ) ; } ++count ; } sdbSetErrMsg( ss.str().c_str() ) ; if ( sdbIsErrMsgEmpty() ) { sdbSetErrMsg( getErrDesp( rc ) ) ; } JS_SetPendingException( cx , INT_TO_JSVAL( rc ) ) ; } else { sdbSetErrMsg( NULL ) ; } return ; }
JSBool js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp) { JSErrNum errorNumber; JSExnType exn; JSBool ok; JSObject *errProto, *errObject; JSString *messageStr, *filenameStr; uintN lineno; JSExnPrivate *privateData; /* Find the exception index associated with this error. */ JS_ASSERT(reportp); if (JSREPORT_IS_WARNING(reportp->flags)) return JS_FALSE; errorNumber = (JSErrNum) reportp->errorNumber; exn = errorToExceptionNum[errorNumber]; JS_ASSERT(exn < JSEXN_LIMIT); #if defined( DEBUG_mccabe ) && defined ( PRINTNAMES ) /* Print the error name and the associated exception name to stderr */ fprintf(stderr, "%s\t%s\n", errortoexnname[errorNumber].name, errortoexnname[errorNumber].exception); #endif /* * Return false (no exception raised) if no exception is associated * with the given error number. */ if (exn == JSEXN_NONE) return JS_FALSE; /* * Prevent runaway recursion, just as the Exception native constructor * must do, via cx->creatingException. If an out-of-memory error occurs, * no exception object will be created, but we don't assume that OOM is * the only kind of error that subroutines of this function called below * might raise. */ if (cx->creatingException) return JS_FALSE; cx->creatingException = JS_TRUE; /* * Try to get an appropriate prototype by looking up the corresponding * exception constructor name in the scope chain of the current context's * top stack frame, or in the global object if no frame is active. * * XXXbe hack around JSCLASS_NEW_RESOLVE code in js_LookupProperty that * checks cx->fp, cx->fp->pc, and js_CodeSpec[*cx->fp->pc] in order * to compute resolve flags such as JSRESOLVE_ASSIGNING. The bug * is that this "internal" js_GetClassPrototype call may trigger a * resolve of exceptions[exn].name if the global object uses a lazy * standard class resolver (see JS_ResolveStandardClass), but the * current frame and bytecode end up affecting the resolve flags. */ { JSStackFrame *fp = cx->fp; jsbytecode *pc = NULL; if (fp) { pc = fp->pc; fp->pc = NULL; } ok = js_GetClassPrototype(cx, exceptions[exn].name, &errProto); if (pc) fp->pc = pc; if (!ok) goto out; } errObject = js_NewObject(cx, &ExceptionClass, errProto, NULL); if (!errObject) { ok = JS_FALSE; goto out; } messageStr = JS_NewStringCopyZ(cx, message); if (!messageStr) { ok = JS_FALSE; goto out; } if (reportp) { filenameStr = JS_NewStringCopyZ(cx, reportp->filename); if (!filenameStr) { ok = JS_FALSE; goto out; } lineno = reportp->lineno; } else { filenameStr = cx->runtime->emptyString; lineno = 0; } ok = InitExceptionObject(cx, errObject, messageStr, filenameStr, lineno); if (!ok) goto out; /* * Construct a new copy of the error report struct, and store it in the * exception object's private data. We can't use the error report struct * that was passed in, because it's stack-allocated, and also because it * may point to transient data in the JSTokenStream. */ privateData = exn_newPrivate(cx, reportp); if (!privateData) { ok = JS_FALSE; goto out; } OBJ_SET_SLOT(cx, errObject, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(privateData)); /* Set the generated Exception object as the current exception. */ JS_SetPendingException(cx, OBJECT_TO_JSVAL(errObject)); /* Flag the error report passed in to indicate an exception was raised. */ reportp->flags |= JSREPORT_EXCEPTION; out: cx->creatingException = JS_FALSE; return ok; }
/* * See: * https://bugzilla.mozilla.org/show_bug.cgi?id=166436 * https://bugzilla.mozilla.org/show_bug.cgi?id=215173 * * Very surprisingly, jsapi.h lacks any way to "throw new Error()" * * So here is an awful hack inspired by * http://egachine.berlios.de/embedding-sm-best-practice/embedding-sm-best-practice.html#error-handling */ static void gjs_throw_valist(JSContext *context, const char *error_class, const char *format, va_list args) { char *s; JSBool result; jsval v_constructor, v_message; JSObject *err_obj; s = g_strdup_vprintf(format, args); JS_BeginRequest(context); if (JS_IsExceptionPending(context)) { /* Often it's unclear whether a given jsapi.h function * will throw an exception, so we will throw ourselves * "just in case"; in those cases, we don't want to * overwrite an exception that already exists. * (Do log in case our second exception adds more info, * but don't log as topic ERROR because if the exception is * caught we don't want an ERROR in the logs.) */ gjs_debug(GJS_DEBUG_CONTEXT, "Ignoring second exception: '%s'", s); g_free(s); JS_EndRequest(context); return; } result = JS_FALSE; (void)JS_EnterLocalRootScope(context); if (!gjs_string_from_utf8(context, s, -1, &v_message)) { JS_ReportError(context, "Failed to copy exception string"); goto out; } if (!gjs_object_get_property(context, JS_GetGlobalObject(context), error_class, &v_constructor)) { JS_ReportError(context, "??? Missing Error constructor in global object?"); goto out; } /* throw new Error(message) */ err_obj = JS_New(context, JSVAL_TO_OBJECT(v_constructor), 1, &v_message); JS_SetPendingException(context, OBJECT_TO_JSVAL(err_obj)); result = JS_TRUE; out: JS_LeaveLocalRootScope(context); if (!result) { /* try just reporting it to error handler? should not * happen though pretty much */ JS_ReportError(context, "Failed to throw exception '%s'", s); } g_free(s); JS_EndRequest(context); }
static JSBool log_and_maybe_keep_exception(JSContext *context, char **message_p, gboolean keep) { jsval exc = JSVAL_VOID; JSString *s; char *message; JSBool retval = JS_FALSE; JS_BeginRequest(context); if (message_p) *message_p = NULL; JS_AddRoot(context, &exc); if (!JS_GetPendingException(context, &exc)) goto out; JS_ClearPendingException(context); s = JS_ValueToString(context, exc); if (s == NULL) { gjs_debug(GJS_DEBUG_ERROR, "Failed to convert exception to string"); goto out; /* Exception should be thrown already */ } if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(s), &message)) { gjs_debug(GJS_DEBUG_ERROR, "Failed to convert exception string to UTF-8"); goto out; /* Error already set */ } gjs_debug(GJS_DEBUG_ERROR, "Exception was: %s", message); if (message_p) { *message_p = message; } else { g_free(message); } gjs_log_exception_props(context, exc); /* We clear above and then set it back so any exceptions * from the logging process don't overwrite the original */ if (keep) JS_SetPendingException(context, exc); retval = JS_TRUE; out: JS_RemoveRoot(context, &exc); JS_EndRequest(context); return retval; }