mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1062077 - Introduce xpc::ErrorReport. r=bz
I've got it! Let's just wrap the JS thing in an XPCOM thing that duplicates its fields with a different ownership model! We totally need another one of those, right? And we could even stick it in XPConnect! </sarcasm> In seriousness - the code to own, format, and display error reports is currently spread between the JS engine, JSErrorReporters, an async Runnable abstraction, and elsewhere. We need to condense it somewhere to start chipping away at this mess.
This commit is contained in:
parent
1174c125e2
commit
35d62e8c00
@ -355,46 +355,6 @@ NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
AsyncErrorReporter::AsyncErrorReporter(JSRuntime* aRuntime,
|
||||
JSErrorReport* aErrorReport,
|
||||
const char* aFallbackMessage,
|
||||
bool aIsChromeError,
|
||||
nsPIDOMWindow* aWindow)
|
||||
: mSourceLine(static_cast<const char16_t*>(aErrorReport->uclinebuf))
|
||||
, mLineNumber(aErrorReport->lineno)
|
||||
, mColumn(aErrorReport->column)
|
||||
, mFlags(aErrorReport->flags)
|
||||
{
|
||||
if (!aErrorReport->filename) {
|
||||
mFileName.SetIsVoid(true);
|
||||
} else {
|
||||
mFileName.AssignWithConversion(aErrorReport->filename);
|
||||
}
|
||||
|
||||
const char16_t* m = static_cast<const char16_t*>(aErrorReport->ucmessage);
|
||||
if (m) {
|
||||
JSFlatString* name = js::GetErrorTypeName(aRuntime, aErrorReport->exnType);
|
||||
if (name) {
|
||||
AssignJSFlatString(mErrorMsg, name);
|
||||
mErrorMsg.AppendLiteral(": ");
|
||||
}
|
||||
mErrorMsg.Append(m);
|
||||
}
|
||||
|
||||
if (mErrorMsg.IsEmpty() && aFallbackMessage) {
|
||||
mErrorMsg.AssignWithConversion(aFallbackMessage);
|
||||
}
|
||||
|
||||
mCategory = aIsChromeError ? NS_LITERAL_CSTRING("chrome javascript") :
|
||||
NS_LITERAL_CSTRING("content javascript");
|
||||
|
||||
mInnerWindowID = 0;
|
||||
if (aWindow) {
|
||||
MOZ_ASSERT(aWindow->IsInnerWindow());
|
||||
mInnerWindowID = aWindow->WindowID();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsyncErrorReporter::ReportError()
|
||||
{
|
||||
@ -404,10 +364,15 @@ AsyncErrorReporter::ReportError()
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = errorObject->InitWithWindowID(mErrorMsg, mFileName,
|
||||
mSourceLine, mLineNumber,
|
||||
mColumn, mFlags, mCategory,
|
||||
mInnerWindowID);
|
||||
uint64_t windowID = mReport->mWindow ? mReport->mWindow->WindowID() : 0;
|
||||
nsresult rv = errorObject->InitWithWindowID(mReport->mErrorMsg,
|
||||
mReport->mFileName,
|
||||
mReport->mSourceLine,
|
||||
mReport->mLineNumber,
|
||||
mReport->mColumn,
|
||||
mReport->mFlags,
|
||||
mReport->Category(),
|
||||
windowID);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
@ -429,34 +394,27 @@ class ScriptErrorEvent : public AsyncErrorReporter
|
||||
{
|
||||
public:
|
||||
ScriptErrorEvent(JSRuntime* aRuntime,
|
||||
JSErrorReport* aErrorReport,
|
||||
const char* aFallbackMessage,
|
||||
xpc::ErrorReport* aReport,
|
||||
nsIPrincipal* aScriptOriginPrincipal,
|
||||
nsIPrincipal* aGlobalPrincipal,
|
||||
nsPIDOMWindow* aWindow,
|
||||
JS::Handle<JS::Value> aError,
|
||||
bool aDispatchEvent)
|
||||
// Pass an empty category, then compute ours
|
||||
: AsyncErrorReporter(aRuntime, aErrorReport, aFallbackMessage,
|
||||
nsContentUtils::IsSystemPrincipal(aGlobalPrincipal),
|
||||
aWindow)
|
||||
: AsyncErrorReporter(aRuntime, aReport)
|
||||
, mOriginPrincipal(aScriptOriginPrincipal)
|
||||
, mDispatchEvent(aDispatchEvent)
|
||||
, mError(aRuntime, aError)
|
||||
, mWindow(aWindow)
|
||||
{
|
||||
MOZ_ASSERT_IF(mWindow, mWindow->IsInnerWindow());
|
||||
}
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsPIDOMWindow* win = mReport->mWindow;
|
||||
// First, notify the DOM that we have a script error, but only if
|
||||
// our window is still the current inner, if we're associated with a window.
|
||||
if (mDispatchEvent && (!mWindow || mWindow->IsCurrentInnerWindow())) {
|
||||
nsIDocShell* docShell = mWindow ? mWindow->GetDocShell() : nullptr;
|
||||
if (mDispatchEvent && (!win || win->IsCurrentInnerWindow())) {
|
||||
nsIDocShell* docShell = win ? win->GetDocShell() : nullptr;
|
||||
if (docShell &&
|
||||
!JSREPORT_IS_WARNING(mFlags) &&
|
||||
!JSREPORT_IS_WARNING(mReport->mFlags) &&
|
||||
!sHandlingScriptError) {
|
||||
AutoRestore<bool> recursionGuard(sHandlingScriptError);
|
||||
sHandlingScriptError = true;
|
||||
@ -467,10 +425,10 @@ public:
|
||||
ThreadsafeAutoJSContext cx;
|
||||
RootedDictionary<ErrorEventInit> init(cx);
|
||||
init.mCancelable = true;
|
||||
init.mFilename = mFileName;
|
||||
init.mFilename = mReport->mFileName;
|
||||
init.mBubbles = true;
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(mWindow));
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
|
||||
NS_ENSURE_STATE(sop);
|
||||
nsIPrincipal* p = sop->GetPrincipal();
|
||||
NS_ENSURE_STATE(p);
|
||||
@ -485,9 +443,9 @@ public:
|
||||
|
||||
NS_NAMED_LITERAL_STRING(xoriginMsg, "Script error.");
|
||||
if (sameOrigin) {
|
||||
init.mMessage = mErrorMsg;
|
||||
init.mLineno = mLineNumber;
|
||||
init.mColno = mColumn;
|
||||
init.mMessage = mReport->mErrorMsg;
|
||||
init.mLineno = mReport->mLineNumber;
|
||||
init.mColno = mReport->mColumn;
|
||||
init.mError = mError;
|
||||
} else {
|
||||
NS_WARNING("Not same origin error!");
|
||||
@ -496,11 +454,11 @@ public:
|
||||
}
|
||||
|
||||
nsRefPtr<ErrorEvent> event =
|
||||
ErrorEvent::Constructor(static_cast<nsGlobalWindow*>(mWindow.get()),
|
||||
ErrorEvent::Constructor(static_cast<nsGlobalWindow*>(win),
|
||||
NS_LITERAL_STRING("error"), init);
|
||||
event->SetTrusted(true);
|
||||
|
||||
EventDispatcher::DispatchDOMEvent(mWindow, nullptr, event, presContext,
|
||||
EventDispatcher::DispatchDOMEvent(win, nullptr, event, presContext,
|
||||
&status);
|
||||
}
|
||||
}
|
||||
@ -516,7 +474,6 @@ private:
|
||||
nsCOMPtr<nsIPrincipal> mOriginPrincipal;
|
||||
bool mDispatchEvent;
|
||||
JS::PersistentRootedValue mError;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
static bool sHandlingScriptError;
|
||||
};
|
||||
@ -547,20 +504,13 @@ NS_ScriptErrorReporter(JSContext *cx,
|
||||
}
|
||||
}
|
||||
if (globalObject) {
|
||||
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
xpcReport->Init(report, message, globalObject);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
|
||||
MOZ_ASSERT_IF(win, win->IsInnerWindow());
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
|
||||
do_QueryInterface(globalObject);
|
||||
NS_ASSERTION(scriptPrincipal, "Global objects must implement "
|
||||
"nsIScriptObjectPrincipal");
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new ScriptErrorEvent(JS_GetRuntime(cx),
|
||||
report,
|
||||
message,
|
||||
xpcReport,
|
||||
nsJSPrincipals::get(report->originPrincipals),
|
||||
scriptPrincipal->GetPrincipal(),
|
||||
win,
|
||||
exception,
|
||||
/* We do not try to report Out Of Memory via a dom
|
||||
* event because the dom event handler would
|
||||
|
@ -14,7 +14,9 @@
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
class nsICycleCollectorListener;
|
||||
class nsIXPConnectJSObjectHolder;
|
||||
@ -189,11 +191,9 @@ class AsyncErrorReporter : public nsRunnable
|
||||
{
|
||||
public:
|
||||
// aWindow may be null if this error report is not associated with a window
|
||||
AsyncErrorReporter(JSRuntime* aRuntime,
|
||||
JSErrorReport* aErrorReport,
|
||||
const char* aFallbackMessage,
|
||||
bool aIsChromeError, // To determine category
|
||||
nsPIDOMWindow* aWindow);
|
||||
AsyncErrorReporter(JSRuntime* aRuntime, xpc::ErrorReport* aReport)
|
||||
: mReport(aReport)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
@ -205,14 +205,7 @@ protected:
|
||||
// Do the actual error reporting
|
||||
void ReportError();
|
||||
|
||||
nsString mErrorMsg;
|
||||
nsString mFileName;
|
||||
nsString mSourceLine;
|
||||
nsCString mCategory;
|
||||
uint32_t mLineNumber;
|
||||
uint32_t mColumn;
|
||||
uint32_t mFlags;
|
||||
uint64_t mInnerWindowID;
|
||||
nsRefPtr<xpc::ErrorReport> mReport;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -1005,19 +1005,13 @@ Promise::MaybeReportRejected()
|
||||
return;
|
||||
}
|
||||
|
||||
// Remains null in case of worker.
|
||||
nsCOMPtr<nsPIDOMWindow> win;
|
||||
bool isChromeError = false;
|
||||
|
||||
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
nsIPrincipal* principal;
|
||||
win = xpc::WindowGlobalOrNull(obj);
|
||||
principal = nsContentUtils::ObjectPrincipal(obj);
|
||||
isChromeError = nsContentUtils::IsSystemPrincipal(principal);
|
||||
nsIGlobalObject* global = xpc::GetNativeForGlobal(js::GetGlobalForObjectCrossCompartment(obj));
|
||||
xpcReport->Init(report.report(), report.message(), global);
|
||||
} else {
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
isChromeError = worker->IsChromeWorker();
|
||||
xpcReport->InitOnWorkerThread(report.report(), report.message(),
|
||||
GetCurrentThreadWorkerPrivate()->IsChromeWorker());
|
||||
}
|
||||
|
||||
// Now post an event to do the real reporting async
|
||||
@ -1025,11 +1019,7 @@ Promise::MaybeReportRejected()
|
||||
// AsyncErrorReporter, otherwise if the call to DispatchToMainThread fails, it
|
||||
// will leak. See Bug 958684.
|
||||
nsRefPtr<AsyncErrorReporter> r =
|
||||
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(),
|
||||
report.report(),
|
||||
report.message(),
|
||||
isChromeError,
|
||||
win);
|
||||
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(), xpcReport);
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
|
@ -237,6 +237,65 @@ xpc::SystemErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep)
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
xpc::ErrorReport::Init(JSErrorReport *aReport,
|
||||
const char *aFallbackMessage,
|
||||
nsIGlobalObject *aGlobal)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aGlobal);
|
||||
|
||||
mGlobal = aGlobal;
|
||||
mWindow = do_QueryInterface(mGlobal);
|
||||
MOZ_ASSERT_IF(mWindow, mWindow->IsInnerWindow());
|
||||
|
||||
nsIPrincipal *prin = mGlobal->PrincipalOrNull();
|
||||
mIsChrome = nsContentUtils::IsSystemPrincipal(prin);
|
||||
|
||||
InitInternal(aReport, aFallbackMessage);
|
||||
}
|
||||
|
||||
void
|
||||
xpc::ErrorReport::InitOnWorkerThread(JSErrorReport *aReport,
|
||||
const char *aFallbackMessage,
|
||||
bool aIsChrome)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
mIsChrome = aIsChrome;
|
||||
|
||||
InitInternal(aReport, aFallbackMessage);
|
||||
}
|
||||
|
||||
void
|
||||
xpc::ErrorReport::InitInternal(JSErrorReport *aReport,
|
||||
const char *aFallbackMessage)
|
||||
{
|
||||
const char16_t* m = static_cast<const char16_t*>(aReport->ucmessage);
|
||||
if (m) {
|
||||
JSFlatString* name = js::GetErrorTypeName(CycleCollectedJSRuntime::Get()->Runtime(), aReport->exnType);
|
||||
if (name) {
|
||||
AssignJSFlatString(mErrorMsg, name);
|
||||
mErrorMsg.AppendLiteral(": ");
|
||||
}
|
||||
mErrorMsg.Append(m);
|
||||
}
|
||||
|
||||
if (mErrorMsg.IsEmpty() && aFallbackMessage) {
|
||||
mErrorMsg.AssignWithConversion(aFallbackMessage);
|
||||
}
|
||||
|
||||
if (!aReport->filename) {
|
||||
mFileName.SetIsVoid(true);
|
||||
} else {
|
||||
mFileName.AssignWithConversion(aReport->filename);
|
||||
}
|
||||
|
||||
mSourceLine = static_cast<const char16_t*>(aReport->uclinebuf);
|
||||
|
||||
mLineNumber = aReport->lineno;
|
||||
mColumn = aReport->column;
|
||||
mFlags = aReport->flags;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "nsISupports.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
@ -26,7 +28,6 @@
|
||||
class nsGlobalWindow;
|
||||
class nsIPrincipal;
|
||||
class nsScriptNameSpaceManager;
|
||||
class nsIGlobalObject;
|
||||
class nsIMemoryReporterCallback;
|
||||
|
||||
#ifndef BAD_TLS_INDEX
|
||||
@ -490,6 +491,46 @@ SetAddonInterposition(const nsACString &addonId, nsIAddonInterposition *interpos
|
||||
bool
|
||||
ExtraWarningsForSystemJS();
|
||||
|
||||
class ErrorReport {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ErrorReport);
|
||||
|
||||
ErrorReport() : mIsChrome(false)
|
||||
, mLineNumber(0)
|
||||
, mColumn(0)
|
||||
, mFlags(0)
|
||||
{}
|
||||
|
||||
void Init(JSErrorReport *aReport, const char *aFallbackMessage,
|
||||
nsIGlobalObject *aGlobal);
|
||||
void InitOnWorkerThread(JSErrorReport *aReport, const char *aFallbackMessage,
|
||||
bool aIsChrome);
|
||||
|
||||
private:
|
||||
void InitInternal(JSErrorReport *aReport, const char *aFallbackMessage);
|
||||
bool mIsChrome;
|
||||
|
||||
public:
|
||||
const nsCString Category() {
|
||||
return mIsChrome ? NS_LITERAL_CSTRING("chrome javascript")
|
||||
: NS_LITERAL_CSTRING("content javascript");
|
||||
}
|
||||
|
||||
nsString mErrorMsg;
|
||||
nsString mFileName;
|
||||
nsString mSourceLine;
|
||||
uint32_t mLineNumber;
|
||||
uint32_t mColumn;
|
||||
uint32_t mFlags;
|
||||
|
||||
// These are both null for ErrorReports initialized on a worker thread.
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
private:
|
||||
~ErrorReport() {}
|
||||
};
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
namespace mozilla {
|
||||
|
Loading…
Reference in New Issue
Block a user