Source code

Revision control

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
#ifndef debugger_NoExecute_h
#define debugger_NoExecute_h
#include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT
#include "mozilla/Attributes.h" // for MOZ_RAII
#include "jsapi.h"
#include "NamespaceImports.h" // for HandleScript
#include "js/Promise.h" // for JS::AutoDebuggerJobQueueInterruption
namespace js {
class Debugger;
class LeaveDebuggeeNoExecute;
// Prevents all the debuggeee compartments of a given Debugger from executing
// scripts. Attempts to run script will throw an
// instance of Debugger.DebuggeeWouldRun from the topmost locked Debugger's
// compartment.
class MOZ_RAII EnterDebuggeeNoExecute {
friend class LeaveDebuggeeNoExecute;
Debugger& dbg_;
EnterDebuggeeNoExecute** stack_;
EnterDebuggeeNoExecute* prev_;
// 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_;
// Mark execution in dbg's debuggees as forbidden, for the lifetime of this
// object. Require an AutoDebuggerJobQueueInterruption in scope.
explicit EnterDebuggeeNoExecute(
JSContext* cx, Debugger& dbg,
const JS::AutoDebuggerJobQueueInterruption& adjqiProof);
~EnterDebuggeeNoExecute() {
MOZ_ASSERT(*stack_ == this);
*stack_ = prev_;
Debugger& debugger() const { return dbg_; }
#ifdef DEBUG
static bool isLockedInStack(JSContext* cx, Debugger& dbg);
// Given a JSContext entered into a debuggee realm, find the lock
// that locks it. Returns nullptr if not found.
static EnterDebuggeeNoExecute* findInStack(JSContext* cx);
// Given a JSContext entered into a debuggee compartment, report a
// warning or an error if there is a lock that locks it.
static bool reportIfFoundInStack(JSContext* cx, HandleScript script);
// Given a JSContext entered into a debuggee compartment, if it is in
// an NX section, unlock the topmost EnterDebuggeeNoExecute instance.
// Does nothing if debuggee is not in an NX section. For example, this
// situation arises when invocation functions are called without entering
// Debugger code, e.g., calling D.O.p.executeInGlobal or D.O.p.apply.
class MOZ_RAII LeaveDebuggeeNoExecute {
EnterDebuggeeNoExecute* prevLocked_;
explicit LeaveDebuggeeNoExecute(JSContext* cx)
: prevLocked_(EnterDebuggeeNoExecute::findInStack(cx)) {
if (prevLocked_) {
prevLocked_->unlocked_ = this;
~LeaveDebuggeeNoExecute() {
if (prevLocked_) {
MOZ_ASSERT(prevLocked_->unlocked_ == this);
prevLocked_->unlocked_ = nullptr;
} /* namespace js */
#endif /* debugger_NoExecute_h */