Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/public/friend/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 10 kB image not shown  

Quelle  StackLimits.h   Sprache: C

 
/* -*- 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 js_friend_StackLimits_h
#define js_friend_StackLimits_h

#include "mozilla/Attributes.h"  // MOZ_ALWAYS_INLINE, MOZ_COLD
#include "mozilla/Likely.h"      // MOZ_LIKELY
#include "mozilla/Variant.h"     // mozilla::Variant, mozilla::AsVariant

#include <stddef.h>  // size_t

#include "jstypes.h"  // JS_PUBLIC_API

#include "js/HeapAPI.h"  // JS::StackKind, JS::StackForTrustedScript, JS::StackForUntrustedScript
#include "js/RootingAPI.h"  // JS::RootingContext
#include "js/Stack.h"       // JS::NativeStackLimit
#include "js/Utility.h"     // JS_STACK_OOM_POSSIBLY_FAIL

struct JS_PUBLIC_API JSContext;

#ifndef JS_STACK_GROWTH_DIRECTION
#  ifdef __hppa
#    define JS_STACK_GROWTH_DIRECTION (1)
#  else
#    define JS_STACK_GROWTH_DIRECTION (-1)
#  endif
#endif

namespace js {

class FrontendContext;

#ifdef __wasi__
extern MOZ_COLD JS_PUBLIC_API void IncWasiRecursionDepth(JSContext* cx);
extern MOZ_COLD JS_PUBLIC_API void DecWasiRecursionDepth(JSContext* cx);
extern MOZ_COLD JS_PUBLIC_API bool CheckWasiRecursionLimit(JSContext* cx);

extern MOZ_COLD JS_PUBLIC_API void IncWasiRecursionDepth(FrontendContext* fc);
extern MOZ_COLD JS_PUBLIC_API void DecWasiRecursionDepth(FrontendContext* fc);
extern MOZ_COLD JS_PUBLIC_API bool CheckWasiRecursionLimit(FrontendContext* fc);
#endif  // __wasi__

// The minimum margin for stack limit to ensure that the periodic
// AutoCheckRecursionLimit operation is sufficient.
//
// See FrontendContext::checkAndUpdateFrontendContextRecursionLimit and
// JS::ThreadStackQuotaForSize.
static constexpr size_t MinimumStackLimitMargin = 32 * 1024;

// AutoCheckRecursionLimit can be used to check whether we're close to using up
// the C++ stack.
//
// Typical usage is like this:
//
//   AutoCheckRecursionLimit recursion(cx);
//   if (!recursion.check(cx)) {
//     return false;
//   }
//
// The check* functions return |false| if we are close to the stack limit.
// They also report an overrecursion error, except for the DontReport variants.
//
// The checkSystem variant gives us a little extra space so we can ensure that
// crucial code is able to run.
//
// checkConservative allows less space than any other check, including a safety
// buffer (as in, it uses the untrusted limit and subtracts a little more from
// it).
class MOZ_RAII AutoCheckRecursionLimit {
  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkLimitImpl(
      JS::NativeStackLimit limit, void* sp) const;

  MOZ_ALWAYS_INLINE JS::NativeStackLimit getStackLimitSlow(JSContext* cx) const;
  MOZ_ALWAYS_INLINE JS::NativeStackLimit getStackLimitHelper(
      JSContext* cx, JS::StackKind kind, int extraAllowance) const;

  JS::NativeStackLimit getStackLimit(FrontendContext* fc) const;

  JS_PUBLIC_API JS::StackKind stackKindForCurrentPrincipal(JSContext* cx) const;

#ifdef __wasi__
  // The JSContext outlives AutoCheckRecursionLimit so it is safe to use raw
  // pointer here.
  mozilla::Variant<JSContext*, FrontendContext*> context_;
#endif  // __wasi__

 public:
  explicit MOZ_ALWAYS_INLINE AutoCheckRecursionLimit(JSContext* cx)
#ifdef __wasi__
      : context_(mozilla::AsVariant(cx))
#endif  // __wasi__
  {
#ifdef __wasi__
    incWasiRecursionDepth();
#endif  // __wasi__
  }

  explicit MOZ_ALWAYS_INLINE AutoCheckRecursionLimit(FrontendContext* fc)
#ifdef __wasi__
      : context_(mozilla::AsVariant(fc))
#endif  // __wasi__
  {
#ifdef __wasi__
    incWasiRecursionDepth();
#endif  // __wasi__
  }

  MOZ_ALWAYS_INLINE ~AutoCheckRecursionLimit() {
#ifdef __wasi__
    decWasiRecursionDepth();
#endif  // __wasi__
  }

#ifdef __wasi__
  MOZ_ALWAYS_INLINE void incWasiRecursionDepth() {
    if (context_.is<JSContext*>()) {
      JSContext* cx = context_.as<JSContext*>();
      IncWasiRecursionDepth(cx);
    } else {
      FrontendContext* fc = context_.as<FrontendContext*>();
      IncWasiRecursionDepth(fc);
    }
  }

  MOZ_ALWAYS_INLINE void decWasiRecursionDepth() {
    if (context_.is<JSContext*>()) {
      JSContext* cx = context_.as<JSContext*>();
      DecWasiRecursionDepth(cx);
    } else {
      FrontendContext* fc = context_.as<FrontendContext*>();
      DecWasiRecursionDepth(fc);
    }
  }

  MOZ_ALWAYS_INLINE bool checkWasiRecursionLimit() const {
    if (context_.is<JSContext*>()) {
      JSContext* cx = context_.as<JSContext*>();
      if (!CheckWasiRecursionLimit(cx)) {
        return false;
      }
    } else {
      FrontendContext* fc = context_.as<FrontendContext*>();
      if (!CheckWasiRecursionLimit(fc)) {
        return false;
      }
    }

    return true;
  }
#endif  // __wasi__

  AutoCheckRecursionLimit(const AutoCheckRecursionLimit&) = delete;
  void operator=(const AutoCheckRecursionLimit&) = delete;

  [[nodiscard]] MOZ_ALWAYS_INLINE bool check(JSContext* cx) const;
  [[nodiscard]] MOZ_ALWAYS_INLINE bool check(FrontendContext* fc) const;
  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkDontReport(JSContext* cx) const;
  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkDontReport(
      FrontendContext* fc) const;
  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithExtra(JSContext* cx,
                                                      size_t extra) const;
  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithStackPointerDontReport(
      JSContext* cx, void* sp) const;
  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkWithStackPointerDontReport(
      FrontendContext* fc, void* sp) const;

  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkConservative(JSContext* cx) const;
  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkConservativeDontReport(
      JSContext* cx) const;
  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkConservativeDontReport(
      JS::NativeStackLimit limit) const;

  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkSystem(JSContext* cx) const;
  [[nodiscard]] MOZ_ALWAYS_INLINE bool checkSystemDontReport(
      JSContext* cx) const;
};

extern MOZ_COLD JS_PUBLIC_API void ReportOverRecursed(JSContext* maybecx);
extern MOZ_COLD JS_PUBLIC_API void ReportOverRecursed(FrontendContext* fc);

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkLimitImpl(
    JS::NativeStackLimit limit, void* sp) const {
  JS_STACK_OOM_POSSIBLY_FAIL();

#ifdef __wasi__
  if (!checkWasiRecursionLimit()) {
    return false;
  }
#endif  // __wasi__

#if JS_STACK_GROWTH_DIRECTION > 0
  return MOZ_LIKELY(JS::NativeStackLimit(sp) < limit);
#else
  return MOZ_LIKELY(JS::NativeStackLimit(sp) > limit);
#endif
}

#ifdef ENABLE_WASM_JSPI
bool IsSuspendableStackActive(JSContext* cx);
JS::NativeStackLimit GetSuspendableStackLimit(JSContext* cx);
#endif

MOZ_ALWAYS_INLINE JS::NativeStackLimit
AutoCheckRecursionLimit::getStackLimitSlow(JSContext* cx) const {
  JS::StackKind kind = stackKindForCurrentPrincipal(cx);
#ifdef ENABLE_WASM_JSPI
  if (IsSuspendableStackActive(cx)) {
    MOZ_RELEASE_ASSERT(kind == JS::StackForUntrustedScript);
    return GetSuspendableStackLimit(cx);
  }
#endif
  return getStackLimitHelper(cx, kind, 0);
}

MOZ_ALWAYS_INLINE JS::NativeStackLimit
AutoCheckRecursionLimit::getStackLimitHelper(JSContext* cx, JS::StackKind kind,
                                             int extraAllowance) const {
  JS::NativeStackLimit limit =
      JS::RootingContext::get(cx)->nativeStackLimit[kind];
#if JS_STACK_GROWTH_DIRECTION > 0
  limit += extraAllowance;
#else
  limit -= extraAllowance;
#endif
  return limit;
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::check(JSContext* cx) const {
  if (MOZ_UNLIKELY(!checkDontReport(cx))) {
    ReportOverRecursed(cx);
    return false;
  }
  return true;
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::check(
    FrontendContext* fc) const {
  if (MOZ_UNLIKELY(!checkDontReport(fc))) {
    ReportOverRecursed(fc);
    return false;
  }
  return true;
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkDontReport(
    JSContext* cx) const {
  return checkWithStackPointerDontReport(cx, __builtin_frame_address(0));
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkDontReport(
    FrontendContext* fc) const {
  return checkWithStackPointerDontReport(fc, __builtin_frame_address(0));
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkWithStackPointerDontReport(
    JSContext* cx, void* sp) const {
  // getStackLimitSlow(cx) is pretty slow because it has to do an uninlined
  // call to stackKindForCurrentPrincipal to determine which stack limit to
  // use. To work around this, check the untrusted limit first to avoid the
  // overhead in most cases.
  JS::NativeStackLimit untrustedLimit =
      getStackLimitHelper(cx, JS::StackForUntrustedScript, 0);
  if (MOZ_LIKELY(checkLimitImpl(untrustedLimit, sp))) {
    return true;
  }
  return checkLimitImpl(getStackLimitSlow(cx), sp);
}

#ifdef DEBUG
extern void CheckAndUpdateFrontendContextRecursionLimit(FrontendContext* fc,
                                                        void* sp);
#endif

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkWithStackPointerDontReport(
    FrontendContext* fc, void* sp) const {
#ifdef DEBUG
  CheckAndUpdateFrontendContextRecursionLimit(fc, sp);
#endif
  return checkLimitImpl(getStackLimit(fc), sp);
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkWithExtra(
    JSContext* cx, size_t extra) const {
  char* sp = reinterpret_cast<char*>(__builtin_frame_address(0));
#if JS_STACK_GROWTH_DIRECTION > 0
  sp += extra;
#else
  sp -= extra;
#endif
  if (MOZ_UNLIKELY(!checkWithStackPointerDontReport(cx, sp))) {
    ReportOverRecursed(cx);
    return false;
  }
  return true;
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkSystem(
    JSContext* cx) const {
  if (MOZ_UNLIKELY(!checkSystemDontReport(cx))) {
    ReportOverRecursed(cx);
    return false;
  }
  return true;
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkSystemDontReport(
    JSContext* cx) const {
  JS::NativeStackLimit limit =
      getStackLimitHelper(cx, JS::StackForSystemCode, 0);
  return checkLimitImpl(limit, __builtin_frame_address(0));
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkConservative(
    JSContext* cx) const {
  if (MOZ_UNLIKELY(!checkConservativeDontReport(cx))) {
    ReportOverRecursed(cx);
    return false;
  }
  return true;
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkConservativeDontReport(
    JSContext* cx) const {
  JS::NativeStackLimit limit = getStackLimitHelper(
      cx, JS::StackForUntrustedScript, -4096 * int(sizeof(size_t)));
  return checkLimitImpl(limit, __builtin_frame_address(0));
}

MOZ_ALWAYS_INLINE bool AutoCheckRecursionLimit::checkConservativeDontReport(
    JS::NativeStackLimit limit) const {
  return checkLimitImpl(limit, __builtin_frame_address(0));
}

}  // namespace js

#endif  // js_friend_StackLimits_h

Messung V0.5
C=94 H=93 G=93

¤ Dauer der Verarbeitung: 0.28 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.