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