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