tor-browser

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

xpcpublic.h (33050B)


      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 xpcpublic_h
      8 #define xpcpublic_h
      9 
     10 #include <cstddef>
     11 #include <cstdint>
     12 #include <type_traits>
     13 #include "ErrorList.h"
     14 #include "js/BuildId.h"
     15 #include "js/ErrorReport.h"
     16 #include "js/GCAPI.h"
     17 #include "js/Object.h"
     18 #include "js/RootingAPI.h"
     19 #include "js/String.h"
     20 #include "js/TypeDecls.h"
     21 #include "js/Utility.h"
     22 #include "js/Value.h"
     23 #include "jsapi.h"
     24 #include "mozilla/AlreadyAddRefed.h"
     25 #include "mozilla/Assertions.h"
     26 #include "mozilla/Attributes.h"
     27 #include "mozilla/Maybe.h"
     28 #include "mozilla/MemoryReporting.h"
     29 #include "mozilla/TextUtils.h"
     30 #include "mozilla/dom/DOMString.h"
     31 #include "mozilla/StringBuffer.h"
     32 #include "mozilla/fallible.h"
     33 #include "nsAtom.h"
     34 #include "nsCOMPtr.h"
     35 #include "nsISupports.h"
     36 #include "nsIURI.h"
     37 #include "nsStringFwd.h"
     38 #include "nsTArray.h"
     39 #include "nsWrapperCache.h"
     40 
     41 // XXX only for NukeAllWrappersForRealm, which is only used in
     42 // dom/base/WindowDestroyedEvent.cpp outside of js
     43 #include "jsfriendapi.h"
     44 
     45 class JSObject;
     46 class JSString;
     47 class JSTracer;
     48 class nsGlobalWindowInner;
     49 class nsIGlobalObject;
     50 class nsIHandleReportCallback;
     51 class nsIPrincipal;
     52 class nsPIDOMWindowInner;
     53 struct JSContext;
     54 struct nsID;
     55 struct nsXPTInterfaceInfo;
     56 
     57 namespace JS {
     58 class Compartment;
     59 class ContextOptions;
     60 class PrefableCompileOptions;
     61 class Realm;
     62 class RealmOptions;
     63 class Value;
     64 struct RuntimeStats;
     65 }  // namespace JS
     66 
     67 namespace mozilla {
     68 class BasePrincipal;
     69 
     70 namespace dom {
     71 class Exception;
     72 }  // namespace dom
     73 }  // namespace mozilla
     74 
     75 using xpcGCCallback = void (*)(JSGCStatus);
     76 
     77 namespace xpc {
     78 
     79 class Scriptability {
     80 public:
     81  explicit Scriptability(JS::Realm* realm);
     82  bool Allowed();
     83  bool IsImmuneToScriptPolicy();
     84 
     85  void Block();
     86  void Unblock();
     87  void SetWindowAllowsScript(bool aAllowed);
     88 
     89  static Scriptability& Get(JSObject* aScope);
     90 
     91  // Returns true if scripting is allowed, false otherwise (if no Scriptability
     92  // exists, like for example inside a ShadowRealm global, then script execution
     93  // is assumed to be allowed)
     94  static bool AllowedIfExists(JSObject* aScope);
     95 
     96 private:
     97  // Whenever a consumer wishes to prevent script from running on a global,
     98  // it increments this value with a call to Block(). When it wishes to
     99  // re-enable it (if ever), it decrements this value with a call to Unblock().
    100  // Script may not run if this value is non-zero.
    101  uint32_t mScriptBlocks;
    102 
    103  // Whether the DOM window allows javascript in this scope. If this scope
    104  // doesn't have a window, this value is always true.
    105  bool mWindowAllowsScript;
    106 
    107  // Whether this scope is immune to user-defined or addon-defined script
    108  // policy.
    109  bool mImmuneToScriptPolicy;
    110 
    111  // Whether the new-style domain policy when this compartment was created
    112  // forbids script execution.
    113  bool mScriptBlockedByPolicy;
    114 };
    115 
    116 JSObject* TransplantObject(JSContext* cx, JS::Handle<JSObject*> origobj,
    117                           JS::Handle<JSObject*> target);
    118 
    119 JSObject* TransplantObjectRetainingXrayExpandos(JSContext* cx,
    120                                                JS::Handle<JSObject*> origobj,
    121                                                JS::Handle<JSObject*> target);
    122 
    123 // If origObj has an xray waiver, nuke it before transplant.
    124 JSObject* TransplantObjectNukingXrayWaiver(JSContext* cx,
    125                                           JS::Handle<JSObject*> origObj,
    126                                           JS::Handle<JSObject*> target);
    127 
    128 bool IsUAWidgetCompartment(JS::Compartment* compartment);
    129 bool IsUAWidgetScope(JS::Realm* realm);
    130 bool IsInUAWidgetScope(JSObject* obj);
    131 
    132 bool MightBeWebContentCompartment(JS::Compartment* compartment);
    133 
    134 void SetCompartmentChangedDocumentDomain(JS::Compartment* compartment);
    135 
    136 JSObject* GetUAWidgetScope(JSContext* cx, nsIPrincipal* principal);
    137 
    138 JSObject* GetUAWidgetScope(JSContext* cx, JSObject* contentScope);
    139 
    140 // Returns whether XBL scopes have been explicitly disabled for code running
    141 // in this compartment. See the comment around mAllowContentXBLScope.
    142 bool AllowContentXBLScope(JS::Realm* realm);
    143 
    144 // Get the scope for creating reflectors for native anonymous content
    145 // whose normal global would be the given global.
    146 JSObject* NACScope(JSObject* global);
    147 
    148 bool IsSandboxPrototypeProxy(JSObject* obj);
    149 bool IsWebExtensionContentScriptSandbox(JSObject* obj);
    150 
    151 // The JSContext argument represents the Realm that's asking the question.  This
    152 // is needed to properly answer without exposing information unnecessarily
    153 // from behind security wrappers.  There will be no exceptions thrown on this
    154 // JSContext.
    155 bool IsReflector(JSObject* obj, JSContext* cx);
    156 
    157 bool IsXrayWrapper(JSObject* obj);
    158 
    159 // If this function was created for a given XrayWrapper, returns the global of
    160 // the Xrayed object. Otherwise, returns the global of the function.
    161 //
    162 // To emphasize the obvious: the return value here is not necessarily same-
    163 // compartment with the argument.
    164 JSObject* XrayAwareCalleeGlobal(JSObject* fun);
    165 
    166 void TraceXPCGlobal(JSTracer* trc, JSObject* obj);
    167 
    168 /**
    169 * Creates a new global object using the given aCOMObj as the global object.
    170 * The object will be set up according to the flags (defined below).
    171 * aCOMObj must implement nsIXPCScriptable so it can resolve the standard
    172 * classes when asked by the JS engine.
    173 *
    174 * @param aJSContext the context to use while creating the global object.
    175 * @param aCOMObj the native object that represents the global object.
    176 * @param aPrincipal the principal of the code that will run in this
    177 *                   compartment. Can be null if not on the main thread.
    178 * @param aFlags one of the flags below specifying what options this
    179 *               global object wants.
    180 * @param aOptions JSAPI-specific options for the new compartment.
    181 */
    182 nsresult InitClassesWithNewWrappedGlobal(
    183    JSContext* aJSContext, nsISupports* aCOMObj, nsIPrincipal* aPrincipal,
    184    uint32_t aFlags, JS::RealmOptions& aOptions,
    185    JS::MutableHandle<JSObject*> aNewGlobal);
    186 
    187 enum InitClassesFlag {
    188  DONT_FIRE_ONNEWGLOBALHOOK = 1 << 0,
    189  OMIT_COMPONENTS_OBJECT = 1 << 1,
    190 };
    191 
    192 } /* namespace xpc */
    193 
    194 namespace JS {
    195 
    196 struct RuntimeStats;
    197 
    198 }  // namespace JS
    199 
    200 static_assert(JSCLASS_GLOBAL_APPLICATION_SLOTS > 0,
    201              "Need at least one slot for JSCLASS_SLOT0_IS_NSISUPPORTS");
    202 
    203 #define XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(n)    \
    204  JSCLASS_DOM_GLOBAL | JSCLASS_SLOT0_IS_NSISUPPORTS | \
    205      JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS + n)
    206 
    207 #define XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET \
    208  (JSCLASS_GLOBAL_SLOT_COUNT + DOM_GLOBAL_SLOTS)
    209 
    210 #define XPCONNECT_GLOBAL_FLAGS XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(0)
    211 
    212 inline JSObject* xpc_FastGetCachedWrapper(JSContext* cx, nsWrapperCache* cache,
    213                                          JS::MutableHandle<JS::Value> vp) {
    214  if (cache) {
    215    JSObject* wrapper = cache->GetWrapper();
    216    if (wrapper &&
    217        JS::GetCompartment(wrapper) == js::GetContextCompartment(cx)) {
    218      vp.setObject(*wrapper);
    219      return wrapper;
    220    }
    221  }
    222 
    223  return nullptr;
    224 }
    225 
    226 // If aWrappedJS is a JS wrapper, unmark its JSObject.
    227 extern void xpc_TryUnmarkWrappedGrayObject(nsISupports* aWrappedJS);
    228 
    229 extern void xpc_UnmarkSkippableJSHolders();
    230 
    231 // Defined in XPCDebug.cpp.
    232 extern bool xpc_DumpJSStack(bool showArgs, bool showLocals, bool showThisProps);
    233 
    234 // Return a newly-allocated string containing a representation of the
    235 // current JS stack. Defined in XPCDebug.cpp.
    236 extern JS::UniqueChars xpc_PrintJSStack(JSContext* cx, bool showArgs,
    237                                        bool showLocals, bool showThisProps);
    238 
    239 inline void AssignFromStringBuffer(mozilla::StringBuffer* buffer, size_t len,
    240                                   nsAString& dest) {
    241  dest.Assign(buffer, len);
    242 }
    243 inline void AssignFromStringBuffer(mozilla::StringBuffer* buffer, size_t len,
    244                                   nsACString& dest) {
    245  dest.Assign(buffer, len);
    246 }
    247 
    248 // readable string conversions, static methods and members only
    249 class XPCStringConvert {
    250 public:
    251  // Convert the given stringbuffer/length pair to a jsval
    252  static MOZ_ALWAYS_INLINE bool UCStringBufferToJSVal(
    253      JSContext* cx, mozilla::StringBuffer* buf, uint32_t length,
    254      JS::MutableHandle<JS::Value> rval) {
    255    JSString* str = JS::NewStringFromKnownLiveTwoByteBuffer(cx, buf, length);
    256    if (!str) {
    257      return false;
    258    }
    259    rval.setString(str);
    260    return true;
    261  }
    262 
    263  static MOZ_ALWAYS_INLINE bool Latin1StringBufferToJSVal(
    264      JSContext* cx, mozilla::StringBuffer* buf, uint32_t length,
    265      JS::MutableHandle<JS::Value> rval) {
    266    JSString* str = JS::NewStringFromKnownLiveLatin1Buffer(cx, buf, length);
    267    if (!str) {
    268      return false;
    269    }
    270    rval.setString(str);
    271    return true;
    272  }
    273 
    274  static MOZ_ALWAYS_INLINE bool UTF8StringBufferToJSVal(
    275      JSContext* cx, mozilla::StringBuffer* buf, uint32_t length,
    276      JS::MutableHandle<JS::Value> rval) {
    277    JSString* str = JS::NewStringFromKnownLiveUTF8Buffer(cx, buf, length);
    278    if (!str) {
    279      return false;
    280    }
    281    rval.setString(str);
    282    return true;
    283  }
    284 
    285  static inline bool StringLiteralToJSVal(JSContext* cx,
    286                                          const char16_t* literal,
    287                                          uint32_t length,
    288                                          JS::MutableHandle<JS::Value> rval) {
    289    bool ignored;
    290    JSString* str = JS_NewMaybeExternalUCString(
    291        cx, literal, length, &sLiteralExternalString, &ignored);
    292    if (!str) {
    293      return false;
    294    }
    295    rval.setString(str);
    296    return true;
    297  }
    298 
    299  static inline bool StringLiteralToJSVal(JSContext* cx,
    300                                          const JS::Latin1Char* literal,
    301                                          uint32_t length,
    302                                          JS::MutableHandle<JS::Value> rval) {
    303    bool ignored;
    304    JSString* str = JS_NewMaybeExternalStringLatin1(
    305        cx, literal, length, &sLiteralExternalString, &ignored);
    306    if (!str) {
    307      return false;
    308    }
    309    rval.setString(str);
    310    return true;
    311  }
    312 
    313  static inline bool UTF8StringLiteralToJSVal(
    314      JSContext* cx, const JS::UTF8Chars& chars,
    315      JS::MutableHandle<JS::Value> rval) {
    316    bool ignored;
    317    JSString* str = JS_NewMaybeExternalStringUTF8(
    318        cx, chars, &sLiteralExternalString, &ignored);
    319    if (!str) {
    320      return false;
    321    }
    322    rval.setString(str);
    323    return true;
    324  }
    325 
    326 private:
    327  static MOZ_ALWAYS_INLINE bool MaybeGetExternalStringChars(
    328      JSString* str, const JSExternalStringCallbacks** callbacks,
    329      const char16_t** chars) {
    330    return JS::IsExternalUCString(str, callbacks, chars);
    331  }
    332  static MOZ_ALWAYS_INLINE bool MaybeGetExternalStringChars(
    333      JSString* str, const JSExternalStringCallbacks** callbacks,
    334      const JS::Latin1Char** chars) {
    335    return JS::IsExternalStringLatin1(str, callbacks, chars);
    336  }
    337 
    338  static MOZ_ALWAYS_INLINE bool IsStringWithStringBuffer(
    339      JSString* str, mozilla::StringBuffer** buffer, const char16_t** chars) {
    340    if (!JS::IsTwoByteStringWithStringBuffer(str, buffer)) {
    341      return false;
    342    }
    343    *chars = static_cast<const char16_t*>((*buffer)->Data());
    344    return true;
    345  }
    346  static MOZ_ALWAYS_INLINE bool IsStringWithStringBuffer(
    347      JSString* str, mozilla::StringBuffer** buffer,
    348      const JS::Latin1Char** chars) {
    349    if (!JS::IsLatin1StringWithStringBuffer(str, buffer)) {
    350      return false;
    351    }
    352    *chars = static_cast<const JS::Latin1Char*>((*buffer)->Data());
    353    return true;
    354  }
    355 
    356  enum class AcceptedEncoding { All, ASCII };
    357 
    358  template <typename SrcCharT, typename DestCharT, AcceptedEncoding encoding,
    359            typename T>
    360  static MOZ_ALWAYS_INLINE bool MaybeAssignStringChars(JSString* s, size_t len,
    361                                                       T& dest) {
    362    MOZ_ASSERT(len == JS::GetStringLength(s));
    363    static_assert(sizeof(SrcCharT) == sizeof(DestCharT));
    364    if constexpr (encoding == AcceptedEncoding::ASCII) {
    365      static_assert(
    366          std::is_same_v<DestCharT, char>,
    367          "AcceptedEncoding::ASCII can be used only with single byte");
    368    }
    369 
    370    const DestCharT* chars;
    371    {
    372      mozilla::StringBuffer* buf;
    373      if (IsStringWithStringBuffer(
    374              s, &buf, reinterpret_cast<const SrcCharT**>(&chars))) {
    375        if constexpr (encoding == AcceptedEncoding::ASCII) {
    376          if (!mozilla::IsAscii(mozilla::Span(chars, len))) {
    377            return false;
    378          }
    379        }
    380 
    381        // The characters represent an existing string buffer that we shared
    382        // with JS.  We can share that buffer ourselves if the string
    383        // corresponds to the whole buffer; otherwise we have to copy.
    384        if (chars[len] == '\0') {
    385          AssignFromStringBuffer(buf, len, dest);
    386          return true;
    387        }
    388        return false;
    389      }
    390    }
    391 
    392    const JSExternalStringCallbacks* callbacks;
    393    if (!MaybeGetExternalStringChars(
    394            s, &callbacks, reinterpret_cast<const SrcCharT**>(&chars))) {
    395      return false;
    396    }
    397    if (callbacks == &sLiteralExternalString) {
    398      if constexpr (encoding == AcceptedEncoding::ASCII) {
    399        if (!mozilla::IsAscii(mozilla::Span(chars, len))) {
    400          return false;
    401        }
    402      }
    403 
    404      // The characters represent a literal string constant
    405      // compiled into libxul; we can just use it as-is.
    406      dest.AssignLiteral(chars, len);
    407      return true;
    408    }
    409 
    410    return false;
    411  }
    412 
    413 public:
    414  template <typename T>
    415  static MOZ_ALWAYS_INLINE bool MaybeAssignUCStringChars(JSString* s,
    416                                                         size_t len, T& dest) {
    417    return MaybeAssignStringChars<char16_t, char16_t, AcceptedEncoding::All>(
    418        s, len, dest);
    419  }
    420 
    421  template <typename T>
    422  static MOZ_ALWAYS_INLINE bool MaybeAssignLatin1StringChars(JSString* s,
    423                                                             size_t len,
    424                                                             T& dest) {
    425    return MaybeAssignStringChars<JS::Latin1Char, char, AcceptedEncoding::All>(
    426        s, len, dest);
    427  }
    428 
    429  template <typename T>
    430  static MOZ_ALWAYS_INLINE bool MaybeAssignUTF8StringChars(JSString* s,
    431                                                           size_t len,
    432                                                           T& dest) {
    433    return MaybeAssignStringChars<JS::Latin1Char, char,
    434                                  AcceptedEncoding::ASCII>(s, len, dest);
    435  }
    436 
    437 private:
    438  struct LiteralExternalString : public JSExternalStringCallbacks {
    439    void finalize(JS::Latin1Char* aChars) const override;
    440    void finalize(char16_t* aChars) const override;
    441    size_t sizeOfBuffer(const JS::Latin1Char* aChars,
    442                        mozilla::MallocSizeOf aMallocSizeOf) const override;
    443    size_t sizeOfBuffer(const char16_t* aChars,
    444                        mozilla::MallocSizeOf aMallocSizeOf) const override;
    445  };
    446  static const LiteralExternalString sLiteralExternalString;
    447 
    448  XPCStringConvert() = delete;
    449 };
    450 
    451 namespace xpc {
    452 
    453 // If these functions return false, then an exception will be set on cx.
    454 bool Base64Encode(JSContext* cx, JS::Handle<JS::Value> val,
    455                  JS::MutableHandle<JS::Value> out);
    456 bool Base64Decode(JSContext* cx, JS::Handle<JS::Value> val,
    457                  JS::MutableHandle<JS::Value> out);
    458 
    459 /**
    460 * Convert an nsString to jsval, returning true on success.
    461 */
    462 [[nodiscard]] bool NonVoidStringToJsval(JSContext* cx, const nsAString& str,
    463                                        JS::MutableHandle<JS::Value> rval);
    464 
    465 inline bool StringToJsval(JSContext* cx, const nsAString& str,
    466                          JS::MutableHandle<JS::Value> rval) {
    467  // From the T_ASTRING case in XPCConvert::NativeData2JS.
    468  if (str.IsVoid()) {
    469    rval.setNull();
    470    return true;
    471  }
    472  return NonVoidStringToJsval(cx, str, rval);
    473 }
    474 
    475 /**
    476 * As above, but for mozilla::dom::DOMString.
    477 */
    478 inline bool NonVoidStringToJsval(JSContext* cx, mozilla::dom::DOMString& str,
    479                                 JS::MutableHandle<JS::Value> rval) {
    480  if (str.IsEmpty()) {
    481    rval.set(JS_GetEmptyStringValue(cx));
    482    return true;
    483  }
    484 
    485  if (str.HasStringBuffer()) {
    486    uint32_t length = str.StringBufferLength();
    487    mozilla::StringBuffer* buf = str.StringBuffer();
    488    return XPCStringConvert::UCStringBufferToJSVal(cx, buf, length, rval);
    489  }
    490 
    491  if (str.HasLiteral()) {
    492    return XPCStringConvert::StringLiteralToJSVal(cx, str.Literal(),
    493                                                  str.LiteralLength(), rval);
    494  }
    495 
    496  // It's an actual XPCOM string
    497  return NonVoidStringToJsval(cx, str.AsAString(), rval);
    498 }
    499 
    500 MOZ_ALWAYS_INLINE
    501 bool StringToJsval(JSContext* cx, mozilla::dom::DOMString& str,
    502                   JS::MutableHandle<JS::Value> rval) {
    503  if (str.IsNull()) {
    504    rval.setNull();
    505    return true;
    506  }
    507  return NonVoidStringToJsval(cx, str, rval);
    508 }
    509 
    510 /**
    511 * As above, but for nsACString with latin-1 (non-UTF8) content.
    512 */
    513 [[nodiscard]] bool NonVoidLatin1StringToJsval(
    514    JSContext* cx, const nsACString& str, JS::MutableHandle<JS::Value> rval);
    515 
    516 inline bool Latin1StringToJsval(JSContext* cx, const nsACString& str,
    517                                JS::MutableHandle<JS::Value> rval) {
    518  if (str.IsVoid()) {
    519    rval.setNull();
    520    return true;
    521  }
    522  return NonVoidLatin1StringToJsval(cx, str, rval);
    523 }
    524 
    525 /**
    526 * As above, but for nsACString with UTF-8 content.
    527 */
    528 bool NonVoidUTF8StringToJsval(JSContext* cx, const nsACString& str,
    529                              JS::MutableHandle<JS::Value> rval);
    530 
    531 inline bool UTF8StringToJsval(JSContext* cx, const nsACString& str,
    532                              JS::MutableHandle<JS::Value> rval) {
    533  if (str.IsVoid()) {
    534    rval.setNull();
    535    return true;
    536  }
    537  return NonVoidUTF8StringToJsval(cx, str, rval);
    538 }
    539 
    540 mozilla::BasePrincipal* GetRealmPrincipal(JS::Realm* realm);
    541 
    542 void NukeAllWrappersForRealm(JSContext* cx, JS::Realm* realm,
    543                             js::NukeReferencesToWindow nukeReferencesToWindow =
    544                                 js::NukeWindowReferences);
    545 
    546 void SetLocationForGlobal(JSObject* global, const nsACString& location);
    547 void SetLocationForGlobal(JSObject* global, nsIURI* locationURI);
    548 
    549 // ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member
    550 // of JS::ZoneStats.
    551 class ZoneStatsExtras {
    552 public:
    553  ZoneStatsExtras() = default;
    554 
    555  nsCString pathPrefix;
    556 
    557 private:
    558  ZoneStatsExtras(const ZoneStatsExtras& other) = delete;
    559  ZoneStatsExtras& operator=(const ZoneStatsExtras& other) = delete;
    560 };
    561 
    562 // ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member
    563 // of JS::RealmStats.
    564 class RealmStatsExtras {
    565 public:
    566  RealmStatsExtras() = default;
    567 
    568  nsCString jsPathPrefix;
    569  nsCString domPathPrefix;
    570  nsCOMPtr<nsIURI> location;
    571 
    572 private:
    573  RealmStatsExtras(const RealmStatsExtras& other) = delete;
    574  RealmStatsExtras& operator=(const RealmStatsExtras& other) = delete;
    575 };
    576 
    577 // This reports all the stats in |rtStats| that belong in the "explicit" tree,
    578 // (which isn't all of them).
    579 // @see ZoneStatsExtras
    580 // @see RealmStatsExtras
    581 void ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats& rtStats,
    582                                      const nsACString& rtPath,
    583                                      nsIHandleReportCallback* handleReport,
    584                                      nsISupports* data, bool anonymize,
    585                                      size_t* rtTotal = nullptr);
    586 
    587 /**
    588 * Throws an exception on cx and returns false.
    589 */
    590 bool Throw(JSContext* cx, nsresult rv);
    591 
    592 /**
    593 * Returns the nsISupports native behind a given reflector (either DOM or
    594 * XPCWN).  If a non-reflector object is passed in, null will be returned.
    595 *
    596 * This function will not correctly handle Window or Location objects behind
    597 * cross-compartment wrappers: it will return null.  If you care about getting
    598 * non-null for Window or Location, use ReflectorToISupportsDynamic.
    599 */
    600 already_AddRefed<nsISupports> ReflectorToISupportsStatic(JSObject* reflector);
    601 
    602 /**
    603 * Returns the nsISupports native behind a given reflector (either DOM or
    604 * XPCWN).  If a non-reflector object is passed in, null will be returned.
    605 *
    606 * The JSContext argument represents the Realm that's asking for the
    607 * nsISupports.  This is needed to properly handle Window and Location objects,
    608 * which do dynamic security checks.
    609 */
    610 already_AddRefed<nsISupports> ReflectorToISupportsDynamic(JSObject* reflector,
    611                                                          JSContext* cx);
    612 
    613 /**
    614 * Singleton scopes for stuff that really doesn't fit anywhere else.
    615 *
    616 * If you find yourself wanting to use these compartments, you're probably doing
    617 * something wrong. Callers MUST consult with the XPConnect module owner before
    618 * using this compartment. If you don't, bholley will hunt you down.
    619 */
    620 JSObject* UnprivilegedJunkScope();
    621 
    622 JSObject* UnprivilegedJunkScope(const mozilla::fallible_t&);
    623 
    624 bool IsUnprivilegedJunkScope(JSObject*);
    625 
    626 /**
    627 * This will generally be the shared JSM global, but callers should not depend
    628 * on that fact.
    629 */
    630 JSObject* PrivilegedJunkScope();
    631 
    632 /**
    633 * Shared compilation scope for XUL prototype documents and XBL
    634 * precompilation.
    635 */
    636 JSObject* CompilationScope();
    637 
    638 /**
    639 * Returns the nsIGlobalObject corresponding to |obj|'s JS global. |obj| must
    640 * not be a cross-compartment wrapper: CCWs are not associated with a single
    641 * global.
    642 */
    643 nsIGlobalObject* NativeGlobal(JSObject* obj);
    644 
    645 /**
    646 * Returns the nsIGlobalObject corresponding to |cx|'s JS global. Must not be
    647 * called when |cx| is not in a Realm.
    648 */
    649 nsIGlobalObject* CurrentNativeGlobal(JSContext* cx);
    650 
    651 /**
    652 * If |aObj| is a window, returns the associated nsGlobalWindow.
    653 * Otherwise, returns null.
    654 */
    655 nsGlobalWindowInner* WindowOrNull(JSObject* aObj);
    656 
    657 /**
    658 * If |aObj| has a window for a global, returns the associated nsGlobalWindow.
    659 * Otherwise, returns null. Note: aObj must not be a cross-compartment wrapper
    660 * because CCWs are not associated with a single global/realm.
    661 */
    662 nsGlobalWindowInner* WindowGlobalOrNull(JSObject* aObj);
    663 
    664 /**
    665 * If |aObj| is a Sandbox object and it has a sandboxPrototype, then return
    666 * that prototype.
    667 * |aCx| is used for checked unwrapping of the prototype.
    668 */
    669 JSObject* SandboxPrototypeOrNull(JSContext* aCx, JSObject* aObj);
    670 
    671 /**
    672 * If |aObj| is a Sandbox object associated with a DOMWindow via a
    673 * sandboxPrototype, then return that DOMWindow.
    674 * |aCx| is used for checked unwrapping of the Window.
    675 */
    676 inline nsGlobalWindowInner* SandboxWindowOrNull(JSObject* aObj,
    677                                                JSContext* aCx) {
    678  JSObject* proto = SandboxPrototypeOrNull(aCx, aObj);
    679  return proto ? WindowOrNull(proto) : nullptr;
    680 }
    681 
    682 /**
    683 * If |cx| is in a realm whose global is a window, returns the associated
    684 * nsGlobalWindow. Otherwise, returns null.
    685 */
    686 nsGlobalWindowInner* CurrentWindowOrNull(JSContext* cx);
    687 
    688 class MOZ_RAII AutoScriptActivity {
    689  bool mActive;
    690  bool mOldValue;
    691 
    692 public:
    693  explicit AutoScriptActivity(bool aActive);
    694  ~AutoScriptActivity();
    695 };
    696 
    697 // This function may be used off-main-thread, in which case it is benignly
    698 // racey.
    699 bool ShouldDiscardSystemSource();
    700 
    701 void SetPrefableRealmOptions(JS::RealmOptions& options);
    702 void SetPrefableContextOptions(JS::ContextOptions& options);
    703 
    704 // This function may be used off-main-thread.
    705 void SetPrefableCompileOptions(JS::PrefableCompileOptions& options);
    706 
    707 // Modify the provided realm options, consistent with |aIsSystemPrincipal| and
    708 // with globally-cached values of various preferences.
    709 //
    710 // Call this function *before* |aOptions| is used to create the corresponding
    711 // global object, as not all of the options it sets can be modified on an
    712 // existing global object.  (The type system should make this obvious, because
    713 // you can't get a *mutable* JS::RealmOptions& from an existing global
    714 // object.)
    715 void InitGlobalObjectOptions(JS::RealmOptions& aOptions,
    716                             bool aIsSystemPrincipal, bool aSecureContext,
    717                             bool aForceUTC, bool aAlwaysUseFdlibm,
    718                             bool aLocaleEnUS,
    719                             const nsACString& aLanguageOverride,
    720                             const nsAString& aTimezoneOverride);
    721 
    722 class ErrorBase {
    723 public:
    724  nsString mErrorMsg;
    725  nsCString mFileName;
    726  uint32_t mSourceId;
    727  // Line number (1-origin).
    728  uint32_t mLineNumber;
    729  // Column number in UTF-16 code units (1-origin).
    730  uint32_t mColumn;
    731 
    732  ErrorBase() : mSourceId(0), mLineNumber(0), mColumn(0) {}
    733 
    734  void Init(JSErrorBase* aReport);
    735 
    736  void AppendErrorDetailsTo(nsCString& error);
    737 };
    738 
    739 class ErrorNote : public ErrorBase {
    740 public:
    741  void Init(JSErrorNotes::Note* aNote);
    742 
    743  // Produce an error event message string from the given JSErrorNotes::Note.
    744  // This may produce an empty string if aNote doesn't have a message
    745  // attached.
    746  static void ErrorNoteToMessageString(JSErrorNotes::Note* aNote,
    747                                       nsAString& aString);
    748 
    749  // Log the error note to the stderr.
    750  void LogToStderr();
    751 };
    752 
    753 class ErrorReport : public ErrorBase {
    754 public:
    755  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ErrorReport);
    756 
    757  nsTArray<ErrorNote> mNotes;
    758 
    759  nsCString mCategory;
    760  nsString mErrorMsgName;
    761  uint64_t mWindowID;
    762  bool mIsWarning;
    763  bool mIsMuted;
    764  bool mIsPromiseRejection;
    765 
    766  ErrorReport()
    767      : mWindowID(0),
    768        mIsWarning(false),
    769        mIsMuted(false),
    770        mIsPromiseRejection(false) {}
    771 
    772  void Init(JSErrorReport* aReport, const char* aToStringResult, bool aIsChrome,
    773            uint64_t aWindowID);
    774  void Init(JSContext* aCx, mozilla::dom::Exception* aException, bool aIsChrome,
    775            uint64_t aWindowID);
    776 
    777  // Log the error report to the console.  Which console will depend on the
    778  // window id it was initialized with.
    779  void LogToConsole();
    780  // Log to console, using the given stack object (which should be a stack of
    781  // the sort that JS::CaptureCurrentStack produces).  aStack is allowed to be
    782  // null. If aStack is non-null, aStackGlobal must be a non-null global
    783  // object that's same-compartment with aStack. Note that aStack might be a
    784  // CCW.
    785  void LogToConsoleWithStack(nsGlobalWindowInner* aWin,
    786                             JS::Handle<mozilla::Maybe<JS::Value>> aException,
    787                             JS::Handle<JSObject*> aStack,
    788                             JS::Handle<JSObject*> aStackGlobal);
    789 
    790  // Produce an error event message string from the given JSErrorReport.  Note
    791  // that this may produce an empty string if aReport doesn't have a
    792  // message attached.
    793  static void ErrorReportToMessageString(JSErrorReport* aReport,
    794                                         nsAString& aString);
    795 
    796  // Log the error report to the stderr.
    797  void LogToStderr();
    798 
    799  bool IsWarning() const { return mIsWarning; };
    800 
    801 private:
    802  ~ErrorReport() = default;
    803 };
    804 
    805 void DispatchScriptErrorEvent(nsPIDOMWindowInner* win,
    806                              JS::RootingContext* rootingCx,
    807                              xpc::ErrorReport* xpcReport,
    808                              JS::Handle<JS::Value> exception,
    809                              JS::Handle<JSObject*> exceptionStack);
    810 
    811 // Get a stack (as stackObj outparam) of the sort that can be passed to
    812 // xpc::ErrorReport::LogToConsoleWithStack from the given exception value.  Can
    813 // be nullptr if the exception value doesn't have an associated stack, and if
    814 // there is no stack supplied by the JS engine in exceptionStack.  The
    815 // returned stack, if any, may also not be in the same compartment as
    816 // exceptionValue.
    817 //
    818 // The "win" argument passed in here should be the same as the window whose
    819 // WindowID() is used to initialize the xpc::ErrorReport.  This may be null, of
    820 // course.  If it's not null, this function may return a null stack object if
    821 // the window is far enough gone, because in those cases we don't want to have
    822 // the stack in the console message keeping the window alive.
    823 //
    824 // If this function sets stackObj to a non-null value, stackGlobal is set to
    825 // either the JS exception object's global or the global of the SavedFrame we
    826 // got from a DOM or XPConnect exception. In all cases, stackGlobal is an
    827 // unwrapped global object and is same-compartment with stackObj.
    828 void FindExceptionStackForConsoleReport(
    829    nsPIDOMWindowInner* win, JS::Handle<JS::Value> exceptionValue,
    830    JS::Handle<JSObject*> exceptionStack, JS::MutableHandle<JSObject*> stackObj,
    831    JS::MutableHandle<JSObject*> stackGlobal);
    832 
    833 // Return a name for the realm.
    834 // This function makes reasonable efforts to make this name both mostly
    835 // human-readable and unique. However, there are no guarantees of either
    836 // property.
    837 extern void GetCurrentRealmName(JSContext*, nsCString& name);
    838 
    839 nsCString GetFunctionName(JSContext* cx, JS::Handle<JSObject*> obj);
    840 
    841 void AddGCCallback(xpcGCCallback cb);
    842 void RemoveGCCallback(xpcGCCallback cb);
    843 
    844 // We need an exact page size only if we run the binary in automation.
    845 #if (defined(XP_DARWIN) && defined(__aarch64__)) || defined(__loongarch__)
    846 const size_t kAutomationPageSize = 16384;
    847 #else
    848 const size_t kAutomationPageSize = 4096;
    849 #endif
    850 
    851 struct alignas(kAutomationPageSize) ReadOnlyPage final {
    852  bool mNonLocalConnectionsDisabled = false;
    853  bool mTurnOffAllSecurityPref = false;
    854 
    855  static void Init();
    856 
    857 #ifdef MOZ_TSAN
    858  // TSan is confused by write access to read-only section.
    859  static ReadOnlyPage sInstance;
    860 #elif defined(XP_OPENBSD)
    861  static const volatile ReadOnlyPage sInstance
    862      __attribute__((section(".openbsd.mutable")));
    863 #else
    864  static const volatile ReadOnlyPage sInstance;
    865 #endif
    866 
    867 private:
    868  constexpr ReadOnlyPage() = default;
    869  ReadOnlyPage(const ReadOnlyPage&) = delete;
    870  void operator=(const ReadOnlyPage&) = delete;
    871 
    872  static void Write(const volatile bool* aPtr, bool aValue);
    873 };
    874 
    875 inline bool AreNonLocalConnectionsDisabled() {
    876  return ReadOnlyPage::sInstance.mNonLocalConnectionsDisabled;
    877 }
    878 
    879 inline bool IsInAutomation() {
    880  if (!ReadOnlyPage::sInstance.mTurnOffAllSecurityPref) {
    881    return false;
    882  }
    883  MOZ_RELEASE_ASSERT(AreNonLocalConnectionsDisabled());
    884  return true;
    885 }
    886 
    887 void InitializeJSContext();
    888 
    889 /**
    890 * Extract the native nsID object from a JS ID, IfaceID, ClassID, or ContractID
    891 * value.
    892 *
    893 * Returns 'Nothing()' if 'aVal' does is not one of the supported ID types.
    894 */
    895 mozilla::Maybe<nsID> JSValue2ID(JSContext* aCx, JS::Handle<JS::Value> aVal);
    896 
    897 /**
    898 * Reflect an ID into JS
    899 */
    900 bool ID2JSValue(JSContext* aCx, const nsID& aId,
    901                JS::MutableHandle<JS::Value> aVal);
    902 
    903 /**
    904 * Reflect an IfaceID into JS
    905 *
    906 * This object will expose constants from the selected interface, and support
    907 * 'instanceof', in addition to the other methods available on JS ID objects.
    908 *
    909 * Use 'xpc::JSValue2ID' to unwrap JS::Values created with this function.
    910 */
    911 bool IfaceID2JSValue(JSContext* aCx, const nsXPTInterfaceInfo& aInfo,
    912                     JS::MutableHandle<JS::Value> aVal);
    913 
    914 /**
    915 * Reflect a ContractID into JS
    916 *
    917 * This object will expose 'getService' and 'createInstance' methods in addition
    918 * to the other methods available on nsID objects.
    919 *
    920 * Use 'xpc::JSValue2ID' to unwrap JS::Values created with this function.
    921 */
    922 bool ContractID2JSValue(JSContext* aCx, JSString* aContract,
    923                        JS::MutableHandle<JS::Value> aVal);
    924 
    925 class JSStackFrameBase {
    926 public:
    927  virtual void Clear() = 0;
    928 };
    929 
    930 void RegisterJSStackFrame(JS::Realm* aRealm, JSStackFrameBase* aStackFrame);
    931 void UnregisterJSStackFrame(JS::Realm* aRealm, JSStackFrameBase* aStackFrame);
    932 void NukeJSStackFrames(JS::Realm* aRealm);
    933 
    934 // Check whether the given jsid is a property name (string or symbol) whose
    935 // value can be gotten cross-origin.  Cross-origin gets always return undefined
    936 // as the value, unless the Xray actually provides a different value.
    937 bool IsCrossOriginWhitelistedProp(JSContext* cx,
    938                                  JS::Handle<JS::PropertyKey> id);
    939 
    940 // Appends to props the jsids for property names (strings or symbols) whose
    941 // value can be gotten cross-origin.
    942 bool AppendCrossOriginWhitelistedPropNames(
    943    JSContext* cx, JS::MutableHandle<JS::StackGCVector<JS::PropertyKey>> props);
    944 }  // namespace xpc
    945 
    946 namespace mozilla {
    947 namespace dom {
    948 
    949 /**
    950 * This is used to prevent UA widget code from directly creating and adopting
    951 * nodes via the content document, since they should use the special
    952 * create-and-insert apis instead.
    953 */
    954 bool IsNotUAWidget(JSContext* cx, JSObject* /* unused */);
    955 
    956 /**
    957 * A test for whether WebIDL methods that should only be visible to
    958 * chrome, XBL scopes, or UA Widget scopes.
    959 */
    960 bool IsChromeOrUAWidget(JSContext* cx, JSObject* /* unused */);
    961 
    962 /**
    963 * Same as IsChromeOrUAWidget but can be used in worker threads as well.
    964 */
    965 bool ThreadSafeIsChromeOrUAWidget(JSContext* cx, JSObject* obj);
    966 
    967 }  // namespace dom
    968 
    969 /**
    970 * Fill the given vector with the buildid.
    971 */
    972 bool GetBuildId(JS::BuildIdCharVector* aBuildID);
    973 
    974 }  // namespace mozilla
    975 
    976 #endif