1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
/* -*- 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 http://mozilla.org/MPL/2.0/. */
#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_;
public:
// 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);
#endif
// 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_;
public:
explicit LeaveDebuggeeNoExecute(JSContext* cx)
: prevLocked_(EnterDebuggeeNoExecute::findInStack(cx)) {
if (prevLocked_) {
MOZ_ASSERT(!prevLocked_->unlocked_);
prevLocked_->unlocked_ = this;
}
}
~LeaveDebuggeeNoExecute() {
if (prevLocked_) {
MOZ_ASSERT(prevLocked_->unlocked_ == this);
prevLocked_->unlocked_ = nullptr;
}
}
};
} /* namespace js */
#endif /* debugger_NoExecute_h */
|