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