From c80afef075d395cd81907b39d433d7acf71516ff Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Fri, 19 Feb 2016 13:46:07 -0800 Subject: [PATCH] Bug 912337 - Make a pref to toggle whether DebuggeeWouldRun is a warning or an error. (r=jimb) --- js/src/jsapi.h | 16 +++++++++++ js/src/vm/Debugger.cpp | 48 ++++++++++++++++++------------- js/xpconnect/src/XPCJSRuntime.cpp | 8 ++++++ modules/libpref/init/all.js | 3 ++ 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 155fe41dc188..8de21d68a9be 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1113,6 +1113,8 @@ class JS_PUBLIC_API(RuntimeOptions) { nativeRegExp_(true), unboxedArrays_(false), asyncStack_(true), + throwOnDebuggeeWouldRun_(true), + dumpStackOnDebuggeeWouldRun_(false), werror_(false), strictMode_(false), extraWarnings_(false), @@ -1182,6 +1184,18 @@ class JS_PUBLIC_API(RuntimeOptions) { return *this; } + bool throwOnDebuggeeWouldRun() const { return throwOnDebuggeeWouldRun_; } + RuntimeOptions& setThrowOnDebuggeeWouldRun(bool flag) { + throwOnDebuggeeWouldRun_ = flag; + return *this; + } + + bool dumpStackOnDebuggeeWouldRun() const { return dumpStackOnDebuggeeWouldRun_; } + RuntimeOptions& setDumpStackOnDebuggeeWouldRun(bool flag) { + dumpStackOnDebuggeeWouldRun_ = flag; + return *this; + } + bool werror() const { return werror_; } RuntimeOptions& setWerror(bool flag) { werror_ = flag; @@ -1226,6 +1240,8 @@ class JS_PUBLIC_API(RuntimeOptions) { bool nativeRegExp_ : 1; bool unboxedArrays_ : 1; bool asyncStack_ : 1; + bool throwOnDebuggeeWouldRun_ : 1; + bool dumpStackOnDebuggeeWouldRun_ : 1; bool werror_ : 1; bool strictMode_ : 1; bool extraWarnings_ : 1; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 1a649e0d9213..bf437ebb4da7 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -285,10 +285,15 @@ class MOZ_RAII js::EnterDebuggeeNoExecute // Non-nullptr when unlocked temporarily by a LeaveDebuggeeNoExecute. LeaveDebuggeeNoExecute* unlocked_; + // When DebuggeeWouldRun is a warning instead of an error, whether we've + // reported a warning already. + bool reported_; + public: explicit EnterDebuggeeNoExecute(JSContext* cx, Debugger& dbg) : dbg_(dbg), - unlocked_(nullptr) + unlocked_(nullptr), + reported_(false) { stack_ = &cx->runtime()->noExecuteDebuggerTop; prev_ = *stack_; @@ -307,16 +312,12 @@ class MOZ_RAII js::EnterDebuggeeNoExecute #ifdef DEBUG static bool isUniqueLockedInStack(JSContext* cx, Debugger& dbg) { JSRuntime* rt = cx->runtime(); - - // This invariant does not hold when DebuggeeWouldRun is only a - // warning. - if (!rt->options().throwOnDebuggeeWouldRun()) - return true; - EnterDebuggeeNoExecute* found = nullptr; for (EnterDebuggeeNoExecute* it = rt->noExecuteDebuggerTop; it; it = it->prev_) { if (&it->debugger() == &dbg && !it->unlocked_) { - MOZ_ASSERT(!found); + // This invariant does not hold when DebuggeeWouldRun is only a + // warning. + MOZ_ASSERT_IF(rt->options().throwOnDebuggeeWouldRun(), !found); found = it; } } @@ -337,11 +338,24 @@ class MOZ_RAII js::EnterDebuggeeNoExecute return nullptr; } - // As above, except for returning the Debugger instance. - static Debugger* findDebuggerInStack(JSContext* cx) { - if (EnterDebuggeeNoExecute* nx = findInStack(cx)) - return &nx->debugger(); - return nullptr; + // Given a JSContext entered into a debuggee compartment, reports a + // warning or an error if there is a lock that locks it. + static bool reportIfFoundInStack(JSContext* cx) { + if (EnterDebuggeeNoExecute* nx = findInStack(cx)) { + bool warning = !cx->runtime()->options().throwOnDebuggeeWouldRun(); + if (!warning || !nx->reported_) { + AutoCompartment ac(cx, nx->debugger().toJSObject()); + nx->reported_ = true; + if (cx->runtime()->options().dumpStackOnDebuggeeWouldRun()) { + fprintf(stdout, "Dumping stack for DebuggeeWouldRun:\n"); + DumpBacktrace(cx); + } + unsigned flags = warning ? JSREPORT_WARNING : JSREPORT_ERROR; + return JS_ReportErrorFlagsAndNumber(cx, flags, GetErrorMessage, nullptr, + JSMSG_DEBUGGEE_WOULD_RUN); + } + } + return true; } }; @@ -378,13 +392,7 @@ Debugger::slowPathCheckNoExecute(JSContext* cx) { MOZ_ASSERT(cx->compartment()->isDebuggee()); MOZ_ASSERT(cx->runtime()->noExecuteDebuggerTop); - - if (Debugger* dbg = EnterDebuggeeNoExecute::findDebuggerInStack(cx)) { - AutoCompartment ac(cx, dbg->toJSObject()); - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEBUGGEE_WOULD_RUN); - return false; - } - return true; + return EnterDebuggeeNoExecute::reportIfFoundInStack(cx); } diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 74c2ea5324ea..cc144c0f5878 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -1578,6 +1578,12 @@ ReloadPrefsCallback(const char* pref, void* data) bool useAsyncStack = Preferences::GetBool(JS_OPTIONS_DOT_STR "asyncstack"); + bool throwOnDebuggeeWouldRun = Preferences::GetBool(JS_OPTIONS_DOT_STR + "throw_on_debuggee_would_run"); + + bool dumpStackOnDebuggeeWouldRun = Preferences::GetBool(JS_OPTIONS_DOT_STR + "dump_stack_on_debuggee_would_run"); + bool werror = Preferences::GetBool(JS_OPTIONS_DOT_STR "werror"); bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict"); @@ -1594,6 +1600,8 @@ ReloadPrefsCallback(const char* pref, void* data) .setThrowOnAsmJSValidationFailure(throwOnAsmJSValidationFailure) .setNativeRegExp(useNativeRegExp) .setAsyncStack(useAsyncStack) + .setThrowOnDebuggeeWouldRun(throwOnDebuggeeWouldRun) + .setDumpStackOnDebuggeeWouldRun(dumpStackOnDebuggeeWouldRun) .setWerror(werror) .setExtraWarnings(extraWarnings); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index f03b3f86f487..93cbdebe5876 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1203,6 +1203,9 @@ pref("javascript.options.shared_memory", true); pref("javascript.options.shared_memory", false); #endif +pref("javascript.options.throw_on_debuggee_would_run", false); +pref("javascript.options.dump_stack_on_debuggee_would_run", false); + // advanced prefs pref("advanced.mailftp", false); pref("image.animation_mode", "normal");