Bug 1406455 - Disallow OOM simulation on worker threads r=jandem
authorJon Coppeard <jcoppeard@mozilla.com>
Tue, 10 Oct 2017 12:07:08 +0100
changeset 427915 e3c821833a142619a13b7ec42250c04d5bf27dbc
parent 427914 29e70589594f093939288a1a1aee95841c3a3539
child 427916 82957b8ff351cee2f42e8668b0593ae007594656
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewersjandem
bugs1406455
milestone58.0a1
Bug 1406455 - Disallow OOM simulation on worker threads r=jandem
js/public/Utility.h
js/src/builtin/TestingFunctions.cpp
js/src/jscntxt.cpp
js/src/vm/Initialization.cpp
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -62,16 +62,17 @@ enum ThreadType {
     THREAD_TYPE_ION,            // 3
     THREAD_TYPE_PARSE,          // 4
     THREAD_TYPE_COMPRESS,       // 5
     THREAD_TYPE_GCHELPER,       // 6
     THREAD_TYPE_GCPARALLEL,     // 7
     THREAD_TYPE_PROMISE_TASK,   // 8
     THREAD_TYPE_ION_FREE,       // 9
     THREAD_TYPE_WASM_TIER2,     // 10
+    THREAD_TYPE_WORKER,         // 11
     THREAD_TYPE_MAX             // Used to check shell function arguments
 };
 
 namespace oom {
 
 /*
  * Theads are tagged only in certain debug contexts.  Notably, to make testing
  * OOM in certain helper threads more effective, we allow restricting the OOM
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1439,16 +1439,27 @@ static bool
 OOMThreadTypes(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setInt32(js::THREAD_TYPE_MAX);
     return true;
 }
 
 static bool
+CheckCanSimulateOOM(JSContext* cx)
+{
+    if (js::oom::GetThreadType() != js::THREAD_TYPE_COOPERATING) {
+        JS_ReportErrorASCII(cx, "Simulated OOM failure is only supported on the main thread");
+        return false;
+    }
+
+    return true;
+}
+
+static bool
 SetupOOMFailure(JSContext* cx, bool failAlways, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (disableOOMFunctions) {
         args.rval().setUndefined();
         return true;
     }
@@ -1476,16 +1487,19 @@ SetupOOMFailure(JSContext* cx, bool fail
     if (args.length() > 1 && !ToUint32(cx, args[1], &targetThread))
         return false;
 
     if (targetThread == js::THREAD_TYPE_NONE || targetThread >= js::THREAD_TYPE_MAX) {
         JS_ReportErrorASCII(cx, "Invalid thread type specified");
         return false;
     }
 
+    if (!CheckCanSimulateOOM(cx))
+        return false;
+
     js::oom::SimulateOOMAfter(count, targetThread, failAlways);
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 OOMAfterAllocations(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -1497,16 +1511,20 @@ OOMAtAllocation(JSContext* cx, unsigned 
 {
     return SetupOOMFailure(cx, false, argc, vp);
 }
 
 static bool
 ResetOOMFailure(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (!CheckCanSimulateOOM(cx))
+        return false;
+
     args.rval().setBoolean(js::oom::HadSimulatedOOM());
     js::oom::ResetSimulatedOOM();
     return true;
 }
 
 static size_t
 CountCompartments(JSContext* cx)
 {
@@ -1532,16 +1550,19 @@ OOMTest(JSContext* cx, unsigned argc, Va
         return false;
     }
 
     if (args.length() == 2 && !args[1].isBoolean()) {
         JS_ReportErrorASCII(cx, "The optional second argument to oomTest() must be a boolean.");
         return false;
     }
 
+    if (!CheckCanSimulateOOM(cx))
+        return false;
+
     bool expectExceptionOnFailure = true;
     if (args.length() == 2)
         expectExceptionOnFailure = args[1].toBoolean();
 
     // There are some places where we do fail without raising an exception, so
     // we can't expose this to the fuzzers by default.
     if (fuzzingSafe)
         expectExceptionOnFailure = false;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -143,16 +143,21 @@ JSContext::init(ContextKind kind)
 
 JSContext*
 js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime)
 {
     AutoNoteSingleThreadedRegion anstr;
 
     MOZ_RELEASE_ASSERT(!TlsContext.get());
 
+#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
+    js::oom::SetThreadType(!parentRuntime ? js::THREAD_TYPE_COOPERATING
+                                          : js::THREAD_TYPE_WORKER);
+#endif
+
     JSRuntime* runtime = js_new<JSRuntime>(parentRuntime);
     if (!runtime)
         return nullptr;
 
     JSContext* cx = js_new<JSContext>(runtime, JS::ContextOptions());
     if (!cx) {
         js_delete(runtime);
         return nullptr;
--- a/js/src/vm/Initialization.cpp
+++ b/js/src/vm/Initialization.cpp
@@ -93,17 +93,16 @@ JS::detail::InitWithFailureDiagnostic(bo
 #ifdef DEBUG
     CheckMessageParameterCounts();
 #endif
 
     RETURN_IF_FAIL(js::TlsContext.init());
 
 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
     RETURN_IF_FAIL(js::oom::InitThreadType());
-    js::oom::SetThreadType(js::THREAD_TYPE_COOPERATING);
 #endif
 
     RETURN_IF_FAIL(js::Mutex::Init());
 
     RETURN_IF_FAIL(js::wasm::InitInstanceStaticData());
 
     js::gc::InitMemorySubsystem(); // Ensure gc::SystemPageSize() works.