NoExecute.h (3095B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef debugger_NoExecute_h 8 #define debugger_NoExecute_h 9 10 #include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT 11 #include "mozilla/Attributes.h" // for MOZ_RAII 12 13 #include "NamespaceImports.h" // for HandleScript 14 #include "js/Promise.h" // for JS::AutoDebuggerJobQueueInterruption 15 16 namespace js { 17 18 class Debugger; 19 class LeaveDebuggeeNoExecute; 20 21 // Prevents all the debuggeee compartments of a given Debugger from executing 22 // scripts. Attempts to run script will throw an 23 // instance of Debugger.DebuggeeWouldRun from the topmost locked Debugger's 24 // compartment. 25 class MOZ_RAII EnterDebuggeeNoExecute { 26 friend class LeaveDebuggeeNoExecute; 27 28 Debugger& dbg_; 29 EnterDebuggeeNoExecute** stack_; 30 EnterDebuggeeNoExecute* prev_; 31 32 // Non-nullptr when unlocked temporarily by a LeaveDebuggeeNoExecute. 33 LeaveDebuggeeNoExecute* unlocked_; 34 35 // When DebuggeeWouldRun is a warning instead of an error, whether we've 36 // reported a warning already. 37 bool reported_; 38 39 public: 40 // Mark execution in dbg's debuggees as forbidden, for the lifetime of this 41 // object. Require an AutoDebuggerJobQueueInterruption in scope. 42 explicit EnterDebuggeeNoExecute( 43 JSContext* cx, Debugger& dbg, 44 const JS::AutoDebuggerJobQueueInterruption& adjqiProof); 45 46 ~EnterDebuggeeNoExecute() { 47 MOZ_ASSERT(*stack_ == this); 48 *stack_ = prev_; 49 } 50 51 Debugger& debugger() const { return dbg_; } 52 53 #ifdef DEBUG 54 static bool isLockedInStack(JSContext* cx, Debugger& dbg); 55 #endif 56 57 // Given a JSContext entered into a debuggee realm, find the lock 58 // that locks it. Returns nullptr if not found. 59 static EnterDebuggeeNoExecute* findInStack(JSContext* cx); 60 61 // Given a JSContext entered into a debuggee compartment, report a 62 // warning or an error if there is a lock that locks it. 63 static bool reportIfFoundInStack(JSContext* cx, HandleScript script); 64 }; 65 66 // Given a JSContext entered into a debuggee compartment, if it is in 67 // an NX section, unlock the topmost EnterDebuggeeNoExecute instance. 68 // 69 // Does nothing if debuggee is not in an NX section. For example, this 70 // situation arises when invocation functions are called without entering 71 // Debugger code, e.g., calling D.O.p.executeInGlobal or D.O.p.apply. 72 class MOZ_RAII LeaveDebuggeeNoExecute { 73 EnterDebuggeeNoExecute* prevLocked_; 74 75 public: 76 explicit LeaveDebuggeeNoExecute(JSContext* cx) 77 : prevLocked_(EnterDebuggeeNoExecute::findInStack(cx)) { 78 if (prevLocked_) { 79 MOZ_ASSERT(!prevLocked_->unlocked_); 80 prevLocked_->unlocked_ = this; 81 } 82 } 83 84 ~LeaveDebuggeeNoExecute() { 85 if (prevLocked_) { 86 MOZ_ASSERT(prevLocked_->unlocked_ == this); 87 prevLocked_->unlocked_ = nullptr; 88 } 89 } 90 }; 91 92 } /* namespace js */ 93 94 #endif /* debugger_NoExecute_h */