xpcprivate.h (97713B)
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 /* 8 * XPConnect allows JS code to manipulate C++ object and C++ code to manipulate 9 * JS objects. JS manipulation of C++ objects tends to be significantly more 10 * complex. This comment explains how it is orchestrated by XPConnect. 11 * 12 * For each C++ object to be manipulated in JS, there is a corresponding JS 13 * object. This is called the "flattened JS object". By default, there is an 14 * additional C++ object involved of type XPCWrappedNative. The XPCWrappedNative 15 * holds pointers to the C++ object and the flat JS object. 16 * 17 * All XPCWrappedNative objects belong to an XPCWrappedNativeScope. These scopes 18 * are essentially in 1:1 correspondence with JS compartments. The 19 * XPCWrappedNativeScope has a pointer to the JS compartment. The global of a 20 * flattened JS object is one of the globals in this compartment (the exception 21 * to this rule is when a PreCreate hook asks for a different global; see 22 * nsIXPCScriptable below). 23 * 24 * Some C++ objects (notably DOM objects) have information associated with them 25 * that lists the interfaces implemented by these objects. A C++ object exposes 26 * this information by implementing nsIClassInfo. If a C++ object implements 27 * nsIClassInfo, then JS code can call its methods without needing to use 28 * QueryInterface first. Typically, all instances of a C++ class share the same 29 * nsIClassInfo instance. (That is, obj->QueryInterface(nsIClassInfo) returns 30 * the same result for every obj of a given class.) 31 * 32 * XPConnect tracks nsIClassInfo information in an XPCWrappedNativeProto object. 33 * A given XPCWrappedNativeScope will have one XPCWrappedNativeProto for each 34 * nsIClassInfo instance being used. The XPCWrappedNativeProto has an associated 35 * JS object, which is used as the prototype of all flattened JS objects created 36 * for C++ objects with the given nsIClassInfo. 37 * 38 * Each XPCWrappedNativeProto has a pointer to its XPCWrappedNativeScope. If an 39 * XPCWrappedNative wraps a C++ object with class info, then it points to its 40 * XPCWrappedNativeProto. Otherwise it points to its XPCWrappedNativeScope. (The 41 * pointers are smooshed together in a tagged union.) Either way it can reach 42 * its scope. 43 * 44 * An XPCWrappedNativeProto keeps track of the set of interfaces implemented by 45 * the C++ object in an XPCNativeSet. (The list of interfaces is obtained by 46 * calling a method on the nsIClassInfo.) An XPCNativeSet is a collection of 47 * XPCNativeInterfaces. Each interface stores the list of members, which can be 48 * methods, constants, getters, or setters. 49 * 50 * An XPCWrappedNative also points to an XPCNativeSet. Initially this starts out 51 * the same as the XPCWrappedNativeProto's set. If there is no proto, it starts 52 * out as a singleton set containing nsISupports. If JS code QI's new interfaces 53 * outside of the existing set, the set will grow. All QueryInterface results 54 * are cached in XPCWrappedNativeTearOff objects, which are linked off of the 55 * XPCWrappedNative. 56 * 57 * Besides having class info, a C++ object may be "scriptable" (i.e., implement 58 * nsIXPCScriptable). This allows it to implement a more DOM-like interface, 59 * besides just exposing XPCOM methods and constants. An nsIXPCScriptable 60 * instance has hooks that correspond to all the normal JSClass hooks. Each 61 * nsIXPCScriptable instance can have pointers from XPCWrappedNativeProto and 62 * XPCWrappedNative (since C++ objects can have scriptable info without having 63 * class info). 64 */ 65 66 /* All the XPConnect private declarations - only include locally. */ 67 68 #ifndef xpcprivate_h___ 69 #define xpcprivate_h___ 70 71 #include "mozilla/Assertions.h" 72 #include "mozilla/Attributes.h" 73 #include "mozilla/BasePrincipal.h" 74 #include "mozilla/CycleCollectedJSContext.h" 75 #include "mozilla/CycleCollectedJSRuntime.h" 76 #include "mozilla/DebugOnly.h" 77 #include "mozilla/DefineEnum.h" 78 #include "mozilla/HashFunctions.h" 79 #include "mozilla/LinkedList.h" 80 #include "mozilla/Maybe.h" 81 #include "mozilla/MemoryReporting.h" 82 #include "mozilla/PodOperations.h" 83 #include "mozilla/mozalloc.h" 84 #include "mozilla/Preferences.h" 85 #include "mozilla/TimeStamp.h" 86 #include "mozilla/UniquePtr.h" 87 #include "mozilla/Vector.h" 88 89 #include "mozilla/dom/ScriptSettings.h" 90 91 #include <math.h> 92 #include <stdint.h> 93 #include <stdlib.h> 94 #include <string.h> 95 96 #include "xpcpublic.h" 97 #include "js/HashTable.h" 98 #include "js/GCHashTable.h" 99 #include "js/Object.h" // JS::GetClass, JS::GetCompartment 100 #include "js/PropertyAndElement.h" // JS_DefineProperty 101 #include "js/TracingAPI.h" 102 #include "js/WeakMapPtr.h" 103 #include "nscore.h" 104 #include "nsXPCOM.h" 105 #include "nsCycleCollectionParticipant.h" 106 #include "nsDebug.h" 107 #include "nsISupports.h" 108 #include "nsIServiceManager.h" 109 #include "nsIClassInfoImpl.h" 110 #include "nsIComponentManager.h" 111 #include "nsIComponentRegistrar.h" 112 #include "nsISupportsPrimitives.h" 113 #include "nsISimpleEnumerator.h" 114 #include "nsIXPConnect.h" 115 #include "nsIXPCScriptable.h" 116 #include "nsIObserver.h" 117 #include "nsWeakReference.h" 118 #include "nsCOMPtr.h" 119 #include "nsXPTCUtils.h" 120 #include "xptinfo.h" 121 #include "XPCForwards.h" 122 #include "XPCLog.h" 123 #include "xpccomponents.h" 124 #include "prenv.h" 125 #include "prcvar.h" 126 #include "nsString.h" 127 #include "nsReadableUtils.h" 128 129 #include "MainThreadUtils.h" 130 131 #include "nsIConsoleService.h" 132 133 #include "nsVariant.h" 134 #include "nsCOMArray.h" 135 #include "nsTArray.h" 136 #include "nsBaseHashtable.h" 137 #include "nsHashKeys.h" 138 #include "nsWrapperCache.h" 139 #include "nsDeque.h" 140 141 #include "nsIScriptSecurityManager.h" 142 143 #include "nsIPrincipal.h" 144 #include "nsJSPrincipals.h" 145 #include "nsIScriptObjectPrincipal.h" 146 #include "xpcObjectHelper.h" 147 148 #include "SandboxPrivate.h" 149 #include "SystemGlobal.h" 150 151 #ifdef XP_WIN 152 // Nasty MS defines 153 # ifdef GetClassInfo 154 # undef GetClassInfo 155 # endif 156 # ifdef GetClassName 157 # undef GetClassName 158 # endif 159 #endif /* XP_WIN */ 160 161 namespace mozilla { 162 namespace dom { 163 class AutoEntryScript; 164 class Exception; 165 } // namespace dom 166 } // namespace mozilla 167 168 /***************************************************************************/ 169 // data declarations... 170 extern const char XPC_EXCEPTION_CONTRACTID[]; 171 extern const char XPC_CONSOLE_CONTRACTID[]; 172 extern const char XPC_SCRIPT_ERROR_CONTRACTID[]; 173 extern const char XPC_XPCONNECT_CONTRACTID[]; 174 175 /***************************************************************************/ 176 // Helper function. 177 178 namespace xpc { 179 180 inline bool IsWrappedNativeReflector(JSObject* obj) { 181 return JS::GetClass(obj)->isWrappedNative(); 182 } 183 184 } // namespace xpc 185 186 /*************************************************************************** 187 **************************************************************************** 188 * 189 * Core runtime and context classes... 190 * 191 **************************************************************************** 192 ***************************************************************************/ 193 194 // We have a general rule internally that getters that return addref'd interface 195 // pointer generally do so using an 'out' parm. When interface pointers are 196 // returned as function call result values they are not addref'd. Exceptions 197 // to this rule are noted explicitly. 198 199 class nsXPConnect final : public nsIXPConnect { 200 public: 201 // all the interface method declarations... 202 NS_DECL_ISUPPORTS 203 204 // non-interface implementation 205 public: 206 static XPCJSRuntime* GetRuntimeInstance(); 207 XPCJSContext* GetContext() { return mContext; } 208 209 static nsIScriptSecurityManager* SecurityManager() { 210 MOZ_ASSERT(NS_IsMainThread()); 211 MOZ_ASSERT(gScriptSecurityManager); 212 return gScriptSecurityManager; 213 } 214 215 static nsIPrincipal* SystemPrincipal() { 216 MOZ_ASSERT(NS_IsMainThread()); 217 MOZ_ASSERT(gSystemPrincipal); 218 return gSystemPrincipal; 219 } 220 221 // Called by module code in dll startup 222 static void InitStatics(); 223 // Called by module code on dll shutdown. 224 static void ReleaseXPConnectSingleton(); 225 226 static void InitJSContext(); 227 228 void RecordTraversal(void* p, nsISupports* s); 229 230 protected: 231 virtual ~nsXPConnect(); 232 233 nsXPConnect(); 234 235 private: 236 // Singleton instance 237 static nsXPConnect* gSelf; 238 static bool gOnceAliveNowDead; 239 240 XPCJSContext* mContext = nullptr; 241 XPCJSRuntime* mRuntime = nullptr; 242 243 friend class nsIXPConnect; 244 245 public: 246 static nsIScriptSecurityManager* gScriptSecurityManager; 247 static nsIPrincipal* gSystemPrincipal; 248 }; 249 250 /***************************************************************************/ 251 252 // In the current xpconnect system there can only be one XPCJSContext. 253 // So, xpconnect can only be used on one JSContext within the process. 254 255 class WatchdogManager; 256 257 // clang-format off 258 MOZ_DEFINE_ENUM(WatchdogTimestampCategory, ( 259 TimestampWatchdogWakeup, 260 TimestampWatchdogHibernateStart, 261 TimestampWatchdogHibernateStop, 262 TimestampContextStateChange 263 )); 264 // clang-format on 265 266 class AsyncFreeSnowWhite; 267 class XPCWrappedNativeScope; 268 269 using XPCWrappedNativeScopeList = mozilla::LinkedList<XPCWrappedNativeScope>; 270 271 class XPCJSContext final : public mozilla::CycleCollectedJSContext, 272 public mozilla::LinkedListElement<XPCJSContext> { 273 public: 274 static XPCJSContext* NewXPCJSContext(); 275 static XPCJSContext* Get(); 276 277 XPCJSRuntime* Runtime() const; 278 279 virtual mozilla::CycleCollectedJSRuntime* CreateRuntime( 280 JSContext* aCx) override; 281 282 XPCCallContext* GetCallContext() const { return mCallContext; } 283 XPCCallContext* SetCallContext(XPCCallContext* ccx) { 284 XPCCallContext* old = mCallContext; 285 mCallContext = ccx; 286 return old; 287 } 288 289 jsid GetResolveName() const { return mResolveName; } 290 jsid SetResolveName(jsid name) { 291 jsid old = mResolveName; 292 mResolveName = name; 293 return old; 294 } 295 296 XPCWrappedNative* GetResolvingWrapper() const { return mResolvingWrapper; } 297 XPCWrappedNative* SetResolvingWrapper(XPCWrappedNative* w) { 298 XPCWrappedNative* old = mResolvingWrapper; 299 mResolvingWrapper = w; 300 return old; 301 } 302 303 bool JSContextInitialized(JSContext* cx); 304 305 virtual void BeforeProcessTask(bool aMightBlock) override; 306 virtual void AfterProcessTask(uint32_t aNewRecursionDepth) override; 307 308 // Relay to the CCGCScheduler instead of queuing up an idle runnable 309 // (as is done for workers in CycleCollectedJSContext). 310 virtual void MaybePokeGC() override; 311 312 ~XPCJSContext(); 313 314 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); 315 316 bool IsSystemCaller() const override; 317 318 AutoMarkingPtr** GetAutoRootsAdr() { return &mAutoRoots; } 319 320 nsresult GetPendingResult() { return mPendingResult; } 321 void SetPendingResult(nsresult rv) { mPendingResult = rv; } 322 323 PRTime GetWatchdogTimestamp(WatchdogTimestampCategory aCategory); 324 325 static bool RecordScriptActivity(bool aActive); 326 327 bool SetHasScriptActivity(bool aActive) { 328 bool oldValue = mHasScriptActivity; 329 mHasScriptActivity = aActive; 330 return oldValue; 331 } 332 333 static bool InterruptCallback(JSContext* cx); 334 335 // Mapping of often used strings to jsid atoms that live 'forever'. 336 // 337 // To add a new string: add to this list and to XPCJSRuntime::mStrings 338 // at the top of XPCJSRuntime.cpp 339 enum { 340 IDX_CONSTRUCTOR = 0, 341 IDX_TO_STRING, 342 IDX_TO_SOURCE, 343 IDX_VALUE, 344 IDX_QUERY_INTERFACE, 345 IDX_COMPONENTS, 346 IDX_CC, 347 IDX_CI, 348 IDX_CR, 349 IDX_CU, 350 IDX_SERVICES, 351 IDX_WRAPPED_JSOBJECT, 352 IDX_PROTOTYPE, 353 IDX_EVAL, 354 IDX_CONTROLLERS, 355 IDX_CONTROLLERS_CLASS, 356 IDX_LENGTH, 357 IDX_NAME, 358 IDX_UNDEFINED, 359 IDX_EMPTYSTRING, 360 IDX_FILENAME, 361 IDX_LINENUMBER, 362 IDX_COLUMNNUMBER, 363 IDX_STACK, 364 IDX_MESSAGE, 365 IDX_CAUSE, 366 IDX_ERRORS, 367 IDX_LASTINDEX, 368 IDX_THEN, 369 IDX_ISINSTANCE, 370 IDX_INFINITY, 371 IDX_NAN, 372 IDX_CLASS_ID, 373 IDX_INTERFACE_ID, 374 IDX_INITIALIZER, 375 IDX_PRINT, 376 IDX_FETCH, 377 IDX_CRYPTO, 378 IDX_INDEXEDDB, 379 IDX_STRUCTUREDCLONE, 380 IDX_LOCKS, 381 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 382 IDX_SUPPRESSED, 383 IDX_ERROR, 384 #endif 385 IDX_TOTAL_COUNT // just a count of the above 386 }; 387 388 inline JS::HandleId GetStringID(unsigned index) const; 389 inline const char* GetStringName(unsigned index) const; 390 391 private: 392 XPCJSContext(); 393 394 MOZ_IS_CLASS_INIT 395 nsresult Initialize(); 396 397 XPCCallContext* mCallContext; 398 AutoMarkingPtr* mAutoRoots; 399 jsid mResolveName; 400 XPCWrappedNative* mResolvingWrapper; 401 WatchdogManager* mWatchdogManager; 402 403 // Number of XPCJSContexts currently alive. 404 static uint32_t sInstanceCount; 405 static mozilla::StaticAutoPtr<WatchdogManager> sWatchdogInstance; 406 static WatchdogManager* GetWatchdogManager(); 407 408 // If we spend too much time running JS code in an event handler, then we 409 // want to show the slow script UI. The timeout T is controlled by prefs. We 410 // invoke the interrupt callback once after T/2 seconds and set 411 // mSlowScriptSecondHalf to true. After another T/2 seconds, we invoke the 412 // interrupt callback again. Since mSlowScriptSecondHalf is now true, it 413 // shows the slow script UI. The reason we invoke the callback twice is to 414 // ensure that putting the computer to sleep while running a script doesn't 415 // cause the UI to be shown. If the laptop goes to sleep during one of the 416 // timeout periods, the script still has the other T/2 seconds to complete 417 // before the slow script UI is shown. 418 bool mSlowScriptSecondHalf; 419 420 // mSlowScriptCheckpoint is set to the time when: 421 // 1. We started processing the current event, or 422 // 2. mSlowScriptSecondHalf was set to true 423 // (whichever comes later). We use it to determine whether the interrupt 424 // callback needs to do anything. 425 mozilla::TimeStamp mSlowScriptCheckpoint; 426 // Accumulates total time we actually waited for telemetry 427 mozilla::TimeDuration mSlowScriptActualWait; 428 bool mTimeoutAccumulated; 429 bool mExecutedChromeScript; 430 431 bool mHasScriptActivity; 432 433 // mPendingResult is used to implement Components.returnCode. Only really 434 // meaningful while calling through XPCWrappedJS. 435 nsresult mPendingResult; 436 437 // These members must be accessed via WatchdogManager. 438 enum { CONTEXT_ACTIVE, CONTEXT_INACTIVE } mActive; 439 PRTime mLastStateChange; 440 441 friend class XPCJSRuntime; 442 friend class Watchdog; 443 friend class WatchdogManager; 444 friend class AutoLockWatchdog; 445 }; 446 447 class XPCJSRuntime final : public mozilla::CycleCollectedJSRuntime { 448 public: 449 static XPCJSRuntime* Get(); 450 451 void RemoveWrappedJS(nsXPCWrappedJS* wrapper); 452 void AssertInvalidWrappedJSNotInTable(nsXPCWrappedJS* wrapper) const; 453 454 JSObject2WrappedJSMap* GetMultiCompartmentWrappedJSMap() const { 455 return mWrappedJSMap.get(); 456 } 457 458 IID2NativeInterfaceMap* GetIID2NativeInterfaceMap() const { 459 return mIID2NativeInterfaceMap.get(); 460 } 461 462 ClassInfo2NativeSetMap* GetClassInfo2NativeSetMap() const { 463 return mClassInfo2NativeSetMap.get(); 464 } 465 466 NativeSetMap* GetNativeSetMap() const { return mNativeSetMap.get(); } 467 468 using WrappedNativeProtoVector = 469 mozilla::Vector<mozilla::UniquePtr<XPCWrappedNativeProto>, 0, 470 InfallibleAllocPolicy>; 471 WrappedNativeProtoVector& GetDyingWrappedNativeProtos() { 472 return mDyingWrappedNativeProtos; 473 } 474 475 XPCWrappedNativeScopeList& GetWrappedNativeScopes() { 476 return mWrappedNativeScopes; 477 } 478 479 bool InitializeStrings(JSContext* cx); 480 481 virtual bool DescribeCustomObjects(JSObject* aObject, const JSClass* aClasp, 482 char (&aName)[72]) const override; 483 virtual bool NoteCustomGCThingXPCOMChildren( 484 const JSClass* aClasp, JSObject* aObj, 485 nsCycleCollectionTraversalCallback& aCb) const override; 486 487 /** 488 * Infrastructure for classes that need to defer part of the finalization 489 * until after the GC has run, for example for objects that we don't want to 490 * destroy during the GC. 491 */ 492 493 public: 494 bool GetDoingFinalization() const { return mDoingFinalization; } 495 496 JS::HandleId GetStringID(unsigned index) const { 497 MOZ_ASSERT(index < XPCJSContext::IDX_TOTAL_COUNT, "index out of range"); 498 // fromMarkedLocation() is safe because the string is interned. 499 return JS::HandleId::fromMarkedLocation(&mStrIDs[index]); 500 } 501 const char* GetStringName(unsigned index) const { 502 MOZ_ASSERT(index < XPCJSContext::IDX_TOTAL_COUNT, "index out of range"); 503 return mStrings[index]; 504 } 505 506 virtual bool UsefulToMergeZones() const override; 507 void TraceAdditionalNativeBlackRoots(JSTracer* trc) override; 508 void TraceAdditionalNativeGrayRoots(JSTracer* aTracer) override; 509 void TraverseAdditionalNativeRoots( 510 nsCycleCollectionNoteRootCallback& cb) override; 511 void UnmarkSkippableJSHolders(); 512 void PrepareForForgetSkippable() override; 513 void BeginCycleCollectionCallback(mozilla::CCReason aReason) override; 514 void EndCycleCollectionCallback( 515 mozilla::CycleCollectorResults& aResults) override; 516 void DispatchDeferredDeletion(bool aContinuation, 517 bool aPurge = false) override; 518 519 void CustomGCCallback(JSGCStatus status) override; 520 void CustomOutOfMemoryCallback() override; 521 void OnLargeAllocationFailure(); 522 static void GCSliceCallback(JSContext* cx, JS::GCProgress progress, 523 const JS::GCDescription& desc); 524 static void DoCycleCollectionCallback(JSContext* cx); 525 static void FinalizeCallback(JS::GCContext* gcx, JSFinalizeStatus status, 526 void* data); 527 static void WeakPointerZonesCallback(JSTracer* trc, void* data); 528 static void WeakPointerCompartmentCallback(JSTracer* trc, 529 JS::Compartment* comp, void* data); 530 531 inline void AddSubjectToFinalizationWJS(nsXPCWrappedJS* wrappedJS); 532 533 void DebugDump(int16_t depth); 534 535 bool GCIsRunning() const { return mGCIsRunning; } 536 537 ~XPCJSRuntime(); 538 539 void AddGCCallback(xpcGCCallback cb); 540 void RemoveGCCallback(xpcGCCallback cb); 541 542 JSObject* GetUAWidgetScope(JSContext* cx, nsIPrincipal* principal); 543 544 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); 545 546 /** 547 * The unprivileged junk scope is an unprivileged sandbox global used for 548 * convenience by certain operations which need an unprivileged global but 549 * don't have one immediately handy. It should generally be avoided when 550 * possible. 551 * 552 * The scope is created lazily when it is needed, and held weakly so that it 553 * is destroyed when there are no longer any remaining external references to 554 * it. This means that under low memory conditions, when the scope does not 555 * already exist, we may not be able to create one. In these circumstances, 556 * the infallible version of this API will abort, and the fallible version 557 * will return null. Callers should therefore prefer the fallible version when 558 * on a codepath which can already return failure, but may use the infallible 559 * one otherwise. 560 */ 561 JSObject* UnprivilegedJunkScope(); 562 JSObject* UnprivilegedJunkScope(const mozilla::fallible_t&); 563 564 bool IsUnprivilegedJunkScope(JSObject*); 565 566 void DeleteSingletonScopes(); 567 568 private: 569 explicit XPCJSRuntime(JSContext* aCx); 570 571 MOZ_IS_CLASS_INIT 572 void Initialize(JSContext* cx); 573 void Shutdown(JSContext* cx) override; 574 575 static const char* const mStrings[XPCJSContext::IDX_TOTAL_COUNT]; 576 jsid mStrIDs[XPCJSContext::IDX_TOTAL_COUNT]; 577 578 struct Hasher { 579 using Key = RefPtr<mozilla::BasePrincipal>; 580 using Lookup = Key; 581 static uint32_t hash(const Lookup& l) { return l->GetOriginNoSuffixHash(); } 582 static bool match(const Key& k, const Lookup& l) { 583 return k->FastEquals(l); 584 } 585 }; 586 587 struct MapEntryGCPolicy { 588 static bool traceWeak(JSTracer* trc, 589 RefPtr<mozilla::BasePrincipal>* /* unused */, 590 JS::Heap<JSObject*>* value) { 591 return JS::GCPolicy<JS::Heap<JSObject*>>::traceWeak(trc, value); 592 } 593 }; 594 595 typedef JS::GCHashMap<RefPtr<mozilla::BasePrincipal>, JS::Heap<JSObject*>, 596 Hasher, js::SystemAllocPolicy, MapEntryGCPolicy> 597 Principal2JSObjectMap; 598 599 mozilla::UniquePtr<JSObject2WrappedJSMap> mWrappedJSMap; 600 mozilla::UniquePtr<IID2NativeInterfaceMap> mIID2NativeInterfaceMap; 601 mozilla::UniquePtr<ClassInfo2NativeSetMap> mClassInfo2NativeSetMap; 602 mozilla::UniquePtr<NativeSetMap> mNativeSetMap; 603 Principal2JSObjectMap mUAWidgetScopeMap; 604 XPCWrappedNativeScopeList mWrappedNativeScopes; 605 WrappedNativeProtoVector mDyingWrappedNativeProtos; 606 bool mGCIsRunning; 607 nsTArray<nsISupports*> mNativesToReleaseArray; 608 bool mDoingFinalization; 609 mozilla::LinkedList<nsXPCWrappedJS> mSubjectToFinalizationWJS; 610 nsTArray<xpcGCCallback> extraGCCallbacks; 611 JS::GCSliceCallback mPrevGCSliceCallback; 612 JS::DoCycleCollectionCallback mPrevDoCycleCollectionCallback; 613 mozilla::WeakPtr<SandboxPrivate> mUnprivilegedJunkScope; 614 RefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer; 615 616 friend class XPCJSContext; 617 friend class XPCIncrementalReleaseRunnable; 618 }; 619 620 inline JS::HandleId XPCJSContext::GetStringID(unsigned index) const { 621 return Runtime()->GetStringID(index); 622 } 623 624 inline const char* XPCJSContext::GetStringName(unsigned index) const { 625 return Runtime()->GetStringName(index); 626 } 627 628 /***************************************************************************/ 629 630 // No virtuals 631 // XPCCallContext is ALWAYS declared as a local variable in some function; 632 // i.e. instance lifetime is always controled by some C++ function returning. 633 // 634 // These things are created frequently in many places. We *intentionally* do 635 // not inialialize all members in order to save on construction overhead. 636 // Some constructor pass more valid params than others. We init what must be 637 // init'd and leave other members undefined. In debug builds the accessors 638 // use a CHECK_STATE macro to track whether or not the object is in a valid 639 // state to answer the question a caller might be asking. As long as this 640 // class is maintained correctly it can do its job without a bunch of added 641 // overhead from useless initializations and non-DEBUG error checking. 642 // 643 // Note that most accessors are inlined. 644 645 class MOZ_STACK_CLASS XPCCallContext final { 646 public: 647 enum : unsigned { NO_ARGS = (unsigned)-1 }; 648 649 explicit XPCCallContext(JSContext* cx, JS::HandleObject obj = nullptr, 650 JS::HandleObject funobj = nullptr, 651 JS::HandleId id = JS::VoidHandlePropertyKey, 652 unsigned argc = NO_ARGS, JS::Value* argv = nullptr, 653 JS::Value* rval = nullptr); 654 655 virtual ~XPCCallContext(); 656 657 inline bool IsValid() const; 658 659 inline XPCJSContext* GetContext() const; 660 inline JSContext* GetJSContext() const; 661 inline bool GetContextPopRequired() const; 662 inline XPCCallContext* GetPrevCallContext() const; 663 664 inline JSObject* GetFlattenedJSObject() const; 665 inline XPCWrappedNative* GetWrapper() const; 666 667 inline bool CanGetTearOff() const; 668 inline XPCWrappedNativeTearOff* GetTearOff() const; 669 670 inline nsIXPCScriptable* GetScriptable() const; 671 inline XPCNativeSet* GetSet() const; 672 inline bool CanGetInterface() const; 673 inline XPCNativeInterface* GetInterface() const; 674 inline XPCNativeMember* GetMember() const; 675 inline bool HasInterfaceAndMember() const; 676 inline bool GetStaticMemberIsLocal() const; 677 inline unsigned GetArgc() const; 678 inline JS::Value* GetArgv() const; 679 680 inline uint16_t GetMethodIndex() const; 681 682 inline jsid GetResolveName() const; 683 inline jsid SetResolveName(JS::HandleId name); 684 685 inline XPCWrappedNative* GetResolvingWrapper() const; 686 inline XPCWrappedNative* SetResolvingWrapper(XPCWrappedNative* w); 687 688 inline void SetRetVal(const JS::Value& val); 689 690 void SetName(jsid name); 691 void SetArgsAndResultPtr(unsigned argc, JS::Value* argv, JS::Value* rval); 692 void SetCallInfo(XPCNativeInterface* iface, XPCNativeMember* member, 693 bool isSetter); 694 695 nsresult CanCallNow(); 696 697 void SystemIsBeingShutDown(); 698 699 operator JSContext*() const { return GetJSContext(); } 700 701 private: 702 // no copy ctor or assignment allowed 703 XPCCallContext(const XPCCallContext& r) = delete; 704 XPCCallContext& operator=(const XPCCallContext& r) = delete; 705 706 private: 707 // posible values for mState 708 enum State { 709 INIT_FAILED, 710 SYSTEM_SHUTDOWN, 711 HAVE_CONTEXT, 712 HAVE_OBJECT, 713 HAVE_NAME, 714 HAVE_ARGS, 715 READY_TO_CALL, 716 CALL_DONE 717 }; 718 719 #ifdef DEBUG 720 inline void CHECK_STATE(int s) const { MOZ_ASSERT(mState >= s, "bad state"); } 721 #else 722 # define CHECK_STATE(s) ((void)0) 723 #endif 724 725 private: 726 State mState; 727 728 nsCOMPtr<nsIXPConnect> mXPC; 729 730 XPCJSContext* mXPCJSContext; 731 JSContext* mJSContext; 732 733 // ctor does not necessarily init the following. BEWARE! 734 735 XPCCallContext* mPrevCallContext; 736 737 XPCWrappedNative* mWrapper; 738 XPCWrappedNativeTearOff* mTearOff; 739 740 nsCOMPtr<nsIXPCScriptable> mScriptable; 741 742 RefPtr<XPCNativeSet> mSet; 743 RefPtr<XPCNativeInterface> mInterface; 744 XPCNativeMember* mMember; 745 746 JS::RootedId mName; 747 bool mStaticMemberIsLocal; 748 749 unsigned mArgc; 750 JS::Value* mArgv; 751 JS::Value* mRetVal; 752 753 uint16_t mMethodIndex; 754 }; 755 756 /*************************************************************************** 757 **************************************************************************** 758 * 759 * Core classes for wrapped native objects for use from JavaScript... 760 * 761 **************************************************************************** 762 ***************************************************************************/ 763 764 // These are the various JSClasses and callbacks whose use that required 765 // visibility from more than one .cpp file. 766 767 extern const JSClass XPC_WN_NoHelper_JSClass; 768 extern const JSClass XPC_WN_Proto_JSClass; 769 extern const JSClass XPC_WN_Tearoff_JSClass; 770 extern const JSClass XPC_WN_NoHelper_Proto_JSClass; 771 772 extern bool XPC_WN_CallMethod(JSContext* cx, unsigned argc, JS::Value* vp); 773 774 extern bool XPC_WN_GetterSetter(JSContext* cx, unsigned argc, JS::Value* vp); 775 776 /***************************************************************************/ 777 // XPCWrappedNativeScope is one-to-one with a JS compartment. 778 779 class XPCWrappedNativeScope final 780 : public mozilla::LinkedListElement<XPCWrappedNativeScope> { 781 public: 782 XPCJSRuntime* GetRuntime() const { return XPCJSRuntime::Get(); } 783 784 Native2WrappedNativeMap* GetWrappedNativeMap() const { 785 return mWrappedNativeMap.get(); 786 } 787 788 ClassInfo2WrappedNativeProtoMap* GetWrappedNativeProtoMap() const { 789 return mWrappedNativeProtoMap.get(); 790 } 791 792 nsXPCComponents* GetComponents() const { return mComponents; } 793 794 bool AttachComponentsObject(JSContext* aCx); 795 796 bool AttachJSServices(JSContext* aCx); 797 798 // Returns the JS object reflection of the Components object. 799 bool GetComponentsJSObject(JSContext* cx, JS::MutableHandleObject obj); 800 801 JSObject* GetExpandoChain(JS::HandleObject target); 802 803 JSObject* DetachExpandoChain(JS::HandleObject target); 804 805 bool SetExpandoChain(JSContext* cx, JS::HandleObject target, 806 JS::HandleObject chain); 807 808 static void SystemIsBeingShutDown(); 809 810 static void TraceWrappedNativesInAllScopes(XPCJSRuntime* xpcrt, 811 JSTracer* trc); 812 813 void TraceInside(JSTracer* trc) { 814 if (mXrayExpandos.initialized()) { 815 mXrayExpandos.trace(trc); 816 } 817 JS::TraceEdge(trc, &mIDProto, "XPCWrappedNativeScope::mIDProto"); 818 JS::TraceEdge(trc, &mIIDProto, "XPCWrappedNativeScope::mIIDProto"); 819 JS::TraceEdge(trc, &mCIDProto, "XPCWrappedNativeScope::mCIDProto"); 820 } 821 822 static void SuspectAllWrappers(nsCycleCollectionNoteRootCallback& cb); 823 824 static void SweepAllWrappedNativeTearOffs(); 825 826 void UpdateWeakPointersAfterGC(JSTracer* trc); 827 828 static void DebugDumpAllScopes(int16_t depth); 829 830 void DebugDump(int16_t depth); 831 832 struct ScopeSizeInfo { 833 explicit ScopeSizeInfo(mozilla::MallocSizeOf mallocSizeOf) 834 : mMallocSizeOf(mallocSizeOf), 835 mScopeAndMapSize(0), 836 mProtoAndIfaceCacheSize(0) {} 837 838 mozilla::MallocSizeOf mMallocSizeOf; 839 size_t mScopeAndMapSize; 840 size_t mProtoAndIfaceCacheSize; 841 }; 842 843 static void AddSizeOfAllScopesIncludingThis(JSContext* cx, 844 ScopeSizeInfo* scopeSizeInfo); 845 846 void AddSizeOfIncludingThis(JSContext* cx, ScopeSizeInfo* scopeSizeInfo); 847 848 // Check whether our mAllowContentXBLScope state matches the given 849 // principal. This is used to avoid sharing compartments on 850 // mismatch. 851 bool XBLScopeStateMatches(nsIPrincipal* aPrincipal); 852 853 XPCWrappedNativeScope(JS::Compartment* aCompartment, 854 JS::HandleObject aFirstGlobal); 855 virtual ~XPCWrappedNativeScope(); 856 857 mozilla::UniquePtr<JSObject2JSObjectMap> mWaiverWrapperMap; 858 859 JS::Compartment* Compartment() const { return mCompartment; } 860 861 // Returns the global to use for new WrappedNative objects allocated in this 862 // compartment. This is better than using arbitrary globals we happen to be in 863 // because it prevents leaks (objects keep their globals alive). 864 JSObject* GetGlobalForWrappedNatives() { 865 return js::GetFirstGlobalInCompartment(Compartment()); 866 } 867 868 bool AllowContentXBLScope(JS::Realm* aRealm); 869 870 // ID Object prototype caches. 871 JS::Heap<JSObject*> mIDProto; 872 JS::Heap<JSObject*> mIIDProto; 873 JS::Heap<JSObject*> mCIDProto; 874 875 protected: 876 XPCWrappedNativeScope() = delete; 877 878 private: 879 mozilla::UniquePtr<Native2WrappedNativeMap> mWrappedNativeMap; 880 mozilla::UniquePtr<ClassInfo2WrappedNativeProtoMap> mWrappedNativeProtoMap; 881 RefPtr<nsXPCComponents> mComponents; 882 JS::Compartment* mCompartment; 883 884 JS::WeakMapPtr<JSObject*, JSObject*> mXrayExpandos; 885 886 // For remote XUL domains, we run all XBL in the content scope for compat 887 // reasons (though we sometimes pref this off for automation). We 888 // track the result of this decision (mAllowContentXBLScope) for now. 889 bool mAllowContentXBLScope; 890 }; 891 892 /***************************************************************************/ 893 // Slots we use for our functions 894 #define XPC_FUNCTION_NATIVE_MEMBER_SLOT 0 895 #define XPC_FUNCTION_PARENT_OBJECT_SLOT 1 896 897 /***************************************************************************/ 898 // XPCNativeMember represents a single idl declared method, attribute or 899 // constant. 900 901 // Tight. No virtual methods. Can be bitwise copied (until any resolution done). 902 903 class XPCNativeMember final { 904 public: 905 static bool GetCallInfo(JSObject* funobj, 906 RefPtr<XPCNativeInterface>* pInterface, 907 XPCNativeMember** pMember); 908 909 jsid GetName() const { return mName; } 910 911 uint16_t GetIndex() const { return mIndex; } 912 913 bool GetConstantValue(XPCCallContext& ccx, XPCNativeInterface* iface, 914 JS::Value* pval) { 915 MOZ_ASSERT(IsConstant(), 916 "Only call this if you're sure this is a constant!"); 917 return Resolve(ccx, iface, nullptr, pval); 918 } 919 920 bool NewFunctionObject(XPCCallContext& ccx, XPCNativeInterface* iface, 921 JS::HandleObject parent, JS::Value* pval); 922 923 bool IsMethod() const { return 0 != (mFlags & METHOD); } 924 925 bool IsConstant() const { return 0 != (mFlags & CONSTANT); } 926 927 bool IsAttribute() const { return 0 != (mFlags & GETTER); } 928 929 bool IsWritableAttribute() const { return 0 != (mFlags & SETTER_TOO); } 930 931 bool IsReadOnlyAttribute() const { 932 return IsAttribute() && !IsWritableAttribute(); 933 } 934 935 void SetName(jsid a) { mName = a; } 936 937 void SetMethod(uint16_t index) { 938 mFlags = METHOD; 939 mIndex = index; 940 } 941 942 void SetConstant(uint16_t index) { 943 mFlags = CONSTANT; 944 mIndex = index; 945 } 946 947 void SetReadOnlyAttribute(uint16_t index) { 948 mFlags = GETTER; 949 mIndex = index; 950 } 951 952 void SetWritableAttribute() { 953 MOZ_ASSERT(mFlags == GETTER, "bad"); 954 mFlags = GETTER | SETTER_TOO; 955 } 956 957 static uint16_t GetMaxIndexInInterface() { return (1 << 12) - 1; } 958 959 inline XPCNativeInterface* GetInterface() const; 960 961 void SetIndexInInterface(uint16_t index) { mIndexInInterface = index; } 962 963 /* default ctor - leave random contents */ 964 MOZ_COUNTED_DEFAULT_CTOR(XPCNativeMember) 965 MOZ_COUNTED_DTOR(XPCNativeMember) 966 967 XPCNativeMember(const XPCNativeMember& other) 968 : mName(other.mName), 969 mIndex(other.mIndex), 970 mFlags(other.mFlags), 971 mIndexInInterface(other.mIndexInInterface) { 972 MOZ_COUNT_CTOR(XPCNativeMember); 973 } 974 975 private: 976 bool Resolve(XPCCallContext& ccx, XPCNativeInterface* iface, 977 JS::HandleObject parent, JS::Value* vp); 978 979 enum { 980 METHOD = 0x01, 981 CONSTANT = 0x02, 982 GETTER = 0x04, 983 SETTER_TOO = 0x08 984 // If you add a flag here, you may need to make mFlags wider and either 985 // make mIndexInInterface narrower (and adjust 986 // XPCNativeInterface::NewInstance accordingly) or make this object 987 // bigger. 988 }; 989 990 private: 991 // our only data... 992 jsid mName; 993 uint16_t mIndex; 994 // mFlags needs to be wide enough to hold the flags in the above enum. 995 uint16_t mFlags : 4; 996 // mIndexInInterface is the index of this in our XPCNativeInterface's 997 // mMembers. In theory our XPCNativeInterface could have as many as 2^15-1 998 // members (since mMemberCount is 15-bit) but in practice we prevent 999 // creation of XPCNativeInterfaces which have more than 2^12 members. 1000 // If the width of this field changes, update GetMaxIndexInInterface. 1001 uint16_t mIndexInInterface : 12; 1002 }; 1003 1004 /***************************************************************************/ 1005 // XPCNativeInterface represents a single idl declared interface. This is 1006 // primarily the set of XPCNativeMembers. 1007 1008 // Tight. No virtual methods. 1009 1010 class XPCNativeInterface final { 1011 public: 1012 NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(XPCNativeInterface, 1013 DestroyInstance(this)) 1014 1015 static already_AddRefed<XPCNativeInterface> GetNewOrUsed(JSContext* cx, 1016 const nsIID* iid); 1017 static already_AddRefed<XPCNativeInterface> GetNewOrUsed( 1018 JSContext* cx, const nsXPTInterfaceInfo* info); 1019 static already_AddRefed<XPCNativeInterface> GetNewOrUsed(JSContext* cx, 1020 const char* name); 1021 static already_AddRefed<XPCNativeInterface> GetISupports(JSContext* cx); 1022 1023 inline const nsXPTInterfaceInfo* GetInterfaceInfo() const { return mInfo; } 1024 inline jsid GetName() const { return mName; } 1025 1026 inline const nsIID* GetIID() const; 1027 inline const char* GetNameString() const; 1028 inline XPCNativeMember* FindMember(jsid name) const; 1029 1030 static inline size_t OffsetOfMembers(); 1031 1032 uint16_t GetMemberCount() const { return mMemberCount; } 1033 XPCNativeMember* GetMemberAt(uint16_t i) { 1034 MOZ_ASSERT(i < mMemberCount, "bad index"); 1035 return &mMembers[i]; 1036 } 1037 1038 void DebugDump(int16_t depth); 1039 1040 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); 1041 1042 void Trace(JSTracer* trc); 1043 1044 protected: 1045 static already_AddRefed<XPCNativeInterface> NewInstance( 1046 JSContext* cx, IID2NativeInterfaceMap* aMap, 1047 const nsXPTInterfaceInfo* aInfo); 1048 1049 XPCNativeInterface() = delete; 1050 XPCNativeInterface(const nsXPTInterfaceInfo* aInfo, jsid aName) 1051 : mInfo(aInfo), mName(aName), mMemberCount(0) {} 1052 ~XPCNativeInterface(); 1053 1054 void* operator new(size_t, void* p) noexcept(true) { return p; } 1055 1056 XPCNativeInterface(const XPCNativeInterface& r) = delete; 1057 XPCNativeInterface& operator=(const XPCNativeInterface& r) = delete; 1058 1059 static void DestroyInstance(XPCNativeInterface* inst); 1060 1061 private: 1062 const nsXPTInterfaceInfo* mInfo; 1063 jsid mName; 1064 uint16_t mMemberCount; 1065 XPCNativeMember mMembers[1]; // always last - object sized for array 1066 }; 1067 1068 /***************************************************************************/ 1069 // XPCNativeSetKey is used to key a XPCNativeSet in a NativeSetMap. 1070 // It represents a new XPCNativeSet we are considering constructing, without 1071 // requiring that the set actually be built. 1072 1073 class MOZ_STACK_CLASS XPCNativeSetKey final { 1074 public: 1075 // This represents an existing set |baseSet|. 1076 explicit XPCNativeSetKey(XPCNativeSet* baseSet) 1077 : mCx(nullptr), mBaseSet(baseSet), mAddition(nullptr) { 1078 MOZ_ASSERT(baseSet); 1079 } 1080 1081 // This represents a new set containing only nsISupports and 1082 // |addition|. This needs a JSContext because it may need to 1083 // construct some data structures that need one to construct them. 1084 explicit XPCNativeSetKey(JSContext* cx, XPCNativeInterface* addition) 1085 : mCx(cx), mBaseSet(nullptr), mAddition(addition) { 1086 MOZ_ASSERT(cx); 1087 MOZ_ASSERT(addition); 1088 } 1089 1090 // This represents the existing set |baseSet| with the interface 1091 // |addition| inserted after existing interfaces. |addition| must 1092 // not already be present in |baseSet|. 1093 explicit XPCNativeSetKey(XPCNativeSet* baseSet, XPCNativeInterface* addition); 1094 ~XPCNativeSetKey() = default; 1095 1096 XPCNativeSet* GetBaseSet() const { return mBaseSet; } 1097 XPCNativeInterface* GetAddition() const { return mAddition; } 1098 1099 mozilla::HashNumber Hash() const; 1100 1101 // Allow shallow copy 1102 1103 private: 1104 JSContext* mCx; 1105 RefPtr<XPCNativeSet> mBaseSet; 1106 RefPtr<XPCNativeInterface> mAddition; 1107 }; 1108 1109 /***************************************************************************/ 1110 // XPCNativeSet represents an ordered collection of XPCNativeInterface pointers. 1111 1112 class XPCNativeSet final { 1113 public: 1114 NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(XPCNativeSet, DestroyInstance(this)) 1115 1116 static already_AddRefed<XPCNativeSet> GetNewOrUsed(JSContext* cx, 1117 const nsIID* iid); 1118 static already_AddRefed<XPCNativeSet> GetNewOrUsed(JSContext* cx, 1119 nsIClassInfo* classInfo); 1120 static already_AddRefed<XPCNativeSet> GetNewOrUsed(JSContext* cx, 1121 XPCNativeSetKey* key); 1122 1123 // This generates a union set. 1124 // 1125 // If preserveFirstSetOrder is true, the elements from |firstSet| come first, 1126 // followed by any non-duplicate items from |secondSet|. If false, the same 1127 // algorithm is applied; but if we detect that |secondSet| is a superset of 1128 // |firstSet|, we return |secondSet| without worrying about whether the 1129 // ordering might differ from |firstSet|. 1130 static already_AddRefed<XPCNativeSet> GetNewOrUsed( 1131 JSContext* cx, XPCNativeSet* firstSet, XPCNativeSet* secondSet, 1132 bool preserveFirstSetOrder); 1133 1134 static void ClearCacheEntryForClassInfo(nsIClassInfo* classInfo); 1135 1136 inline bool FindMember(jsid name, XPCNativeMember** pMember, 1137 uint16_t* pInterfaceIndex) const; 1138 1139 inline bool FindMember(jsid name, XPCNativeMember** pMember, 1140 RefPtr<XPCNativeInterface>* pInterface) const; 1141 1142 inline bool FindMember(JS::HandleId name, XPCNativeMember** pMember, 1143 RefPtr<XPCNativeInterface>* pInterface, 1144 XPCNativeSet* protoSet, bool* pIsLocal) const; 1145 1146 inline bool HasInterface(XPCNativeInterface* aInterface) const; 1147 1148 uint16_t GetInterfaceCount() const { return mInterfaceCount; } 1149 XPCNativeInterface** GetInterfaceArray() { return mInterfaces; } 1150 1151 XPCNativeInterface* GetInterfaceAt(uint16_t i) { 1152 MOZ_ASSERT(i < mInterfaceCount, "bad index"); 1153 return mInterfaces[i]; 1154 } 1155 1156 inline bool MatchesSetUpToInterface(const XPCNativeSet* other, 1157 XPCNativeInterface* iface) const; 1158 1159 void DebugDump(int16_t depth); 1160 1161 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); 1162 1163 protected: 1164 static already_AddRefed<XPCNativeSet> NewInstance( 1165 JSContext* cx, nsTArray<RefPtr<XPCNativeInterface>>&& array); 1166 static already_AddRefed<XPCNativeSet> NewInstanceMutate(XPCNativeSetKey* key); 1167 1168 XPCNativeSet() : mInterfaceCount(0) {} 1169 ~XPCNativeSet(); 1170 void* operator new(size_t, void* p) noexcept(true) { return p; } 1171 1172 static void DestroyInstance(XPCNativeSet* inst); 1173 1174 private: 1175 uint16_t mInterfaceCount; 1176 // Always last - object sized for array. 1177 // These are strong references. 1178 XPCNativeInterface* mInterfaces[1]; 1179 }; 1180 1181 /***********************************************/ 1182 // XPCWrappedNativeProtos hold the additional shared wrapper data for 1183 // XPCWrappedNative whose native objects expose nsIClassInfo. 1184 // 1185 // The XPCWrappedNativeProto is owned by its mJSProtoObject, until that object 1186 // is finalized. After that, it is owned by XPCJSRuntime's 1187 // mDyingWrappedNativeProtos. See XPCWrappedNativeProto::JSProtoObjectFinalized 1188 // and XPCJSRuntime::FinalizeCallback. 1189 1190 class XPCWrappedNativeProto final { 1191 public: 1192 enum Slots { ProtoSlot, SlotCount }; 1193 1194 static XPCWrappedNativeProto* GetNewOrUsed(JSContext* cx, 1195 XPCWrappedNativeScope* scope, 1196 nsIClassInfo* classInfo, 1197 nsIXPCScriptable* scriptable); 1198 1199 XPCWrappedNativeScope* GetScope() const { return mScope; } 1200 1201 XPCJSRuntime* GetRuntime() const { return mScope->GetRuntime(); } 1202 1203 JSObject* GetJSProtoObject() const { return mJSProtoObject; } 1204 1205 JSObject* GetJSProtoObjectPreserveColor() const { 1206 return mJSProtoObject.unbarrieredGet(); 1207 } 1208 1209 nsIClassInfo* GetClassInfo() const { return mClassInfo; } 1210 1211 XPCNativeSet* GetSet() const { return mSet; } 1212 1213 nsIXPCScriptable* GetScriptable() const { return mScriptable; } 1214 1215 void JSProtoObjectFinalized(JS::GCContext* gcx, JSObject* obj); 1216 void JSProtoObjectMoved(JSObject* obj, const JSObject* old); 1217 1218 static XPCWrappedNativeProto* Get(JSObject* obj); 1219 1220 void SystemIsBeingShutDown(); 1221 1222 void DebugDump(int16_t depth); 1223 1224 void TraceSelf(JSTracer* trc) { 1225 if (mJSProtoObject) { 1226 TraceEdge(trc, &mJSProtoObject, "XPCWrappedNativeProto::mJSProtoObject"); 1227 } 1228 } 1229 1230 void TraceJS(JSTracer* trc) { TraceSelf(trc); } 1231 1232 // NOP. This is just here to make the AutoMarkingPtr code compile. 1233 void Mark() const {} 1234 inline void AutoTrace(JSTracer* trc) {} 1235 1236 ~XPCWrappedNativeProto(); 1237 1238 protected: 1239 // disable copy ctor and assignment 1240 XPCWrappedNativeProto(const XPCWrappedNativeProto& r) = delete; 1241 XPCWrappedNativeProto& operator=(const XPCWrappedNativeProto& r) = delete; 1242 1243 // hide ctor 1244 XPCWrappedNativeProto(XPCWrappedNativeScope* Scope, nsIClassInfo* ClassInfo, 1245 RefPtr<XPCNativeSet>&& Set); 1246 1247 bool Init(JSContext* cx, nsIXPCScriptable* scriptable); 1248 1249 private: 1250 #ifdef DEBUG 1251 static int32_t gDEBUG_LiveProtoCount; 1252 #endif 1253 1254 private: 1255 XPCWrappedNativeScope* mScope; 1256 JS::Heap<JSObject*> mJSProtoObject; 1257 nsCOMPtr<nsIClassInfo> mClassInfo; 1258 RefPtr<XPCNativeSet> mSet; 1259 nsCOMPtr<nsIXPCScriptable> mScriptable; 1260 }; 1261 1262 /***********************************************/ 1263 // XPCWrappedNativeTearOff represents the info needed to make calls to one 1264 // interface on the underlying native object of a XPCWrappedNative. 1265 1266 class XPCWrappedNativeTearOff final { 1267 public: 1268 enum Slots { FlatObjectSlot, TearOffSlot, SlotCount }; 1269 1270 bool IsAvailable() const { return mInterface == nullptr; } 1271 bool IsReserved() const { return mInterface == (XPCNativeInterface*)1; } 1272 bool IsValid() const { return !IsAvailable() && !IsReserved(); } 1273 void SetReserved() { mInterface = (XPCNativeInterface*)1; } 1274 1275 XPCNativeInterface* GetInterface() const { return mInterface; } 1276 nsISupports* GetNative() const { return mNative; } 1277 JSObject* GetJSObject(); 1278 JSObject* GetJSObjectPreserveColor() const; 1279 void SetInterface(XPCNativeInterface* Interface) { mInterface = Interface; } 1280 void SetNative(nsISupports* Native) { mNative = Native; } 1281 already_AddRefed<nsISupports> TakeNative() { return mNative.forget(); } 1282 void SetJSObject(JSObject* JSObj); 1283 1284 void JSObjectFinalized() { SetJSObject(nullptr); } 1285 void JSObjectMoved(JSObject* obj, const JSObject* old); 1286 1287 static XPCWrappedNativeTearOff* Get(JSObject* obj); 1288 1289 XPCWrappedNativeTearOff() : mInterface(nullptr), mJSObject(nullptr) { 1290 MOZ_COUNT_CTOR(XPCWrappedNativeTearOff); 1291 } 1292 ~XPCWrappedNativeTearOff(); 1293 1294 // NOP. This is just here to make the AutoMarkingPtr code compile. 1295 inline void TraceJS(JSTracer* trc) {} 1296 inline void AutoTrace(JSTracer* trc) {} 1297 1298 void Mark() { mJSObject.setFlags(1); } 1299 void Unmark() { mJSObject.unsetFlags(1); } 1300 bool IsMarked() const { return mJSObject.hasFlag(1); } 1301 1302 XPCWrappedNativeTearOff* AddTearOff() { 1303 MOZ_ASSERT(!mNextTearOff); 1304 mNextTearOff = mozilla::MakeUnique<XPCWrappedNativeTearOff>(); 1305 return mNextTearOff.get(); 1306 } 1307 1308 XPCWrappedNativeTearOff* GetNextTearOff() { return mNextTearOff.get(); } 1309 1310 private: 1311 XPCWrappedNativeTearOff(const XPCWrappedNativeTearOff& r) = delete; 1312 XPCWrappedNativeTearOff& operator=(const XPCWrappedNativeTearOff& r) = delete; 1313 1314 private: 1315 XPCNativeInterface* mInterface; 1316 // mNative is an nsRefPtr not an nsCOMPtr because it may not be the canonical 1317 // nsISupports pointer. 1318 RefPtr<nsISupports> mNative; 1319 JS::TenuredHeap<JSObject*> mJSObject; 1320 mozilla::UniquePtr<XPCWrappedNativeTearOff> mNextTearOff; 1321 }; 1322 1323 /***************************************************************************/ 1324 // XPCWrappedNative the wrapper around one instance of a native xpcom object 1325 // to be used from JavaScript. 1326 1327 class XPCWrappedNative final : public nsIXPConnectWrappedNative { 1328 public: 1329 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1330 1331 NS_DECL_CYCLE_COLLECTION_CLASS(XPCWrappedNative) 1332 1333 JSObject* GetJSObject() override; 1334 1335 bool IsValid() const { return mFlatJSObject.hasFlag(FLAT_JS_OBJECT_VALID); } 1336 1337 nsresult DebugDump(int16_t depth); 1338 1339 #define XPC_SCOPE_WORD(s) (intptr_t(s)) 1340 #define XPC_SCOPE_MASK (intptr_t(0x3)) 1341 #define XPC_SCOPE_TAG (intptr_t(0x1)) 1342 #define XPC_WRAPPER_EXPIRED (intptr_t(0x2)) 1343 1344 static inline bool IsTaggedScope(XPCWrappedNativeScope* s) { 1345 return XPC_SCOPE_WORD(s) & XPC_SCOPE_TAG; 1346 } 1347 1348 static inline XPCWrappedNativeScope* TagScope(XPCWrappedNativeScope* s) { 1349 MOZ_ASSERT(!IsTaggedScope(s), "bad pointer!"); 1350 return (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(s) | XPC_SCOPE_TAG); 1351 } 1352 1353 static inline XPCWrappedNativeScope* UnTagScope(XPCWrappedNativeScope* s) { 1354 return (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(s) & ~XPC_SCOPE_TAG); 1355 } 1356 1357 inline bool IsWrapperExpired() const { 1358 return XPC_SCOPE_WORD(mMaybeScope) & XPC_WRAPPER_EXPIRED; 1359 } 1360 1361 bool HasProto() const { return !IsTaggedScope(mMaybeScope); } 1362 1363 XPCWrappedNativeProto* GetProto() const { 1364 return HasProto() ? (XPCWrappedNativeProto*)(XPC_SCOPE_WORD(mMaybeProto) & 1365 ~XPC_SCOPE_MASK) 1366 : nullptr; 1367 } 1368 1369 XPCWrappedNativeScope* GetScope() const { 1370 return GetProto() ? GetProto()->GetScope() 1371 : (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(mMaybeScope) & 1372 ~XPC_SCOPE_MASK); 1373 } 1374 1375 nsISupports* GetIdentityObject() const { return mIdentity; } 1376 1377 /** 1378 * This getter clears the gray bit before handing out the JSObject which 1379 * means that the object is guaranteed to be kept alive past the next CC. 1380 */ 1381 JSObject* GetFlatJSObject() const { return mFlatJSObject; } 1382 1383 /** 1384 * This getter does not change the color of the JSObject meaning that the 1385 * object returned is not guaranteed to be kept alive past the next CC. 1386 * 1387 * This should only be called if you are certain that the return value won't 1388 * be passed into a JS API function and that it won't be stored without 1389 * being rooted (or otherwise signaling the stored value to the CC). 1390 */ 1391 JSObject* GetFlatJSObjectPreserveColor() const { 1392 return mFlatJSObject.unbarrieredGetPtr(); 1393 } 1394 1395 XPCNativeSet* GetSet() const { return mSet; } 1396 1397 void SetSet(already_AddRefed<XPCNativeSet> set) { mSet = set; } 1398 1399 static XPCWrappedNative* Get(JSObject* obj) { 1400 MOZ_ASSERT(xpc::IsWrappedNativeReflector(obj)); 1401 return JS::GetObjectISupports<XPCWrappedNative>(obj); 1402 } 1403 1404 private: 1405 void SetFlatJSObject(JSObject* object); 1406 void UnsetFlatJSObject(); 1407 1408 inline void ExpireWrapper() { 1409 mMaybeScope = (XPCWrappedNativeScope*)(XPC_SCOPE_WORD(mMaybeScope) | 1410 XPC_WRAPPER_EXPIRED); 1411 } 1412 1413 public: 1414 nsIXPCScriptable* GetScriptable() const { return mScriptable; } 1415 1416 nsIClassInfo* GetClassInfo() const { 1417 return IsValid() && HasProto() ? GetProto()->GetClassInfo() : nullptr; 1418 } 1419 1420 bool HasMutatedSet() const { 1421 return IsValid() && (!HasProto() || GetSet() != GetProto()->GetSet()); 1422 } 1423 1424 XPCJSRuntime* GetRuntime() const { 1425 XPCWrappedNativeScope* scope = GetScope(); 1426 return scope ? scope->GetRuntime() : nullptr; 1427 } 1428 1429 static nsresult WrapNewGlobal(JSContext* cx, xpcObjectHelper& nativeHelper, 1430 nsIPrincipal* principal, 1431 JS::RealmOptions& aOptions, 1432 XPCWrappedNative** wrappedGlobal); 1433 1434 static nsresult GetNewOrUsed(JSContext* cx, xpcObjectHelper& helper, 1435 XPCWrappedNativeScope* Scope, 1436 XPCNativeInterface* Interface, 1437 XPCWrappedNative** wrapper); 1438 1439 void FlatJSObjectFinalized(); 1440 void FlatJSObjectMoved(JSObject* obj, const JSObject* old); 1441 1442 void SystemIsBeingShutDown(); 1443 1444 enum CallMode { CALL_METHOD, CALL_GETTER, CALL_SETTER }; 1445 1446 static bool CallMethod(XPCCallContext& ccx, CallMode mode = CALL_METHOD); 1447 1448 static bool GetAttribute(XPCCallContext& ccx) { 1449 return CallMethod(ccx, CALL_GETTER); 1450 } 1451 1452 static bool SetAttribute(XPCCallContext& ccx) { 1453 return CallMethod(ccx, CALL_SETTER); 1454 } 1455 1456 XPCWrappedNativeTearOff* FindTearOff(JSContext* cx, 1457 XPCNativeInterface* aInterface, 1458 bool needJSObject = false, 1459 nsresult* pError = nullptr); 1460 XPCWrappedNativeTearOff* FindTearOff(JSContext* cx, const nsIID& iid); 1461 1462 void Mark() const {} 1463 1464 inline void TraceInside(JSTracer* trc) { 1465 if (HasProto()) { 1466 GetProto()->TraceSelf(trc); 1467 } 1468 1469 JSObject* obj = mFlatJSObject.unbarrieredGetPtr(); 1470 if (obj && JS_IsGlobalObject(obj)) { 1471 xpc::TraceXPCGlobal(trc, obj); 1472 } 1473 } 1474 1475 void TraceJS(JSTracer* trc) { TraceInside(trc); } 1476 1477 void TraceSelf(JSTracer* trc) { 1478 // If this got called, we're being kept alive by someone who really 1479 // needs us alive and whole. Do not let our mFlatJSObject go away. 1480 // This is the only time we should be tracing our mFlatJSObject, 1481 // normally somebody else is doing that. 1482 JS::TraceEdge(trc, &mFlatJSObject, "XPCWrappedNative::mFlatJSObject"); 1483 } 1484 1485 static void Trace(JSTracer* trc, JSObject* obj); 1486 1487 void AutoTrace(JSTracer* trc) { TraceSelf(trc); } 1488 1489 inline void SweepTearOffs(); 1490 1491 // Returns a string that should be freed with js_free, or nullptr on 1492 // failure. 1493 char* ToString(XPCWrappedNativeTearOff* to = nullptr) const; 1494 1495 static nsIXPCScriptable* GatherProtoScriptable(nsIClassInfo* classInfo); 1496 1497 bool HasExternalReference() const { return mRefCnt > 1; } 1498 1499 void Suspect(nsCycleCollectionNoteRootCallback& cb); 1500 void NoteTearoffs(nsCycleCollectionTraversalCallback& cb); 1501 1502 // Make ctor and dtor protected (rather than private) to placate nsCOMPtr. 1503 protected: 1504 XPCWrappedNative() = delete; 1505 1506 // This ctor is used if this object will have a proto. 1507 XPCWrappedNative(nsCOMPtr<nsISupports>&& aIdentity, 1508 XPCWrappedNativeProto* aProto); 1509 1510 // This ctor is used if this object will NOT have a proto. 1511 XPCWrappedNative(nsCOMPtr<nsISupports>&& aIdentity, 1512 XPCWrappedNativeScope* aScope, RefPtr<XPCNativeSet>&& aSet); 1513 1514 virtual ~XPCWrappedNative(); 1515 void Destroy(); 1516 1517 private: 1518 enum { 1519 // Flags bits for mFlatJSObject: 1520 FLAT_JS_OBJECT_VALID = js::Bit(0) 1521 }; 1522 1523 bool Init(JSContext* cx, nsIXPCScriptable* scriptable); 1524 bool FinishInit(JSContext* cx); 1525 1526 bool ExtendSet(JSContext* aCx, XPCNativeInterface* aInterface); 1527 1528 nsresult InitTearOff(JSContext* cx, XPCWrappedNativeTearOff* aTearOff, 1529 XPCNativeInterface* aInterface, bool needJSObject); 1530 1531 bool InitTearOffJSObject(JSContext* cx, XPCWrappedNativeTearOff* to); 1532 1533 public: 1534 static void GatherScriptable(nsISupports* obj, nsIClassInfo* classInfo, 1535 nsIXPCScriptable** scrProto, 1536 nsIXPCScriptable** scrWrapper); 1537 1538 private: 1539 union { 1540 XPCWrappedNativeScope* mMaybeScope; 1541 XPCWrappedNativeProto* mMaybeProto; 1542 }; 1543 RefPtr<XPCNativeSet> mSet; 1544 JS::TenuredHeap<JSObject*> mFlatJSObject; 1545 nsCOMPtr<nsIXPCScriptable> mScriptable; 1546 XPCWrappedNativeTearOff mFirstTearOff; 1547 }; 1548 1549 /*************************************************************************** 1550 **************************************************************************** 1551 * 1552 * Core classes for wrapped JSObject for use from native code... 1553 * 1554 **************************************************************************** 1555 ***************************************************************************/ 1556 1557 /*************************/ 1558 // nsXPCWrappedJS is a wrapper for a single JSObject for use from native code. 1559 // nsXPCWrappedJS objects are chained together to represent the various 1560 // interface on the single underlying (possibly aggregate) JSObject. 1561 1562 class nsXPCWrappedJS final : protected nsAutoXPTCStub, 1563 public nsIXPConnectWrappedJSUnmarkGray, 1564 public nsSupportsWeakReference, 1565 public mozilla::LinkedListElement<nsXPCWrappedJS> { 1566 public: 1567 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1568 NS_DECL_NSISUPPORTSWEAKREFERENCE 1569 1570 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS( 1571 nsXPCWrappedJS, nsIXPConnectWrappedJS) 1572 1573 JSObject* GetJSObject() override; 1574 1575 // This method is defined in XPCWrappedJSClass.cpp to preserve VCS blame. 1576 NS_IMETHOD CallMethod(uint16_t methodIndex, const nsXPTMethodInfo* info, 1577 nsXPTCMiniVariant* nativeParams) override; 1578 1579 /* 1580 * This is rarely called directly. Instead one usually calls 1581 * XPCConvert::JSObject2NativeInterface which will handles cases where the 1582 * JS object is already a wrapped native or a DOM object. 1583 */ 1584 1585 static nsresult GetNewOrUsed(JSContext* cx, JS::HandleObject aJSObj, 1586 REFNSIID aIID, nsXPCWrappedJS** wrapper); 1587 1588 nsISomeInterface* GetXPTCStub() { return mXPTCStub; } 1589 1590 nsresult DebugDump(int16_t depth); 1591 1592 /** 1593 * This getter does not change the color of the JSObject meaning that the 1594 * object returned is not guaranteed to be kept alive past the next CC. 1595 * 1596 * This should only be called if you are certain that the return value won't 1597 * be passed into a JS API function and that it won't be stored without 1598 * being rooted (or otherwise signaling the stored value to the CC). 1599 */ 1600 JSObject* GetJSObjectPreserveColor() const { return mJSObj.unbarrieredGet(); } 1601 1602 // Returns true if the wrapper chain contains references to multiple 1603 // compartments. If the wrapper chain contains references to multiple 1604 // compartments, then it must be registered on the XPCJSContext. Otherwise, 1605 // it should be registered in the CompartmentPrivate for the compartment of 1606 // the root's JS object. This will only return correct results when called 1607 // on the root wrapper and will assert if not called on a root wrapper. 1608 bool IsMultiCompartment() const; 1609 1610 const nsXPTInterfaceInfo* GetInfo() const { return mInfo; } 1611 REFNSIID GetIID() const { return mInfo->IID(); } 1612 nsXPCWrappedJS* GetRootWrapper() const { return mRoot; } 1613 nsXPCWrappedJS* GetNextWrapper() const { return mNext; } 1614 1615 nsXPCWrappedJS* Find(REFNSIID aIID); 1616 nsXPCWrappedJS* FindInherited(REFNSIID aIID); 1617 nsXPCWrappedJS* FindOrFindInherited(REFNSIID aIID) { 1618 nsXPCWrappedJS* wrapper = Find(aIID); 1619 if (wrapper) { 1620 return wrapper; 1621 } 1622 return FindInherited(aIID); 1623 } 1624 1625 bool IsRootWrapper() const { return mRoot == this; } 1626 bool IsValid() const { return bool(mJSObj); } 1627 void SystemIsBeingShutDown(); 1628 1629 // These two methods are used by JSObject2WrappedJSMap::FindDyingJSObjects 1630 // to find non-rooting wrappers for dying JS objects. See the top of 1631 // XPCWrappedJS.cpp for more details. 1632 bool IsSubjectToFinalization() const { return IsValid() && mRefCnt == 1; } 1633 1634 void UpdateObjectPointerAfterGC(JSTracer* trc) { 1635 MOZ_ASSERT(IsRootWrapper()); 1636 JS_UpdateWeakPointerAfterGC(trc, &mJSObj); 1637 } 1638 1639 bool IsAggregatedToNative() const { return mRoot->mOuter != nullptr; } 1640 nsISupports* GetAggregatedNativeObject() const { return mRoot->mOuter; } 1641 void SetAggregatedNativeObject(nsISupports* aNative) { 1642 MOZ_ASSERT(aNative); 1643 if (mRoot->mOuter) { 1644 MOZ_ASSERT(mRoot->mOuter == aNative, 1645 "Only one aggregated native can be set"); 1646 return; 1647 } 1648 mRoot->mOuter = aNative; 1649 } 1650 1651 // This method is defined in XPCWrappedJSClass.cpp to preserve VCS blame. 1652 static void DebugDumpInterfaceInfo(const nsXPTInterfaceInfo* aInfo, 1653 int16_t depth); 1654 1655 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 1656 1657 virtual ~nsXPCWrappedJS(); 1658 1659 protected: 1660 nsXPCWrappedJS() = delete; 1661 nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj, 1662 const nsXPTInterfaceInfo* aInfo, nsXPCWrappedJS* root, 1663 nsresult* rv); 1664 1665 bool CanSkip(); 1666 void Destroy(); 1667 void Unlink(); 1668 1669 private: 1670 friend class nsIXPConnectWrappedJS; 1671 1672 JS::Compartment* Compartment() const { 1673 return JS::GetCompartment(mJSObj.unbarrieredGet()); 1674 } 1675 1676 // These methods are defined in XPCWrappedJSClass.cpp to preserve VCS blame. 1677 static const nsXPTInterfaceInfo* GetInterfaceInfo(REFNSIID aIID); 1678 1679 nsresult DelegatedQueryInterface(REFNSIID aIID, void** aInstancePtr); 1680 1681 static JSObject* GetRootJSObject(JSContext* cx, JSObject* aJSObj); 1682 1683 static JSObject* CallQueryInterfaceOnJSObject(JSContext* cx, JSObject* jsobj, 1684 JS::HandleObject scope, 1685 REFNSIID aIID); 1686 1687 // aObj is the nsXPCWrappedJS's object. We used this as the callee (or |this| 1688 // if getter or setter). 1689 // aSyntheticException, if not null, is the exception we should be using. 1690 // If null, look for an exception on the JSContext hanging off the 1691 // XPCCallContext. 1692 static nsresult CheckForException( 1693 XPCCallContext& ccx, mozilla::dom::AutoEntryScript& aes, 1694 JS::HandleObject aObj, const char* aPropertyName, 1695 const char* anInterfaceName, 1696 mozilla::dom::Exception* aSyntheticException = nullptr); 1697 1698 static bool GetArraySizeFromParam(const nsXPTMethodInfo* method, 1699 const nsXPTType& type, 1700 nsXPTCMiniVariant* params, 1701 uint32_t* result); 1702 1703 static bool GetInterfaceTypeFromParam(const nsXPTMethodInfo* method, 1704 const nsXPTType& type, 1705 nsXPTCMiniVariant* params, 1706 nsID* result); 1707 1708 static void CleanupOutparams(const nsXPTMethodInfo* info, 1709 nsXPTCMiniVariant* nativeParams, bool inOutOnly, 1710 uint8_t count); 1711 1712 JS::Heap<JSObject*> mJSObj; 1713 const nsXPTInterfaceInfo* const mInfo; 1714 nsXPCWrappedJS* mRoot; // If mRoot != this, it is an owning pointer. 1715 nsXPCWrappedJS* mNext; 1716 nsCOMPtr<nsISupports> mOuter; // only set in root 1717 }; 1718 1719 /*************************************************************************** 1720 **************************************************************************** 1721 * 1722 * All manner of utility classes follow... 1723 * 1724 **************************************************************************** 1725 ***************************************************************************/ 1726 1727 namespace xpc { 1728 1729 // A wrapper around JS iterators which presents an equivalent 1730 // nsISimpleEnumerator interface for their contents. 1731 class XPCWrappedJSIterator final : public nsISimpleEnumerator { 1732 public: 1733 NS_DECL_CYCLE_COLLECTION_CLASS(XPCWrappedJSIterator) 1734 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1735 NS_DECL_NSISIMPLEENUMERATOR 1736 NS_DECL_NSISIMPLEENUMERATORBASE 1737 1738 explicit XPCWrappedJSIterator(nsIJSEnumerator* aEnum); 1739 1740 private: 1741 ~XPCWrappedJSIterator() = default; 1742 1743 nsCOMPtr<nsIJSEnumerator> mEnum; 1744 nsCOMPtr<nsIGlobalObject> mGlobal; 1745 nsCOMPtr<nsISupports> mNext; 1746 mozilla::Maybe<bool> mHasNext; 1747 }; 1748 1749 } // namespace xpc 1750 1751 /***************************************************************************/ 1752 // class here just for static methods 1753 class XPCConvert { 1754 public: 1755 /** 1756 * Convert a native object into a JS::Value. 1757 * 1758 * @param cx the JSContext representing the global we want the value in 1759 * @param d [out] the resulting JS::Value 1760 * @param s the native object we're working with 1761 * @param type the type of object that s is 1762 * @param iid the interface of s that we want 1763 * @param scope the default scope to put on the new JSObject's parent 1764 * chain 1765 * @param pErr [out] relevant error code, if any. 1766 */ 1767 1768 static bool NativeData2JS(JSContext* cx, JS::MutableHandleValue d, 1769 const void* s, const nsXPTType& type, 1770 const nsID* iid, uint32_t arrlen, nsresult* pErr); 1771 1772 static bool JSData2Native(JSContext* cx, void* d, JS::HandleValue s, 1773 const nsXPTType& type, const nsID* iid, 1774 uint32_t arrlen, nsresult* pErr); 1775 1776 /** 1777 * Convert a native nsISupports into a JSObject. 1778 * 1779 * @param cx the JSContext representing the global we want the object in. 1780 * @param dest [out] the resulting JSObject 1781 * @param src the native object we're working with 1782 * @param iid the interface of src that we want (may be null) 1783 * @param cache the wrapper cache for src (may be null, in which case src 1784 * will be QI'ed to get the cache) 1785 * @param allowNativeWrapper if true, this method may wrap the resulting 1786 * JSObject in an XPCNativeWrapper and return that, as needed. 1787 * @param pErr [out] relevant error code, if any. 1788 * @param src_is_identity optional performance hint. Set to true only 1789 * if src is the identity pointer. 1790 */ 1791 static bool NativeInterface2JSObject(JSContext* cx, 1792 JS::MutableHandleValue dest, 1793 xpcObjectHelper& aHelper, 1794 const nsID* iid, bool allowNativeWrapper, 1795 nsresult* pErr); 1796 1797 static bool GetNativeInterfaceFromJSObject(void** dest, JSObject* src, 1798 const nsID* iid, nsresult* pErr); 1799 static bool JSObject2NativeInterface(JSContext* cx, void** dest, 1800 JS::HandleObject src, const nsID* iid, 1801 nsISupports* aOuter, nsresult* pErr); 1802 1803 // Note - This return the XPCWrappedNative, rather than the native itself, 1804 // for the WN case. You probably want UnwrapReflectorToISupports. 1805 static bool GetISupportsFromJSObject(JSObject* obj, nsISupports** iface); 1806 1807 static nsresult JSValToXPCException(JSContext* cx, JS::MutableHandleValue s, 1808 const char* ifaceName, 1809 const char* methodName, 1810 mozilla::dom::Exception** exception); 1811 1812 static nsresult ConstructException(nsresult rv, const char* message, 1813 const char* ifaceName, 1814 const char* methodName, nsISupports* data, 1815 mozilla::dom::Exception** exception, 1816 JSContext* cx, JS::Value* jsExceptionPtr); 1817 1818 private: 1819 /** 1820 * Convert a native array into a JS::Value. 1821 * 1822 * @param cx the JSContext we're working with and in whose global the array 1823 * should be created. 1824 * @param d [out] the resulting JS::Value 1825 * @param buf the native buffer containing input values 1826 * @param type the type of objects in the array 1827 * @param iid the interface of each object in the array that we want 1828 * @param count the number of items in the array 1829 * @param scope the default scope to put on the new JSObjects' parent chain 1830 * @param pErr [out] relevant error code, if any. 1831 */ 1832 static bool NativeArray2JS(JSContext* cx, JS::MutableHandleValue d, 1833 const void* buf, const nsXPTType& type, 1834 const nsID* iid, uint32_t count, nsresult* pErr); 1835 1836 using ArrayAllocFixupLen = std::function<void*(uint32_t*)>; 1837 1838 /** 1839 * Convert a JS::Value into a native array. 1840 * 1841 * @param cx the JSContext we're working with 1842 * @param aJSVal the JS::Value to convert 1843 * @param aEltType the type of objects in the array 1844 * @param aIID the interface of each object in the array 1845 * @param pErr [out] relevant error code, if any 1846 * @param aAllocFixupLen function called with the JS Array's length to 1847 * allocate the backing buffer. This function may 1848 * modify the length of array to be converted. 1849 */ 1850 static bool JSArray2Native(JSContext* cx, JS::HandleValue aJSVal, 1851 const nsXPTType& aEltType, const nsIID* aIID, 1852 nsresult* pErr, 1853 const ArrayAllocFixupLen& aAllocFixupLen); 1854 1855 XPCConvert() = delete; 1856 }; 1857 1858 /***************************************************************************/ 1859 // code for throwing exceptions into JS 1860 1861 class nsXPCException; 1862 1863 class XPCThrower { 1864 public: 1865 static void Throw(nsresult rv, JSContext* cx); 1866 static void Throw(nsresult rv, XPCCallContext& ccx); 1867 static void ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx); 1868 static void ThrowBadParam(nsresult rv, unsigned paramNum, 1869 XPCCallContext& ccx); 1870 static bool SetVerbosity(bool state) { 1871 bool old = sVerbose; 1872 sVerbose = state; 1873 return old; 1874 } 1875 1876 static bool CheckForPendingException(nsresult result, JSContext* cx); 1877 1878 private: 1879 static void Verbosify(XPCCallContext& ccx, char** psz, bool own); 1880 1881 private: 1882 static bool sVerbose; 1883 }; 1884 1885 /***************************************************************************/ 1886 1887 class nsXPCException { 1888 public: 1889 static bool NameAndFormatForNSResult(nsresult rv, const char** name, 1890 const char** format); 1891 1892 static const void* IterateNSResults(nsresult* rv, const char** name, 1893 const char** format, const void** iterp); 1894 1895 static uint32_t GetNSResultCount(); 1896 }; 1897 1898 /***************************************************************************/ 1899 // 'Components' object implementation. 1900 1901 class nsXPCComponents final : public nsIXPCComponents { 1902 public: 1903 NS_DECL_ISUPPORTS 1904 NS_DECL_NSIXPCCOMPONENTS 1905 1906 public: 1907 void SystemIsBeingShutDown() { ClearMembers(); } 1908 1909 XPCWrappedNativeScope* GetScope() { return mScope; } 1910 1911 protected: 1912 ~nsXPCComponents(); 1913 1914 explicit nsXPCComponents(XPCWrappedNativeScope* aScope); 1915 void ClearMembers(); 1916 1917 XPCWrappedNativeScope* mScope; 1918 1919 RefPtr<nsXPCComponents_Interfaces> mInterfaces; 1920 RefPtr<nsXPCComponents_Results> mResults; 1921 RefPtr<nsXPCComponents_Classes> mClasses; 1922 RefPtr<nsXPCComponents_ID> mID; 1923 RefPtr<nsXPCComponents_Exception> mException; 1924 RefPtr<nsXPCComponents_Constructor> mConstructor; 1925 RefPtr<nsXPCComponents_Utils> mUtils; 1926 1927 friend class XPCWrappedNativeScope; 1928 }; 1929 1930 /****************************************************************************** 1931 * Handles pre/post script processing. 1932 */ 1933 class MOZ_RAII AutoScriptEvaluate { 1934 public: 1935 /** 1936 * Saves the JSContext as well as initializing our state 1937 * @param cx The JSContext, this can be null, we don't do anything then 1938 */ 1939 explicit AutoScriptEvaluate(JSContext* cx) 1940 : mJSContext(cx), mEvaluated(false) {} 1941 1942 /** 1943 * Does the pre script evaluation. 1944 * This function should only be called once, and will assert if called 1945 * more than once 1946 */ 1947 1948 bool StartEvaluating(JS::HandleObject scope); 1949 1950 /** 1951 * Does the post script evaluation. 1952 */ 1953 ~AutoScriptEvaluate(); 1954 1955 private: 1956 JSContext* mJSContext; 1957 mozilla::Maybe<JS::AutoSaveExceptionState> mState; 1958 bool mEvaluated; 1959 mozilla::Maybe<JSAutoRealm> mAutoRealm; 1960 1961 // No copying or assignment allowed 1962 AutoScriptEvaluate(const AutoScriptEvaluate&) = delete; 1963 AutoScriptEvaluate& operator=(const AutoScriptEvaluate&) = delete; 1964 }; 1965 1966 /***************************************************************************/ 1967 class MOZ_RAII AutoResolveName { 1968 public: 1969 AutoResolveName(XPCCallContext& ccx, JS::HandleId name) 1970 : mContext(ccx.GetContext()), 1971 mOld(ccx, mContext->SetResolveName(name)) 1972 #ifdef DEBUG 1973 , 1974 mCheck(ccx, name) 1975 #endif 1976 { 1977 } 1978 1979 ~AutoResolveName() { 1980 mozilla::DebugOnly<jsid> old = mContext->SetResolveName(mOld); 1981 MOZ_ASSERT(old == mCheck, "Bad Nesting!"); 1982 } 1983 1984 private: 1985 XPCJSContext* mContext; 1986 JS::RootedId mOld; 1987 #ifdef DEBUG 1988 JS::RootedId mCheck; 1989 #endif 1990 }; 1991 1992 /***************************************************************************/ 1993 // AutoMarkingPtr is the base class for the various AutoMarking pointer types 1994 // below. This system allows us to temporarily protect instances of our garbage 1995 // collected types after they are constructed but before they are safely 1996 // attached to other rooted objects. 1997 // This base class has pure virtual support for marking. 1998 1999 class AutoMarkingPtr { 2000 public: 2001 explicit AutoMarkingPtr(JSContext* cx) { 2002 mRoot = XPCJSContext::Get()->GetAutoRootsAdr(); 2003 mNext = *mRoot; 2004 *mRoot = this; 2005 } 2006 2007 virtual ~AutoMarkingPtr() { 2008 if (mRoot) { 2009 MOZ_ASSERT(*mRoot == this); 2010 *mRoot = mNext; 2011 } 2012 } 2013 2014 void TraceJSAll(JSTracer* trc) { 2015 for (AutoMarkingPtr* cur = this; cur; cur = cur->mNext) { 2016 cur->TraceJS(trc); 2017 } 2018 } 2019 2020 void MarkAfterJSFinalizeAll() { 2021 for (AutoMarkingPtr* cur = this; cur; cur = cur->mNext) { 2022 cur->MarkAfterJSFinalize(); 2023 } 2024 } 2025 2026 protected: 2027 virtual void TraceJS(JSTracer* trc) = 0; 2028 virtual void MarkAfterJSFinalize() = 0; 2029 2030 private: 2031 AutoMarkingPtr** mRoot; 2032 AutoMarkingPtr* mNext; 2033 }; 2034 2035 template <class T> 2036 class TypedAutoMarkingPtr : public AutoMarkingPtr { 2037 public: 2038 explicit TypedAutoMarkingPtr(JSContext* cx) 2039 : AutoMarkingPtr(cx), mPtr(nullptr) {} 2040 TypedAutoMarkingPtr(JSContext* cx, T* ptr) : AutoMarkingPtr(cx), mPtr(ptr) {} 2041 2042 T* get() const { return mPtr; } 2043 operator T*() const { return mPtr; } 2044 T* operator->() const { return mPtr; } 2045 2046 TypedAutoMarkingPtr<T>& operator=(T* ptr) { 2047 mPtr = ptr; 2048 return *this; 2049 } 2050 2051 protected: 2052 virtual void TraceJS(JSTracer* trc) override { 2053 if (mPtr) { 2054 mPtr->TraceJS(trc); 2055 mPtr->AutoTrace(trc); 2056 } 2057 } 2058 2059 virtual void MarkAfterJSFinalize() override { 2060 if (mPtr) { 2061 mPtr->Mark(); 2062 } 2063 } 2064 2065 private: 2066 T* mPtr; 2067 }; 2068 2069 using AutoMarkingWrappedNativePtr = TypedAutoMarkingPtr<XPCWrappedNative>; 2070 using AutoMarkingWrappedNativeTearOffPtr = 2071 TypedAutoMarkingPtr<XPCWrappedNativeTearOff>; 2072 using AutoMarkingWrappedNativeProtoPtr = 2073 TypedAutoMarkingPtr<XPCWrappedNativeProto>; 2074 2075 /***************************************************************************/ 2076 // Definitions in XPCVariant.cpp. 2077 2078 // {1809FD50-91E8-11d5-90F9-0010A4E73D9A} 2079 #define XPCVARIANT_IID \ 2080 {0x1809fd50, 0x91e8, 0x11d5, {0x90, 0xf9, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a}} 2081 2082 // {DC524540-487E-4501-9AC7-AAA784B17C1C} 2083 #define XPCVARIANT_CID \ 2084 {0xdc524540, 0x487e, 0x4501, {0x9a, 0xc7, 0xaa, 0xa7, 0x84, 0xb1, 0x7c, 0x1c}} 2085 2086 class XPCVariant : public nsIVariant { 2087 public: 2088 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 2089 NS_DECL_NSIVARIANT 2090 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(XPCVariant) 2091 2092 // If this class ever implements nsIWritableVariant, take special care with 2093 // the case when mJSVal is JSVAL_STRING, since we don't own the data in 2094 // that case. 2095 2096 // We #define and iid so that out module local code can use QI to detect 2097 // if a given nsIVariant is in fact an XPCVariant. 2098 NS_INLINE_DECL_STATIC_IID(XPCVARIANT_IID) 2099 2100 static already_AddRefed<XPCVariant> newVariant(JSContext* cx, 2101 const JS::Value& aJSVal); 2102 2103 /** 2104 * This getter clears the gray bit before handing out the Value if the Value 2105 * represents a JSObject. That means that the object is guaranteed to be 2106 * kept alive past the next CC. 2107 */ 2108 JS::Value GetJSVal() const { return mJSVal; } 2109 2110 protected: 2111 /** 2112 * This getter does not change the color of the Value (if it represents a 2113 * JSObject) meaning that the value returned is not guaranteed to be kept 2114 * alive past the next CC. 2115 * 2116 * This should only be called if you are certain that the return value won't 2117 * be passed into a JS API function and that it won't be stored without 2118 * being rooted (or otherwise signaling the stored value to the CC). 2119 */ 2120 JS::Value GetJSValPreserveColor() const { return mJSVal.unbarrieredGet(); } 2121 2122 XPCVariant(JSContext* cx, const JS::Value& aJSVal); 2123 2124 public: 2125 /** 2126 * Convert a variant into a JS::Value. 2127 * 2128 * @param cx the context for the whole procedure 2129 * @param variant the variant to convert 2130 * @param scope the default scope to put on the new JSObject's parent chain 2131 * @param pErr [out] relevant error code, if any. 2132 * @param pJSVal [out] the resulting jsval. 2133 */ 2134 static bool VariantDataToJS(JSContext* cx, nsIVariant* variant, 2135 nsresult* pErr, JS::MutableHandleValue pJSVal); 2136 2137 protected: 2138 virtual ~XPCVariant(); 2139 2140 bool InitializeData(JSContext* cx); 2141 2142 void Cleanup(); 2143 2144 nsDiscriminatedUnion mData; 2145 JS::Heap<JS::Value> mJSVal; 2146 bool mReturnRawObject; 2147 }; 2148 2149 /***************************************************************************/ 2150 // Utilities 2151 2152 inline JSContext* xpc_GetSafeJSContext() { 2153 return XPCJSContext::Get()->Context(); 2154 } 2155 2156 namespace xpc { 2157 2158 // JSNatives to expose atob and btoa in various non-DOM XPConnect scopes. 2159 bool Atob(JSContext* cx, unsigned argc, JS::Value* vp); 2160 2161 bool Btoa(JSContext* cx, unsigned argc, JS::Value* vp); 2162 2163 // Helper function that creates a JSFunction that wraps a native function that 2164 // forwards the call to the original 'callable'. 2165 class FunctionForwarderOptions; 2166 bool NewFunctionForwarder(JSContext* cx, JS::HandleId id, 2167 JS::HandleObject callable, 2168 FunctionForwarderOptions& options, 2169 JS::MutableHandleValue vp); 2170 2171 // Old fashioned xpc error reporter. Try to use JS_ReportError instead. 2172 nsresult ThrowAndFail(nsresult errNum, JSContext* cx, bool* retval); 2173 2174 struct GlobalProperties { 2175 GlobalProperties() { mozilla::PodZero(this); } 2176 bool Parse(JSContext* cx, JS::HandleObject obj); 2177 bool DefineInXPCComponents(JSContext* cx, JS::HandleObject obj); 2178 bool DefineInSandbox(JSContext* cx, JS::HandleObject obj); 2179 2180 // Interface objects we can expose. 2181 bool AbortController : 1; 2182 bool Blob : 1; 2183 bool ChromeUtils : 1; 2184 bool CSS : 1; 2185 bool CSSPositionTryDescriptors : 1; 2186 bool CSSRule : 1; 2187 bool CustomStateSet : 1; 2188 bool Directory : 1; 2189 bool Document : 1; 2190 bool DOMException : 1; 2191 bool DOMParser : 1; 2192 bool DOMTokenList : 1; 2193 bool Element : 1; 2194 bool Event : 1; 2195 bool File : 1; 2196 bool FileReader : 1; 2197 bool FormData : 1; 2198 bool Headers : 1; 2199 bool IOUtils : 1; 2200 bool InspectorCSSParser : 1; 2201 bool InspectorUtils : 1; 2202 bool MessageChannel : 1; 2203 bool MIDIInputMap : 1; 2204 bool MIDIOutputMap : 1; 2205 bool Node : 1; 2206 bool NodeFilter : 1; 2207 bool PathUtils : 1; 2208 bool Performance : 1; 2209 bool PromiseDebugging : 1; 2210 bool Range : 1; 2211 bool Selection : 1; 2212 bool TextDecoder : 1; 2213 bool TextEncoder : 1; 2214 bool TrustedHTML : 1; 2215 bool TrustedScript : 1; 2216 bool TrustedScriptURL : 1; 2217 bool URL : 1; 2218 bool URLSearchParams : 1; 2219 bool XMLHttpRequest : 1; 2220 bool WebSocket : 1; 2221 bool Window : 1; 2222 bool XMLSerializer : 1; 2223 bool ReadableStream : 1; 2224 2225 // Ad-hoc property names we implement. 2226 bool atob : 1; 2227 bool btoa : 1; 2228 bool caches : 1; 2229 bool crypto : 1; 2230 bool fetch : 1; 2231 bool storage : 1; 2232 bool structuredClone : 1; 2233 bool locks : 1; 2234 bool indexedDB : 1; 2235 bool isSecureContext : 1; 2236 bool rtcIdentityProvider : 1; 2237 2238 private: 2239 bool Define(JSContext* cx, JS::HandleObject obj); 2240 }; 2241 2242 // Infallible. 2243 already_AddRefed<nsIXPCComponents_utils_Sandbox> NewSandboxConstructor(); 2244 2245 // Returns true if class of 'obj' is SandboxClass. 2246 bool IsSandbox(JSObject* obj); 2247 2248 class MOZ_STACK_CLASS OptionsBase { 2249 public: 2250 explicit OptionsBase(JSContext* cx = xpc_GetSafeJSContext(), 2251 JSObject* options = nullptr) 2252 : mCx(cx), mObject(cx, options) {} 2253 2254 virtual bool Parse() = 0; 2255 2256 protected: 2257 bool ParseValue(const char* name, JS::MutableHandleValue prop, 2258 bool* found = nullptr); 2259 bool ParseBoolean(const char* name, bool* prop); 2260 bool ParseObject(const char* name, JS::MutableHandleObject prop); 2261 bool ParseJSString(const char* name, JS::MutableHandleString prop); 2262 bool ParseString(const char* name, nsCString& prop); 2263 bool ParseString(const char* name, nsString& prop); 2264 bool ParseOptionalString(const char* name, mozilla::Maybe<nsString>& prop); 2265 bool ParseId(const char* name, JS::MutableHandleId id); 2266 bool ParseUInt32(const char* name, uint32_t* prop); 2267 2268 JSContext* mCx; 2269 JS::RootedObject mObject; 2270 }; 2271 2272 class MOZ_STACK_CLASS SandboxOptions : public OptionsBase { 2273 public: 2274 explicit SandboxOptions(JSContext* cx = xpc_GetSafeJSContext(), 2275 JSObject* options = nullptr) 2276 : OptionsBase(cx, options), 2277 wantXrays(true), 2278 allowWaivers(true), 2279 wantComponents(true), 2280 wantExportHelpers(false), 2281 isWebExtensionContentScript(false), 2282 proto(cx), 2283 sameZoneAs(cx), 2284 forceSecureContext(false), 2285 freshCompartment(false), 2286 freshZone(false), 2287 isUAWidgetScope(false), 2288 invisibleToDebugger(false), 2289 discardSource(false), 2290 metadata(cx), 2291 userContextId(0), 2292 originAttributes(cx), 2293 alwaysUseFdlibm(false) {} 2294 2295 virtual bool Parse() override; 2296 2297 bool wantXrays; 2298 bool allowWaivers; 2299 bool wantComponents; 2300 bool wantExportHelpers; 2301 bool isWebExtensionContentScript; 2302 JS::RootedObject proto; 2303 mozilla::Maybe<nsString> sandboxContentSecurityPolicy; 2304 nsCString sandboxName; 2305 JS::RootedObject sameZoneAs; 2306 bool forceSecureContext; 2307 bool freshCompartment; 2308 bool freshZone; 2309 bool isUAWidgetScope; 2310 bool invisibleToDebugger; 2311 bool discardSource; 2312 GlobalProperties globalProperties; 2313 JS::RootedValue metadata; 2314 uint32_t userContextId; 2315 JS::RootedObject originAttributes; 2316 bool alwaysUseFdlibm; 2317 2318 protected: 2319 bool ParseGlobalProperties(); 2320 }; 2321 2322 class MOZ_STACK_CLASS CreateObjectInOptions : public OptionsBase { 2323 public: 2324 explicit CreateObjectInOptions(JSContext* cx = xpc_GetSafeJSContext(), 2325 JSObject* options = nullptr) 2326 : OptionsBase(cx, options), defineAs(cx, JS::PropertyKey::Void()) {} 2327 2328 virtual bool Parse() override { return ParseId("defineAs", &defineAs); } 2329 2330 JS::RootedId defineAs; 2331 }; 2332 2333 class MOZ_STACK_CLASS ExportFunctionOptions : public OptionsBase { 2334 public: 2335 explicit ExportFunctionOptions(JSContext* cx = xpc_GetSafeJSContext(), 2336 JSObject* options = nullptr) 2337 : OptionsBase(cx, options), 2338 defineAs(cx, JS::PropertyKey::Void()), 2339 allowCrossOriginArguments(false) {} 2340 2341 virtual bool Parse() override { 2342 return ParseId("defineAs", &defineAs) && 2343 ParseBoolean("allowCrossOriginArguments", 2344 &allowCrossOriginArguments); 2345 } 2346 2347 JS::RootedId defineAs; 2348 bool allowCrossOriginArguments; 2349 }; 2350 2351 class MOZ_STACK_CLASS FunctionForwarderOptions : public OptionsBase { 2352 public: 2353 explicit FunctionForwarderOptions(JSContext* cx = xpc_GetSafeJSContext(), 2354 JSObject* options = nullptr) 2355 : OptionsBase(cx, options), allowCrossOriginArguments(false) {} 2356 2357 JSObject* ToJSObject(JSContext* cx) { 2358 JS::RootedObject obj(cx, JS_NewObjectWithGivenProto(cx, nullptr, nullptr)); 2359 if (!obj) { 2360 return nullptr; 2361 } 2362 2363 JS::RootedValue val(cx); 2364 unsigned attrs = JSPROP_READONLY | JSPROP_PERMANENT; 2365 val = JS::BooleanValue(allowCrossOriginArguments); 2366 if (!JS_DefineProperty(cx, obj, "allowCrossOriginArguments", val, attrs)) { 2367 return nullptr; 2368 } 2369 2370 return obj; 2371 } 2372 2373 virtual bool Parse() override { 2374 return ParseBoolean("allowCrossOriginArguments", 2375 &allowCrossOriginArguments); 2376 } 2377 2378 bool allowCrossOriginArguments; 2379 }; 2380 2381 class MOZ_STACK_CLASS StackScopedCloneOptions : public OptionsBase { 2382 public: 2383 explicit StackScopedCloneOptions(JSContext* cx = xpc_GetSafeJSContext(), 2384 JSObject* options = nullptr) 2385 : OptionsBase(cx, options), 2386 wrapReflectors(false), 2387 cloneFunctions(false), 2388 deepFreeze(false) {} 2389 2390 virtual bool Parse() override { 2391 return ParseBoolean("wrapReflectors", &wrapReflectors) && 2392 ParseBoolean("cloneFunctions", &cloneFunctions) && 2393 ParseBoolean("deepFreeze", &deepFreeze); 2394 } 2395 2396 // When a reflector is encountered, wrap it rather than aborting the clone. 2397 bool wrapReflectors; 2398 2399 // When a function is encountered, clone it (exportFunction-style) rather than 2400 // aborting the clone. 2401 bool cloneFunctions; 2402 2403 // If true, the resulting object is deep-frozen after being cloned. 2404 bool deepFreeze; 2405 }; 2406 2407 JSObject* CreateGlobalObject(JSContext* cx, const JSClass* clasp, 2408 nsIPrincipal* principal, 2409 JS::RealmOptions& aOptions); 2410 2411 // Finish initializing an already-created, not-yet-exposed-to-script global 2412 // object. This will attach a Components object (if necessary) and call 2413 // |JS_FireOnNewGlobalObject| (if necessary). 2414 // 2415 // If you must modify compartment options, see InitGlobalObjectOptions above. 2416 bool InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, 2417 uint32_t aFlags); 2418 2419 // Helper for creating a sandbox object to use for evaluating 2420 // untrusted code completely separated from all other code in the 2421 // system using EvalInSandbox(). Takes the JSContext on which to 2422 // do setup etc on, puts the sandbox object in *vp (which must be 2423 // rooted by the caller), and uses the principal that's either 2424 // directly passed in prinOrSop or indirectly as an 2425 // nsIScriptObjectPrincipal holding the principal. If no principal is 2426 // reachable through prinOrSop, a new null principal will be created 2427 // and used. 2428 nsresult CreateSandboxObject(JSContext* cx, JS::MutableHandleValue vp, 2429 nsISupports* prinOrSop, 2430 xpc::SandboxOptions& options); 2431 // Helper for evaluating scripts in a sandbox object created with 2432 // CreateSandboxObject(). The caller is responsible of ensuring 2433 // that *rval doesn't get collected during the call or usage after the 2434 // call. This helper will use filename and lineNo for error reporting, 2435 // and if no filename is provided it will use the codebase from the 2436 // principal and line number 1 as a fallback. 2437 nsresult EvalInSandbox(JSContext* cx, JS::HandleObject sandbox, 2438 const nsAString& source, const nsACString& filename, 2439 int32_t lineNo, bool enforceFilenameRestrictions, 2440 JS::MutableHandleValue rval); 2441 2442 // Helper for retrieving metadata stored in a reserved slot. The metadata 2443 // is set during the sandbox creation using the "metadata" option. 2444 nsresult GetSandboxMetadata(JSContext* cx, JS::HandleObject sandboxArg, 2445 JS::MutableHandleValue rval); 2446 2447 [[nodiscard]] nsresult SetSandboxMetadata(JSContext* cx, 2448 JS::HandleObject sandboxArg, 2449 JS::HandleValue metadata); 2450 2451 [[nodiscard]] nsresult SetSandboxLocaleOverride(JSContext* cx, 2452 JS::HandleObject sandboxArg, 2453 const char* locale); 2454 2455 [[nodiscard]] nsresult SetSandboxTimezoneOverride(JSContext* cx, 2456 JS::HandleObject sandboxArg, 2457 const char* timezone); 2458 2459 bool CreateObjectIn(JSContext* cx, JS::HandleValue vobj, 2460 CreateObjectInOptions& options, 2461 JS::MutableHandleValue rval); 2462 2463 bool EvalInWindow(JSContext* cx, const nsAString& source, 2464 JS::HandleObject scope, JS::MutableHandleValue rval); 2465 2466 bool ExportFunction(JSContext* cx, JS::HandleValue vscope, 2467 JS::HandleValue vfunction, JS::HandleValue voptions, 2468 JS::MutableHandleValue rval); 2469 2470 bool CloneInto(JSContext* cx, JS::HandleValue vobj, JS::HandleValue vscope, 2471 JS::HandleValue voptions, JS::MutableHandleValue rval); 2472 2473 bool StackScopedClone(JSContext* cx, StackScopedCloneOptions& options, 2474 JS::HandleObject sourceScope, JS::MutableHandleValue val); 2475 2476 } /* namespace xpc */ 2477 2478 /***************************************************************************/ 2479 // Inlined utilities. 2480 2481 inline bool xpc_ForcePropertyResolve(JSContext* cx, JS::HandleObject obj, 2482 jsid id); 2483 2484 inline jsid GetJSIDByIndex(JSContext* cx, unsigned index); 2485 2486 namespace xpc { 2487 2488 enum WrapperDenialType { 2489 WrapperDenialForXray = 0, 2490 WrapperDenialForCOW, 2491 WrapperDenialTypeCount 2492 }; 2493 bool ReportWrapperDenial(JSContext* cx, JS::HandleId id, WrapperDenialType type, 2494 const char* reason); 2495 2496 class CompartmentOriginInfo { 2497 public: 2498 CompartmentOriginInfo(const CompartmentOriginInfo&) = delete; 2499 2500 CompartmentOriginInfo(mozilla::BasePrincipal* aOrigin, 2501 const mozilla::SiteIdentifier& aSite) 2502 : mOrigin(aOrigin), mSite(aSite) { 2503 MOZ_ASSERT(aOrigin); 2504 MOZ_ASSERT(aSite.IsInitialized()); 2505 } 2506 2507 bool IsSameOrigin(nsIPrincipal* aOther) const; 2508 2509 // Does the principal of compartment a subsume the principal of compartment b? 2510 static bool Subsumes(JS::Compartment* aCompA, JS::Compartment* aCompB); 2511 static bool SubsumesIgnoringFPD(JS::Compartment* aCompA, 2512 JS::Compartment* aCompB); 2513 2514 bool MightBeWebContent() const; 2515 2516 // Note: this principal must not be used for subsumes/equality checks 2517 // considering document.domain. See mOrigin. 2518 mozilla::BasePrincipal* GetPrincipalIgnoringDocumentDomain() const { 2519 return mOrigin; 2520 } 2521 2522 const mozilla::SiteIdentifier& SiteRef() const { return mSite; } 2523 2524 bool HasChangedDocumentDomain() const { return mChangedDocumentDomain; } 2525 void SetChangedDocumentDomain() { mChangedDocumentDomain = true; } 2526 2527 private: 2528 // All globals in the compartment must have this origin. Note that 2529 // individual globals and principals can have their domain changed via 2530 // document.domain, so this principal must not be used for things like 2531 // subsumesConsideringDomain or equalsConsideringDomain. Use the realm's 2532 // principal for that. 2533 RefPtr<mozilla::BasePrincipal> mOrigin; 2534 2535 // In addition to the origin we also store the SiteIdentifier. When realms 2536 // in different compartments can become same-origin (via document.domain), 2537 // these compartments must have equal SiteIdentifiers. (This is derived from 2538 // mOrigin but we cache it here for performance reasons.) 2539 mozilla::SiteIdentifier mSite; 2540 2541 // True if any global in this compartment mutated document.domain. 2542 bool mChangedDocumentDomain = false; 2543 }; 2544 2545 // The CompartmentPrivate contains XPConnect-specific stuff related to each JS 2546 // compartment. Since compartments are trust domains, this means mostly 2547 // information needed to select the right security policy for cross-compartment 2548 // wrappers. 2549 class CompartmentPrivate { 2550 CompartmentPrivate() = delete; 2551 CompartmentPrivate(const CompartmentPrivate&) = delete; 2552 2553 public: 2554 CompartmentPrivate(JS::Compartment* c, 2555 mozilla::UniquePtr<XPCWrappedNativeScope> scope, 2556 mozilla::BasePrincipal* origin, 2557 const mozilla::SiteIdentifier& site); 2558 2559 ~CompartmentPrivate(); 2560 2561 static CompartmentPrivate* Get(JS::Compartment* compartment) { 2562 MOZ_ASSERT(compartment); 2563 void* priv = JS_GetCompartmentPrivate(compartment); 2564 return static_cast<CompartmentPrivate*>(priv); 2565 } 2566 2567 static CompartmentPrivate* Get(JS::Realm* realm) { 2568 MOZ_ASSERT(realm); 2569 JS::Compartment* compartment = JS::GetCompartmentForRealm(realm); 2570 return Get(compartment); 2571 } 2572 2573 static CompartmentPrivate* Get(JSObject* object) { 2574 JS::Compartment* compartment = JS::GetCompartment(object); 2575 return Get(compartment); 2576 } 2577 2578 bool CanShareCompartmentWith(nsIPrincipal* principal) { 2579 // Only share if we're same-origin with the principal. 2580 if (!originInfo.IsSameOrigin(principal)) { 2581 return false; 2582 } 2583 2584 // Don't share if we have any weird state set. 2585 return !wantXrays && !isWebExtensionContentScript && 2586 !isUAWidgetCompartment && mScope->XBLScopeStateMatches(principal); 2587 } 2588 2589 CompartmentOriginInfo originInfo; 2590 2591 // Controls whether this compartment gets Xrays to same-origin. This behavior 2592 // is deprecated, but is still the default for sandboxes for compatibity 2593 // reasons. 2594 bool wantXrays; 2595 2596 // Controls whether this compartment is allowed to waive Xrays to content 2597 // that it subsumes. This should generally be true, except in cases where we 2598 // want to prevent code from depending on Xray Waivers (which might make it 2599 // more portable to other browser architectures). 2600 bool allowWaivers; 2601 2602 // This compartment corresponds to a WebExtension content script, and 2603 // receives various bits of special compatibility behavior. 2604 bool isWebExtensionContentScript; 2605 2606 // True if this compartment is a UA widget compartment. 2607 bool isUAWidgetCompartment; 2608 2609 // See CompartmentHasExclusiveExpandos. 2610 bool hasExclusiveExpandos; 2611 2612 // Whether SystemIsBeingShutDown has been called on this compartment. 2613 bool wasShutdown; 2614 2615 JSObject2WrappedJSMap* GetWrappedJSMap() const { return mWrappedJSMap.get(); } 2616 void UpdateWeakPointersAfterGC(JSTracer* trc); 2617 2618 void SystemIsBeingShutDown(); 2619 2620 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); 2621 2622 struct MapEntryGCPolicy { 2623 static bool traceWeak(JSTracer* trc, const void* /* unused */, 2624 JS::Heap<JSObject*>* value) { 2625 return JS::GCPolicy<JS::Heap<JSObject*>>::traceWeak(trc, value); 2626 } 2627 }; 2628 2629 typedef JS::GCHashMap<const void*, JS::Heap<JSObject*>, 2630 mozilla::PointerHasher<const void*>, 2631 js::SystemAllocPolicy, MapEntryGCPolicy> 2632 RemoteProxyMap; 2633 RemoteProxyMap& GetRemoteProxyMap() { return mRemoteProxies; } 2634 2635 XPCWrappedNativeScope* GetScope() { return mScope.get(); } 2636 2637 private: 2638 mozilla::UniquePtr<JSObject2WrappedJSMap> mWrappedJSMap; 2639 2640 // Cache holding proxy objects for Window objects (and their Location object) 2641 // that are loaded in a different process. 2642 RemoteProxyMap mRemoteProxies; 2643 2644 // Our XPCWrappedNativeScope. 2645 mozilla::UniquePtr<XPCWrappedNativeScope> mScope; 2646 }; 2647 2648 inline void CrashIfNotInAutomation() { MOZ_RELEASE_ASSERT(IsInAutomation()); } 2649 2650 // XPConnect-specific data associated with each JavaScript realm. Per-Window 2651 // settings live here; security-wrapper-related settings live in the 2652 // CompartmentPrivate. 2653 // 2654 // Following the ECMAScript spec, a realm contains a global (e.g. an inner 2655 // Window) and its associated scripts and objects; a compartment may contain 2656 // several same-origin realms. 2657 class RealmPrivate { 2658 RealmPrivate() = delete; 2659 RealmPrivate(const RealmPrivate&) = delete; 2660 2661 public: 2662 enum LocationHint { LocationHintRegular, LocationHintAddon }; 2663 2664 explicit RealmPrivate(JS::Realm* realm); 2665 2666 // Creates the RealmPrivate and CompartmentPrivate (if needed) for a new 2667 // global. 2668 static void Init(JS::HandleObject aGlobal, 2669 const mozilla::SiteIdentifier& aSite); 2670 2671 static RealmPrivate* Get(JS::Realm* realm) { 2672 MOZ_ASSERT(realm); 2673 void* priv = JS::GetRealmPrivate(realm); 2674 return static_cast<RealmPrivate*>(priv); 2675 } 2676 2677 // Get the RealmPrivate for a given object. `object` must not be a 2678 // cross-compartment wrapper, as CCWs aren't dedicated to a particular 2679 // realm. 2680 static RealmPrivate* Get(JSObject* object) { 2681 JS::Realm* realm = JS::GetObjectRealmOrNull(object); 2682 return Get(realm); 2683 } 2684 2685 // The scriptability of this realm. 2686 Scriptability scriptability; 2687 2688 // Whether we've emitted a warning about a property that was filtered out 2689 // by a security wrapper. See XrayWrapper.cpp. 2690 bool wrapperDenialWarnings[WrapperDenialTypeCount]; 2691 2692 const nsACString& GetLocation() { 2693 if (location.IsEmpty() && locationURI) { 2694 nsCOMPtr<nsIXPConnectWrappedJS> jsLocationURI = 2695 do_QueryInterface(locationURI); 2696 if (jsLocationURI) { 2697 // We cannot call into JS-implemented nsIURI objects, because 2698 // we are iterating over the JS heap at this point. 2699 location = "<JS-implemented nsIURI location>"_ns; 2700 } else if (NS_FAILED(locationURI->GetSpec(location))) { 2701 location = "<unknown location>"_ns; 2702 } 2703 } 2704 return location; 2705 } 2706 bool GetLocationURI(LocationHint aLocationHint, nsIURI** aURI) { 2707 if (locationURI) { 2708 nsCOMPtr<nsIURI> rval = locationURI; 2709 rval.forget(aURI); 2710 return true; 2711 } 2712 return TryParseLocationURI(aLocationHint, aURI); 2713 } 2714 bool GetLocationURI(nsIURI** aURI) { 2715 return GetLocationURI(LocationHintRegular, aURI); 2716 } 2717 2718 void SetLocation(const nsACString& aLocation) { 2719 if (aLocation.IsEmpty()) { 2720 return; 2721 } 2722 if (!location.IsEmpty() || locationURI) { 2723 return; 2724 } 2725 location = aLocation; 2726 } 2727 void SetLocationURI(nsIURI* aLocationURI) { 2728 if (!aLocationURI) { 2729 return; 2730 } 2731 if (locationURI) { 2732 return; 2733 } 2734 locationURI = aLocationURI; 2735 } 2736 2737 // JSStackFrames are tracked on a per-realm basis so they 2738 // can be cleared when the associated window goes away. 2739 void RegisterStackFrame(JSStackFrameBase* aFrame); 2740 void UnregisterStackFrame(JSStackFrameBase* aFrame); 2741 void NukeJSStackFrames(); 2742 2743 private: 2744 nsCString location; 2745 nsCOMPtr<nsIURI> locationURI; 2746 2747 bool TryParseLocationURI(LocationHint aType, nsIURI** aURI); 2748 2749 nsTHashtable<nsPtrHashKey<JSStackFrameBase>> mJSStackFrames; 2750 }; 2751 2752 inline XPCWrappedNativeScope* ObjectScope(JSObject* obj) { 2753 return CompartmentPrivate::Get(obj)->GetScope(); 2754 } 2755 2756 JSObject* NewOutObject(JSContext* cx); 2757 bool IsOutObject(JSContext* cx, JSObject* obj); 2758 2759 nsresult HasInstance(JSContext* cx, JS::HandleObject objArg, const nsID* iid, 2760 bool* bp); 2761 2762 // Returns the principal associated with |obj|'s realm. The object must not be a 2763 // cross-compartment wrapper. 2764 nsIPrincipal* GetObjectPrincipal(JSObject* obj); 2765 2766 // Attempt to clean up the passed in value pointer. The pointer `value` must be 2767 // a pointer to a value described by the type `nsXPTType`. 2768 // 2769 // This method expects a value of the following types: 2770 // TD_NSIDPTR 2771 // value : nsID* (free) 2772 // TD_ASTRING, TD_CSTRING, TD_UTF8STRING 2773 // value : ns[C]String* (truncate) 2774 // TD_PSTRING, TD_PWSTRING, TD_PSTRING_SIZE_IS, TD_PWSTRING_SIZE_IS 2775 // value : char[16_t]** (free) 2776 // TD_INTERFACE_TYPE, TD_INTERFACE_IS_TYPE 2777 // value : nsISupports** (release) 2778 // TD_LEGACY_ARRAY (NOTE: aArrayLen should be passed) 2779 // value : void** (destroy elements & free) 2780 // TD_ARRAY 2781 // value : nsTArray<T>* (destroy elements & Clear) 2782 // TD_DOMOBJECT 2783 // value : T** (cleanup) 2784 // TD_PROMISE 2785 // value : dom::Promise** (release) 2786 // 2787 // Other types are ignored. 2788 inline void CleanupValue(const nsXPTType& aType, void* aValue, 2789 uint32_t aArrayLen = 0); 2790 2791 // Out-of-line internals for xpc::CleanupValue. Defined in XPCConvert.cpp. 2792 void InnerCleanupValue(const nsXPTType& aType, void* aValue, 2793 uint32_t aArrayLen); 2794 2795 // In order to be able to safely call CleanupValue on a generated value, the 2796 // data behind it needs to be initialized to a safe value. This method handles 2797 // initializing the backing data to a safe value to use as an argument to 2798 // XPCConvert methods, or xpc::CleanupValue. 2799 // 2800 // The pointer `aValue` must point to a block of memory at least aType.Stride() 2801 // bytes large, and correctly aligned. 2802 // 2803 // This method accepts the same types as xpc::CleanupValue. 2804 void InitializeValue(const nsXPTType& aType, void* aValue); 2805 2806 // If a value was initialized with InitializeValue, it should be destroyed with 2807 // DestructValue. This method acts like CleanupValue, except that destructors 2808 // for complex types are also invoked, leaving them in an invalid state. 2809 // 2810 // This method should be called when destroying types initialized with 2811 // InitializeValue. 2812 // 2813 // The pointer 'aValue' must point to a valid value of type 'aType'. 2814 void DestructValue(const nsXPTType& aType, void* aValue, 2815 uint32_t aArrayLen = 0); 2816 2817 bool SandboxCreateCrypto(JSContext* cx, JS::Handle<JSObject*> obj); 2818 bool SandboxCreateFetch(JSContext* cx, JS::Handle<JSObject*> obj); 2819 bool SandboxCreateStructuredClone(JSContext* cx, JS::Handle<JSObject*> obj); 2820 bool SandboxCreateLocks(JSContext* cx, JS::Handle<JSObject*> obj); 2821 2822 } // namespace xpc 2823 2824 namespace mozilla { 2825 namespace dom { 2826 extern bool DefineStaticJSVals(JSContext* cx); 2827 } // namespace dom 2828 } // namespace mozilla 2829 2830 bool xpc_LocalizeRuntime(JSRuntime* rt); 2831 void xpc_DelocalizeRuntime(JSRuntime* rt); 2832 2833 /***************************************************************************/ 2834 // Inlines use the above - include last. 2835 2836 #include "XPCInlines.h" 2837 2838 /***************************************************************************/ 2839 2840 #endif /* xpcprivate_h___ */