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/. */
10 #include "mozilla/Assertions.h" // MOZ_ASSERT
11 #include "mozilla/Maybe.h" // mozilla::Maybe
12 #include "mozilla/Variant.h" // mozilla::Variant
14 #include <stddef.h> // size_t
15 #include <stdint.h> // uint32_t, uintptr_t, UINTPTR_MAX
16 #include <utility> // std::move
18 #include "jstypes.h" // JS_PUBLIC_API
20 #include "js/Principals.h" // JSPrincipals, JS_HoldPrincipals, JS_DropPrincipals
21 #include "js/TypeDecls.h" // JSContext, Handle*, MutableHandle*
25 using NativeStackSize
= size_t;
27 using NativeStackBase
= uintptr_t;
29 using NativeStackLimit
= uintptr_t;
31 #if JS_STACK_GROWTH_DIRECTION > 0
32 constexpr NativeStackLimit NativeStackLimitMin
= 0;
33 constexpr NativeStackLimit NativeStackLimitMax
= UINTPTR_MAX
;
35 constexpr NativeStackLimit NativeStackLimitMin
= UINTPTR_MAX
;
36 constexpr NativeStackLimit NativeStackLimitMax
= 0;
40 // We build with the "stack-first" wasm-ld option, so the stack grows downward
41 // toward zero. Let's set a limit just a bit above this so that we catch an
42 // overflow before a Wasm trap occurs.
43 constexpr NativeStackLimit WASINativeStackLimit
= 1024;
46 inline NativeStackLimit
GetNativeStackLimit(NativeStackBase base
,
47 NativeStackSize size
) {
48 #if JS_STACK_GROWTH_DIRECTION > 0
49 MOZ_ASSERT(base
<= size_t(-1) - size
);
50 return base
+ size
- 1;
51 #else // stack grows up
52 MOZ_ASSERT(base
>= size
);
53 return base
- (size
- 1);
54 #endif // stack grows down
60 * Set the size of the native stack that should not be exceed. To disable
61 * stack size checking pass 0.
63 * SpiderMonkey allows for a distinction between system code (such as GCs, which
64 * may incidentally be triggered by script but are not strictly performed on
65 * behalf of such script), trusted script (as determined by
66 * JS_SetTrustedPrincipals), and untrusted script. Each kind of code may have a
67 * different stack quota, allowing embedders to keep higher-priority machinery
68 * running in the face of scripted stack exhaustion by something else.
70 * The stack quotas for each kind of code should be monotonically descending,
71 * and may be specified with this function. If 0 is passed for a given kind
72 * of code, it defaults to the value of the next-highest-priority kind.
74 * This function may only be called immediately after the runtime is initialized
75 * and before any code is executed and/or interrupts requested.
77 extern JS_PUBLIC_API
void JS_SetNativeStackQuota(
78 JSContext
* cx
, JS::NativeStackSize systemCodeStackSize
,
79 JS::NativeStackSize trustedScriptStackSize
= 0,
80 JS::NativeStackSize untrustedScriptStackSize
= 0);
84 enum class StackFormat
{ SpiderMonkey
, V8
, Default
};
87 * Sets the format used for stringifying Error stacks.
89 * The default format is StackFormat::SpiderMonkey. Use StackFormat::V8
90 * in order to emulate V8's stack formatting. StackFormat::Default can't be
93 extern JS_PUBLIC_API
void SetStackFormat(JSContext
* cx
, StackFormat format
);
95 extern JS_PUBLIC_API StackFormat
GetStackFormat(JSContext
* cx
);
102 * Capture all frames.
107 * Capture at most this many frames.
112 explicit MaxFrames(uint32_t max
) : maxFrames(max
) { MOZ_ASSERT(max
> 0); }
116 * Capture the first frame with the given principals. By default, do not
117 * consider self-hosted frames with the given principals as satisfying the stack
120 struct JS_PUBLIC_API FirstSubsumedFrame
{
122 JSPrincipals
* principals
;
123 bool ignoreSelfHosted
;
126 * Use the cx's current compartment's principals.
128 explicit FirstSubsumedFrame(JSContext
* cx
,
129 bool ignoreSelfHostedFrames
= true);
131 explicit FirstSubsumedFrame(JSContext
* ctx
, JSPrincipals
* p
,
132 bool ignoreSelfHostedFrames
= true)
133 : cx(ctx
), principals(p
), ignoreSelfHosted(ignoreSelfHostedFrames
) {
135 JS_HoldPrincipals(principals
);
139 // No copying because we want to avoid holding and dropping principals
141 FirstSubsumedFrame(const FirstSubsumedFrame
&) = delete;
142 FirstSubsumedFrame
& operator=(const FirstSubsumedFrame
&) = delete;
143 FirstSubsumedFrame
& operator=(FirstSubsumedFrame
&&) = delete;
145 FirstSubsumedFrame(FirstSubsumedFrame
&& rhs
)
146 : principals(rhs
.principals
), ignoreSelfHosted(rhs
.ignoreSelfHosted
) {
147 MOZ_ASSERT(this != &rhs
, "self move disallowed");
148 rhs
.principals
= nullptr;
151 ~FirstSubsumedFrame() {
153 JS_DropPrincipals(cx
, principals
);
158 using StackCapture
= mozilla::Variant
<AllFrames
, MaxFrames
, FirstSubsumedFrame
>;
161 * Capture the current call stack as a chain of SavedFrame JSObjects, and set
162 * |stackp| to the SavedFrame for the youngest stack frame, or nullptr if there
163 * are no JS frames on the stack.
165 * The |capture| parameter describes the portion of the JS stack to capture:
167 * * |JS::AllFrames|: Capture all frames on the stack.
169 * * |JS::MaxFrames|: Capture no more than |JS::MaxFrames::maxFrames| from the
172 * * |JS::FirstSubsumedFrame|: Capture the first frame whose principals are
173 * subsumed by |JS::FirstSubsumedFrame::principals|. By default, do not
174 * consider self-hosted frames; this can be controlled via the
175 * |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async
178 extern JS_PUBLIC_API
bool CaptureCurrentStack(
179 JSContext
* cx
, MutableHandleObject stackp
,
180 StackCapture
&& capture
= StackCapture(AllFrames()));
183 * Returns true if capturing stack trace data to associate with an asynchronous
184 * operation is currently enabled for the current context realm.
186 * Users should check this state before capturing a stack that will be passed
187 * back to AutoSetAsyncStackForNewCalls later, in order to avoid capturing a
188 * stack for async use when we don't actually want to capture it.
190 extern JS_PUBLIC_API
bool IsAsyncStackCaptureEnabledForRealm(JSContext
* cx
);
193 * This is a utility function for preparing an async stack to be used
194 * by some other object. This may be used when you need to treat a
195 * given stack trace as an async parent. If you just need to capture
196 * the current stack, async parents and all, use CaptureCurrentStack
199 * Here |asyncStack| is the async stack to prepare. It is copied into
200 * |cx|'s current compartment, and the newest frame is given
201 * |asyncCause| as its asynchronous cause. If |maxFrameCount| is
202 * |Some(n)|, capture at most the youngest |n| frames. The
203 * new stack object is written to |stackp|. Returns true on success,
204 * or sets an exception and returns |false| on error.
206 extern JS_PUBLIC_API
bool CopyAsyncStack(
207 JSContext
* cx
, HandleObject asyncStack
, HandleString asyncCause
,
208 MutableHandleObject stackp
, const mozilla::Maybe
<size_t>& maxFrameCount
);
211 * Given a SavedFrame JSObject stack, stringify it in the same format as
212 * Error.prototype.stack. The stringified stack out parameter is placed in the
213 * cx's compartment. Defaults to the empty string.
215 * The same notes above about SavedFrame accessors applies here as well: cx
216 * doesn't need to be in stack's compartment, and stack can be null, a
217 * SavedFrame object, or a wrapper (CCW or Xray) around a SavedFrame object.
218 * SavedFrames not subsumed by |principals| are skipped.
220 * Optional indent parameter specifies the number of white spaces to indent
223 extern JS_PUBLIC_API
bool BuildStackString(
224 JSContext
* cx
, JSPrincipals
* principals
, HandleObject stack
,
225 MutableHandleString stringp
, size_t indent
= 0,
226 js::StackFormat stackFormat
= js::StackFormat::Default
);