tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Stack.h (7227B)


      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 js_Stack_h
      8 #define js_Stack_h
      9 
     10 #include "mozilla/Assertions.h"  // MOZ_ASSERT
     11 #include "mozilla/Maybe.h"       // mozilla::Maybe
     12 #include "mozilla/Variant.h"     // mozilla::Variant
     13 
     14 #include <stddef.h>  // size_t
     15 #include <stdint.h>  // uint32_t, uintptr_t, UINTPTR_MAX
     16 #include <utility>   // std::move
     17 
     18 #include "jstypes.h"  // JS_PUBLIC_API
     19 
     20 #include "js/NativeStackLimits.h"
     21 #include "js/Principals.h"  // JSPrincipals, JS_HoldPrincipals, JS_DropPrincipals
     22 #include "js/RootingAPI.h"
     23 
     24 /**
     25 * Set the size of the native stack that should not be exceed. To disable
     26 * stack size checking pass 0.
     27 *
     28 * SpiderMonkey allows for a distinction between system code (such as GCs, which
     29 * may incidentally be triggered by script but are not strictly performed on
     30 * behalf of such script), trusted script (as determined by
     31 * JS_SetTrustedPrincipals), and untrusted script. Each kind of code may have a
     32 * different stack quota, allowing embedders to keep higher-priority machinery
     33 * running in the face of scripted stack exhaustion by something else.
     34 *
     35 * The stack quotas for each kind of code should be monotonically descending,
     36 * and may be specified with this function. If 0 is passed for a given kind
     37 * of code, it defaults to the value of the next-highest-priority kind.
     38 *
     39 * This function may only be called immediately after the runtime is initialized
     40 * and before any code is executed and/or interrupts requested.
     41 */
     42 extern JS_PUBLIC_API void JS_SetNativeStackQuota(
     43    JSContext* cx, JS::NativeStackSize systemCodeStackSize,
     44    JS::NativeStackSize trustedScriptStackSize = 0,
     45    JS::NativeStackSize untrustedScriptStackSize = 0);
     46 
     47 namespace js {
     48 
     49 enum class StackFormat { SpiderMonkey, V8, Default };
     50 
     51 /*
     52 * Sets the format used for stringifying Error stacks.
     53 *
     54 * The default format is StackFormat::SpiderMonkey.  Use StackFormat::V8
     55 * in order to emulate V8's stack formatting.  StackFormat::Default can't be
     56 * used here.
     57 */
     58 extern JS_PUBLIC_API void SetStackFormat(JSContext* cx, StackFormat format);
     59 
     60 extern JS_PUBLIC_API StackFormat GetStackFormat(JSContext* cx);
     61 
     62 }  // namespace js
     63 
     64 namespace JS {
     65 
     66 /**
     67 * Capture all frames.
     68 */
     69 struct AllFrames {};
     70 
     71 /**
     72 * Capture at most this many frames.
     73 */
     74 struct MaxFrames {
     75  uint32_t maxFrames;
     76 
     77  explicit MaxFrames(uint32_t max) : maxFrames(max) { MOZ_ASSERT(max > 0); }
     78 };
     79 
     80 /**
     81 * Capture the first frame with the given principals. By default, do not
     82 * consider self-hosted frames with the given principals as satisfying the stack
     83 * capture.
     84 */
     85 struct JS_PUBLIC_API FirstSubsumedFrame {
     86  JSContext* cx;
     87  JSPrincipals* principals;
     88  bool ignoreSelfHosted;
     89 
     90  /**
     91   * Use the cx's current compartment's principals.
     92   */
     93  explicit FirstSubsumedFrame(JSContext* cx,
     94                              bool ignoreSelfHostedFrames = true);
     95 
     96  explicit FirstSubsumedFrame(JSContext* ctx, JSPrincipals* p,
     97                              bool ignoreSelfHostedFrames = true)
     98      : cx(ctx), principals(p), ignoreSelfHosted(ignoreSelfHostedFrames) {
     99    if (principals) {
    100      JS_HoldPrincipals(principals);
    101    }
    102  }
    103 
    104  // No copying because we want to avoid holding and dropping principals
    105  // unnecessarily.
    106  FirstSubsumedFrame(const FirstSubsumedFrame&) = delete;
    107  FirstSubsumedFrame& operator=(const FirstSubsumedFrame&) = delete;
    108  FirstSubsumedFrame& operator=(FirstSubsumedFrame&&) = delete;
    109 
    110  FirstSubsumedFrame(FirstSubsumedFrame&& rhs)
    111      : principals(rhs.principals), ignoreSelfHosted(rhs.ignoreSelfHosted) {
    112    MOZ_ASSERT(this != &rhs, "self move disallowed");
    113    rhs.principals = nullptr;
    114  }
    115 
    116  ~FirstSubsumedFrame() {
    117    if (principals) {
    118      JS_DropPrincipals(cx, principals);
    119    }
    120  }
    121 };
    122 
    123 using StackCapture = mozilla::Variant<AllFrames, MaxFrames, FirstSubsumedFrame>;
    124 
    125 /**
    126 * Capture the current call stack as a chain of SavedFrame JSObjects, and set
    127 * |stackp| to the SavedFrame for the youngest stack frame, or nullptr if there
    128 * are no JS frames on the stack.
    129 *
    130 * The |capture| parameter describes the portion of the JS stack to capture:
    131 *
    132 *   * |JS::AllFrames|: Capture all frames on the stack.
    133 *
    134 *   * |JS::MaxFrames|: Capture no more than |JS::MaxFrames::maxFrames| from the
    135 *      stack.
    136 *
    137 *   * |JS::FirstSubsumedFrame|: Capture the first frame whose principals are
    138 *     subsumed by |JS::FirstSubsumedFrame::principals|. By default, do not
    139 *     consider self-hosted frames; this can be controlled via the
    140 *     |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async
    141 *     stack.
    142 */
    143 extern JS_PUBLIC_API bool CaptureCurrentStack(
    144    JSContext* cx, MutableHandleObject stackp,
    145    StackCapture&& capture = StackCapture(AllFrames()),
    146    HandleObject startAfter = nullptr);
    147 
    148 /**
    149 * Returns true if capturing stack trace data to associate with an asynchronous
    150 * operation is currently enabled for the current context realm.
    151 *
    152 * Users should check this state before capturing a stack that will be passed
    153 * back to AutoSetAsyncStackForNewCalls later, in order to avoid capturing a
    154 * stack for async use when we don't actually want to capture it.
    155 */
    156 extern JS_PUBLIC_API bool IsAsyncStackCaptureEnabledForRealm(JSContext* cx);
    157 
    158 /*
    159 * This is a utility function for preparing an async stack to be used
    160 * by some other object.  This may be used when you need to treat a
    161 * given stack trace as an async parent.  If you just need to capture
    162 * the current stack, async parents and all, use CaptureCurrentStack
    163 * instead.
    164 *
    165 * Here |asyncStack| is the async stack to prepare.  It is copied into
    166 * |cx|'s current compartment, and the newest frame is given
    167 * |asyncCause| as its asynchronous cause.  If |maxFrameCount| is
    168 * |Some(n)|, capture at most the youngest |n| frames.  The
    169 * new stack object is written to |stackp|.  Returns true on success,
    170 * or sets an exception and returns |false| on error.
    171 */
    172 extern JS_PUBLIC_API bool CopyAsyncStack(
    173    JSContext* cx, HandleObject asyncStack, HandleString asyncCause,
    174    MutableHandleObject stackp, const mozilla::Maybe<size_t>& maxFrameCount);
    175 
    176 /**
    177 * Given a SavedFrame JSObject stack, stringify it in the same format as
    178 * Error.prototype.stack. The stringified stack out parameter is placed in the
    179 * cx's compartment. Defaults to the empty string.
    180 *
    181 * The same notes above about SavedFrame accessors applies here as well: cx
    182 * doesn't need to be in stack's compartment, and stack can be null, a
    183 * SavedFrame object, or a wrapper (CCW or Xray) around a SavedFrame object.
    184 * SavedFrames not subsumed by |principals| are skipped.
    185 *
    186 * Optional indent parameter specifies the number of white spaces to indent
    187 * each line.
    188 */
    189 extern JS_PUBLIC_API bool BuildStackString(
    190    JSContext* cx, JSPrincipals* principals, HandleObject stack,
    191    MutableHandleString stringp, size_t indent = 0,
    192    js::StackFormat stackFormat = js::StackFormat::Default);
    193 
    194 }  // namespace JS
    195 
    196 #endif  // js_Stack_h