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) errorGlobal = xpc::PrivilegedJunkScope(); JSAutoCompartment ac(cx(), errorGlobal); nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal); JS::Rooted<JS::Value> exn(cx()); js::ErrorReport jsReport(cx()); if (StealException(&exn) && jsReport.init(cx(), exn)) { nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport(); xpcReport->Init(jsReport.report(), jsReport.message(), nsContentUtils::IsCallerChrome(), win ? win->WindowID() : 0); if (win) { DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn); } else { xpcReport->LogToConsole(); } } else { NS_WARNING("OOMed while acquiring uncaught exception from JSAPI"); } }
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(); } }
AutoJSAPI::~AutoJSAPI() { if (mOwnErrorReporting) { MOZ_ASSERT(NS_IsMainThread(), "See corresponding assertion in TakeOwnershipOfErrorReporting()"); JS::ContextOptionsRef(cx()).setDontReportUncaught(mOldDontReportUncaught); if (HasException()) { // 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) errorGlobal = xpc::PrivilegedJunkScope(); JSAutoCompartment ac(cx(), errorGlobal); nsCOMPtr<nsPIDOMWindow> win = xpc::WindowGlobalOrNull(errorGlobal); const char *category = nsContentUtils::IsCallerChrome() ? "chrome javascript" : "content javascript"; JS::Rooted<JS::Value> exn(cx()); js::ErrorReport jsReport(cx()); if (StealException(&exn) && jsReport.init(cx(), exn)) { nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport(); xpcReport->Init(jsReport.report(), jsReport.message(), category, win ? win->WindowID() : 0); if (win) { DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn); } else { xpcReport->LogToConsole(); } } else { NS_WARNING("OOMed while acquiring uncaught exception from JSAPI"); } } } if (mOldErrorReporter.isSome()) { JS_SetErrorReporter(JS_GetRuntime(cx()), mOldErrorReporter.value()); } }
void AutoJSAPI::ReportException() { 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, js::ErrorReport::WithSideEffects)) { if (mIsMainThread) { RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport(); RefPtr<nsGlobalWindow> win = xpc::WindowGlobalOrNull(errorGlobal); if (!win) { // We run addons in a separate privileged compartment, but they still // expect to trigger the onerror handler of their associated DOM Window. win = xpc::AddonWindowOrNull(errorGlobal); } nsPIDOMWindowInner* inner = win ? win->AsInner() : nullptr; xpcReport->Init(jsReport.report(), jsReport.toStringResult().c_str(), nsContentUtils::IsCallerChrome(), inner ? inner->WindowID() : 0); if (inner && jsReport.report()->errorNumber != JSMSG_OUT_OF_MEMORY) { JS::RootingContext* rcx = JS::RootingContext::get(cx()); DispatchScriptErrorEvent(inner, rcx, xpcReport, exn); } else { JS::Rooted<JSObject*> stack(cx(), xpc::FindExceptionStackForConsoleReport(inner, exn)); xpcReport->LogToConsoleWithStack(stack); } } 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.toStringResult(), jsReport.report()); ClearException(); } } else { NS_WARNING("OOMed while acquiring uncaught exception from JSAPI"); ClearException(); } }