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 /* The "Components" xpcom objects for JavaScript. */
8 
9 #include "xpcprivate.h"
10 #include "xpc_make_class.h"
11 #include "XPCJSWeakReference.h"
12 #include "WrapperFactory.h"
13 #include "nsJSUtils.h"
14 #include "mozJSComponentLoader.h"
15 #include "nsContentUtils.h"
16 #include "nsCycleCollector.h"
17 #include "jsfriendapi.h"
18 #include "js/StructuredClone.h"
19 #include "mozilla/Attributes.h"
20 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
21 #include "mozilla/Preferences.h"
22 #include "nsJSEnvironment.h"
23 #include "mozilla/TimeStamp.h"
24 #include "mozilla/ResultExtensions.h"
25 #include "mozilla/URLPreloader.h"
26 #include "mozilla/XPTInterfaceInfoManager.h"
27 #include "mozilla/dom/DOMException.h"
28 #include "mozilla/dom/DOMExceptionBinding.h"
29 #include "mozilla/dom/BindingUtils.h"
30 #include "mozilla/dom/StructuredCloneTags.h"
31 #include "mozilla/dom/WindowBinding.h"
32 #include "mozilla/Scheduler.h"
33 #include "nsZipArchive.h"
34 #include "nsIDOMFileList.h"
35 #include "nsWindowMemoryReporter.h"
36 #include "nsDOMClassInfo.h"
37 #include "ShimInterfaceInfo.h"
38 #include "nsIException.h"
39 #include "nsIScriptError.h"
40 #include "nsISimpleEnumerator.h"
41 #include "nsPIDOMWindow.h"
42 #include "nsGlobalWindow.h"
43 #include "nsScriptError.h"
44 #include "GeckoProfiler.h"
45 
46 using namespace mozilla;
47 using namespace JS;
48 using namespace js;
49 using namespace xpc;
50 using mozilla::dom::Exception;
51 
52 /***************************************************************************/
53 // stuff used by all
54 
ThrowAndFail(nsresult errNum,JSContext * cx,bool * retval)55 nsresult xpc::ThrowAndFail(nsresult errNum, JSContext* cx, bool* retval) {
56   XPCThrower::Throw(errNum, cx);
57   *retval = false;
58   return NS_OK;
59 }
60 
JSValIsInterfaceOfType(JSContext * cx,HandleValue v,REFNSIID iid)61 static bool JSValIsInterfaceOfType(JSContext* cx, HandleValue v, REFNSIID iid) {
62   nsCOMPtr<nsIXPConnectWrappedNative> wn;
63   nsCOMPtr<nsISupports> iface;
64 
65   if (v.isPrimitive()) return false;
66 
67   nsXPConnect* xpc = nsXPConnect::XPConnect();
68   RootedObject obj(cx, &v.toObject());
69   return NS_SUCCEEDED(
70              xpc->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wn))) &&
71          wn &&
72          NS_SUCCEEDED(
73              wn->Native()->QueryInterface(iid, getter_AddRefs(iface))) &&
74          iface;
75 }
76 
CloneAllAccess()77 char* xpc::CloneAllAccess() { return moz_xstrdup("AllAccess"); }
78 
CheckAccessList(const char16_t * wideName,const char * const list[])79 char* xpc::CheckAccessList(const char16_t* wideName, const char* const list[]) {
80   nsAutoCString asciiName;
81   CopyUTF16toUTF8(nsDependentString(wideName), asciiName);
82 
83   for (const char* const* p = list; *p; p++)
84     if (!strcmp(*p, asciiName.get())) return CloneAllAccess();
85 
86   return nullptr;
87 }
88 
89 /***************************************************************************/
90 /***************************************************************************/
91 /***************************************************************************/
92 
93 class nsXPCComponents_Interfaces final : public nsIXPCComponents_Interfaces,
94                                          public nsIXPCScriptable,
95                                          public nsIClassInfo {
96  public:
97   // all the interface method declarations...
98   NS_DECL_ISUPPORTS
99   NS_DECL_NSIXPCCOMPONENTS_INTERFACES
100   NS_DECL_NSIXPCSCRIPTABLE
101   NS_DECL_NSICLASSINFO
102 
103  public:
104   nsXPCComponents_Interfaces();
105 
106  private:
107   virtual ~nsXPCComponents_Interfaces();
108 
109   nsCOMArray<nsIInterfaceInfo> mInterfaces;
110 };
111 
112 NS_IMETHODIMP
GetInterfaces(uint32_t * aCount,nsIID *** aArray)113 nsXPCComponents_Interfaces::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
114   *aCount = 2;
115   nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
116   *aArray = array;
117 
118   array[0] = NS_GET_IID(nsIXPCComponents_Interfaces).Clone();
119   array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
120   return NS_OK;
121 }
122 
123 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)124 nsXPCComponents_Interfaces::GetScriptableHelper(nsIXPCScriptable** retval) {
125   *retval = nullptr;
126   return NS_OK;
127 }
128 
129 NS_IMETHODIMP
GetContractID(nsACString & aContractID)130 nsXPCComponents_Interfaces::GetContractID(nsACString& aContractID) {
131   aContractID.SetIsVoid(true);
132   return NS_ERROR_NOT_AVAILABLE;
133 }
134 
135 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)136 nsXPCComponents_Interfaces::GetClassDescription(nsACString& aClassDescription) {
137   aClassDescription.AssignLiteral("XPCComponents_Interfaces");
138   return NS_OK;
139 }
140 
141 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)142 nsXPCComponents_Interfaces::GetClassID(nsCID** aClassID) {
143   *aClassID = nullptr;
144   return NS_OK;
145 }
146 
147 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)148 nsXPCComponents_Interfaces::GetFlags(uint32_t* aFlags) {
149   // Mark ourselves as a DOM object so that instances may be created in
150   // unprivileged scopes.
151   *aFlags = nsIClassInfo::DOM_OBJECT;
152   return NS_OK;
153 }
154 
155 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)156 nsXPCComponents_Interfaces::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
157   return NS_ERROR_NOT_AVAILABLE;
158 }
159 
nsXPCComponents_Interfaces()160 nsXPCComponents_Interfaces::nsXPCComponents_Interfaces() {}
161 
~nsXPCComponents_Interfaces()162 nsXPCComponents_Interfaces::~nsXPCComponents_Interfaces() {
163   // empty
164 }
165 
166 NS_IMPL_ISUPPORTS(nsXPCComponents_Interfaces, nsIXPCComponents_Interfaces,
167                   nsIXPCScriptable, nsIClassInfo);
168 
169 // The nsIXPCScriptable map declaration that will generate stubs for us...
170 #define XPC_MAP_CLASSNAME nsXPCComponents_Interfaces
171 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Interfaces"
172 #define XPC_MAP_FLAGS                                               \
173   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
174    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
175 #include "xpc_map_end.h" /* This will #undef the above */
176 
177 NS_IMETHODIMP
NewEnumerate(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * obj,JS::AutoIdVector & properties,bool * _retval)178 nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
179                                          JSContext* cx, JSObject* obj,
180                                          JS::AutoIdVector& properties,
181                                          bool* _retval) {
182   // Lazily init the list of interfaces when someone tries to
183   // enumerate them.
184   if (mInterfaces.IsEmpty()) {
185     XPTInterfaceInfoManager::GetSingleton()->GetScriptableInterfaces(
186         mInterfaces);
187   }
188 
189   if (!properties.reserve(mInterfaces.Length())) {
190     *_retval = false;
191     return NS_OK;
192   }
193 
194   for (uint32_t index = 0; index < mInterfaces.Length(); index++) {
195     nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(index);
196     if (!interface) continue;
197 
198     const char* name;
199     if (NS_SUCCEEDED(interface->GetNameShared(&name)) && name) {
200       RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
201       if (!idstr) {
202         *_retval = false;
203         return NS_OK;
204       }
205 
206       RootedId id(cx);
207       if (!JS_StringToId(cx, idstr, &id)) {
208         *_retval = false;
209         return NS_OK;
210       }
211 
212       properties.infallibleAppend(id);
213     }
214   }
215 
216   return NS_OK;
217 }
218 
219 NS_IMETHODIMP
Resolve(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,jsid idArg,bool * resolvedp,bool * _retval)220 nsXPCComponents_Interfaces::Resolve(nsIXPConnectWrappedNative* wrapper,
221                                     JSContext* cx, JSObject* objArg, jsid idArg,
222                                     bool* resolvedp, bool* _retval) {
223   RootedObject obj(cx, objArg);
224   RootedId id(cx, idArg);
225 
226   if (!JSID_IS_STRING(id)) return NS_OK;
227 
228   JSAutoByteString name;
229   RootedString str(cx, JSID_TO_STRING(id));
230 
231   // we only allow interfaces by name here
232   if (name.encodeLatin1(cx, str) && name.ptr()[0] != '{') {
233     nsCOMPtr<nsIInterfaceInfo> info =
234         ShimInterfaceInfo::MaybeConstruct(name.ptr(), cx);
235     if (!info) {
236       XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(
237           name.ptr(), getter_AddRefs(info));
238     }
239     if (!info) return NS_OK;
240 
241     nsCOMPtr<nsIJSIID> nsid = nsJSIID::NewID(info);
242 
243     if (nsid) {
244       nsXPConnect* xpc = nsXPConnect::XPConnect();
245       RootedObject idobj(cx);
246       if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, static_cast<nsIJSIID*>(nsid),
247                                        NS_GET_IID(nsIJSIID),
248                                        idobj.address()))) {
249         if (idobj) {
250           *resolvedp = true;
251           *_retval =
252               JS_DefinePropertyById(cx, obj, id, idobj,
253                                     JSPROP_ENUMERATE | JSPROP_READONLY |
254                                         JSPROP_PERMANENT | JSPROP_RESOLVING);
255         }
256       }
257     }
258   }
259   return NS_OK;
260 }
261 
262 /***************************************************************************/
263 /***************************************************************************/
264 /***************************************************************************/
265 
266 class nsXPCComponents_InterfacesByID final
267     : public nsIXPCComponents_InterfacesByID,
268       public nsIXPCScriptable,
269       public nsIClassInfo {
270  public:
271   // all the interface method declarations...
272   NS_DECL_ISUPPORTS
273   NS_DECL_NSIXPCCOMPONENTS_INTERFACESBYID
274   NS_DECL_NSIXPCSCRIPTABLE
275   NS_DECL_NSICLASSINFO
276 
277  public:
278   nsXPCComponents_InterfacesByID();
279 
280  private:
281   virtual ~nsXPCComponents_InterfacesByID();
282 
283   nsCOMArray<nsIInterfaceInfo> mInterfaces;
284 };
285 
286 /***************************************************************************/
287 NS_IMETHODIMP
GetInterfaces(uint32_t * aCount,nsIID *** aArray)288 nsXPCComponents_InterfacesByID::GetInterfaces(uint32_t* aCount,
289                                               nsIID*** aArray) {
290   *aCount = 2;
291   nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
292   *aArray = array;
293 
294   array[0] = NS_GET_IID(nsIXPCComponents_InterfacesByID).Clone();
295   array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
296   return NS_OK;
297 }
298 
299 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)300 nsXPCComponents_InterfacesByID::GetScriptableHelper(nsIXPCScriptable** retval) {
301   *retval = nullptr;
302   return NS_OK;
303 }
304 
305 NS_IMETHODIMP
GetContractID(nsACString & aContractID)306 nsXPCComponents_InterfacesByID::GetContractID(nsACString& aContractID) {
307   aContractID.SetIsVoid(true);
308   return NS_ERROR_NOT_AVAILABLE;
309 }
310 
311 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)312 nsXPCComponents_InterfacesByID::GetClassDescription(
313     nsACString& aClassDescription) {
314   aClassDescription.AssignLiteral("XPCComponents_InterfacesByID");
315   return NS_OK;
316 }
317 
318 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)319 nsXPCComponents_InterfacesByID::GetClassID(nsCID** aClassID) {
320   *aClassID = nullptr;
321   return NS_OK;
322 }
323 
324 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)325 nsXPCComponents_InterfacesByID::GetFlags(uint32_t* aFlags) {
326   // Mark ourselves as a DOM object so that instances may be created in
327   // unprivileged scopes.
328   *aFlags = nsIClassInfo::DOM_OBJECT;
329   return NS_OK;
330 }
331 
332 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)333 nsXPCComponents_InterfacesByID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
334   return NS_ERROR_NOT_AVAILABLE;
335 }
336 
nsXPCComponents_InterfacesByID()337 nsXPCComponents_InterfacesByID::nsXPCComponents_InterfacesByID() {}
338 
~nsXPCComponents_InterfacesByID()339 nsXPCComponents_InterfacesByID::~nsXPCComponents_InterfacesByID() {
340   // empty
341 }
342 
NS_IMPL_ISUPPORTS(nsXPCComponents_InterfacesByID,nsIXPCComponents_InterfacesByID,nsIXPCScriptable,nsIClassInfo)343 NS_IMPL_ISUPPORTS(nsXPCComponents_InterfacesByID,
344                   nsIXPCComponents_InterfacesByID, nsIXPCScriptable,
345                   nsIClassInfo)
346 
347 // The nsIXPCScriptable map declaration that will generate stubs for us...
348 #define XPC_MAP_CLASSNAME nsXPCComponents_InterfacesByID
349 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_InterfacesByID"
350 #define XPC_MAP_FLAGS                                               \
351   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
352    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
353 #include "xpc_map_end.h" /* This will #undef the above */
354 
355 NS_IMETHODIMP
356 nsXPCComponents_InterfacesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
357                                              JSContext* cx, JSObject* obj,
358                                              JS::AutoIdVector& properties,
359                                              bool* _retval) {
360   if (mInterfaces.IsEmpty()) {
361     XPTInterfaceInfoManager::GetSingleton()->GetScriptableInterfaces(
362         mInterfaces);
363   }
364 
365   if (!properties.reserve(mInterfaces.Length())) {
366     *_retval = false;
367     return NS_OK;
368   }
369 
370   for (uint32_t index = 0; index < mInterfaces.Length(); index++) {
371     nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(index);
372     if (!interface) continue;
373 
374     nsIID const* iid;
375     if (NS_SUCCEEDED(interface->GetIIDShared(&iid))) {
376       char idstr[NSID_LENGTH];
377       iid->ToProvidedString(idstr);
378       RootedString jsstr(cx, JS_NewStringCopyZ(cx, idstr));
379       if (!jsstr) {
380         *_retval = false;
381         return NS_OK;
382       }
383 
384       RootedId id(cx);
385       if (!JS_StringToId(cx, jsstr, &id)) {
386         *_retval = false;
387         return NS_OK;
388       }
389 
390       properties.infallibleAppend(id);
391     }
392   }
393 
394   return NS_OK;
395 }
396 
397 NS_IMETHODIMP
Resolve(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,jsid idArg,bool * resolvedp,bool * _retval)398 nsXPCComponents_InterfacesByID::Resolve(nsIXPConnectWrappedNative* wrapper,
399                                         JSContext* cx, JSObject* objArg,
400                                         jsid idArg, bool* resolvedp,
401                                         bool* _retval) {
402   RootedObject obj(cx, objArg);
403   RootedId id(cx, idArg);
404 
405   if (!JSID_IS_STRING(id)) return NS_OK;
406 
407   RootedString str(cx, JSID_TO_STRING(id));
408   if (38 != JS_GetStringLength(str)) return NS_OK;
409 
410   JSAutoByteString utf8str;
411   if (utf8str.encodeUtf8(cx, str)) {
412     nsID iid;
413     if (!iid.Parse(utf8str.ptr())) return NS_OK;
414 
415     nsCOMPtr<nsIInterfaceInfo> info;
416     XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(
417         &iid, getter_AddRefs(info));
418     if (!info) return NS_OK;
419 
420     nsCOMPtr<nsIJSIID> nsid = nsJSIID::NewID(info);
421 
422     if (!nsid) return NS_ERROR_OUT_OF_MEMORY;
423 
424     nsXPConnect* xpc = nsXPConnect::XPConnect();
425     RootedObject idobj(cx);
426     if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, static_cast<nsIJSIID*>(nsid),
427                                      NS_GET_IID(nsIJSIID), idobj.address()))) {
428       if (idobj) {
429         *resolvedp = true;
430         *_retval =
431             JS_DefinePropertyById(cx, obj, id, idobj,
432                                   JSPROP_ENUMERATE | JSPROP_READONLY |
433                                       JSPROP_PERMANENT | JSPROP_RESOLVING);
434       }
435     }
436   }
437   return NS_OK;
438 }
439 
440 /***************************************************************************/
441 /***************************************************************************/
442 /***************************************************************************/
443 
444 class nsXPCComponents_Classes final : public nsIXPCComponents_Classes,
445                                       public nsIXPCScriptable,
446                                       public nsIClassInfo {
447  public:
448   // all the interface method declarations...
449   NS_DECL_ISUPPORTS
450   NS_DECL_NSIXPCCOMPONENTS_CLASSES
451   NS_DECL_NSIXPCSCRIPTABLE
452   NS_DECL_NSICLASSINFO
453 
454  public:
455   nsXPCComponents_Classes();
456 
457  private:
458   virtual ~nsXPCComponents_Classes();
459 };
460 
461 /***************************************************************************/
462 NS_IMETHODIMP
GetInterfaces(uint32_t * aCount,nsIID *** aArray)463 nsXPCComponents_Classes::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
464   *aCount = 2;
465   nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
466   *aArray = array;
467 
468   array[0] = NS_GET_IID(nsIXPCComponents_Classes).Clone();
469   array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
470   return NS_OK;
471 }
472 
473 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)474 nsXPCComponents_Classes::GetScriptableHelper(nsIXPCScriptable** retval) {
475   *retval = nullptr;
476   return NS_OK;
477 }
478 
479 NS_IMETHODIMP
GetContractID(nsACString & aContractID)480 nsXPCComponents_Classes::GetContractID(nsACString& aContractID) {
481   aContractID.SetIsVoid(true);
482   return NS_ERROR_NOT_AVAILABLE;
483 }
484 
485 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)486 nsXPCComponents_Classes::GetClassDescription(nsACString& aClassDescription) {
487   aClassDescription.AssignLiteral("XPCComponents_Classes");
488   return NS_OK;
489 }
490 
491 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)492 nsXPCComponents_Classes::GetClassID(nsCID** aClassID) {
493   *aClassID = nullptr;
494   return NS_OK;
495 }
496 
497 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)498 nsXPCComponents_Classes::GetFlags(uint32_t* aFlags) {
499   *aFlags = 0;
500   return NS_OK;
501 }
502 
503 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)504 nsXPCComponents_Classes::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
505   return NS_ERROR_NOT_AVAILABLE;
506 }
507 
nsXPCComponents_Classes()508 nsXPCComponents_Classes::nsXPCComponents_Classes() {}
509 
~nsXPCComponents_Classes()510 nsXPCComponents_Classes::~nsXPCComponents_Classes() {
511   // empty
512 }
513 
NS_IMPL_ISUPPORTS(nsXPCComponents_Classes,nsIXPCComponents_Classes,nsIXPCScriptable,nsIClassInfo)514 NS_IMPL_ISUPPORTS(nsXPCComponents_Classes, nsIXPCComponents_Classes,
515                   nsIXPCScriptable, nsIClassInfo)
516 
517 // The nsIXPCScriptable map declaration that will generate stubs for us...
518 #define XPC_MAP_CLASSNAME nsXPCComponents_Classes
519 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Classes"
520 #define XPC_MAP_FLAGS                                               \
521   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
522    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
523 #include "xpc_map_end.h" /* This will #undef the above */
524 
525 NS_IMETHODIMP
526 nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
527                                       JSContext* cx, JSObject* obj,
528                                       JS::AutoIdVector& properties,
529                                       bool* _retval) {
530   nsCOMPtr<nsIComponentRegistrar> compMgr;
531   if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr)
532     return NS_ERROR_UNEXPECTED;
533 
534   nsCOMPtr<nsISimpleEnumerator> e;
535   if (NS_FAILED(compMgr->EnumerateContractIDs(getter_AddRefs(e))) || !e)
536     return NS_ERROR_UNEXPECTED;
537 
538   bool hasMore;
539   nsCOMPtr<nsISupports> isup;
540   while (NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore &&
541          NS_SUCCEEDED(e->GetNext(getter_AddRefs(isup))) && isup) {
542     nsCOMPtr<nsISupportsCString> holder(do_QueryInterface(isup));
543     if (!holder) continue;
544 
545     nsAutoCString name;
546     if (NS_SUCCEEDED(holder->GetData(name))) {
547       RootedString idstr(cx, JS_NewStringCopyN(cx, name.get(), name.Length()));
548       if (!idstr) {
549         *_retval = false;
550         return NS_OK;
551       }
552 
553       RootedId id(cx);
554       if (!JS_StringToId(cx, idstr, &id)) {
555         *_retval = false;
556         return NS_OK;
557       }
558 
559       if (!properties.append(id)) {
560         *_retval = false;
561         return NS_OK;
562       }
563     }
564   }
565 
566   return NS_OK;
567 }
568 
569 NS_IMETHODIMP
Resolve(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,jsid idArg,bool * resolvedp,bool * _retval)570 nsXPCComponents_Classes::Resolve(nsIXPConnectWrappedNative* wrapper,
571                                  JSContext* cx, JSObject* objArg, jsid idArg,
572                                  bool* resolvedp, bool* _retval)
573 
574 {
575   RootedId id(cx, idArg);
576   RootedObject obj(cx, objArg);
577 
578   JSAutoByteString name;
579   if (JSID_IS_STRING(id) && name.encodeLatin1(cx, JSID_TO_STRING(id)) &&
580       name.ptr()[0] != '{') {  // we only allow contractids here
581     nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.ptr());
582     if (nsid) {
583       nsXPConnect* xpc = nsXPConnect::XPConnect();
584       RootedObject idobj(cx);
585       if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, static_cast<nsIJSCID*>(nsid),
586                                        NS_GET_IID(nsIJSCID),
587                                        idobj.address()))) {
588         if (idobj) {
589           *resolvedp = true;
590           *_retval =
591               JS_DefinePropertyById(cx, obj, id, idobj,
592                                     JSPROP_ENUMERATE | JSPROP_READONLY |
593                                         JSPROP_PERMANENT | JSPROP_RESOLVING);
594         }
595       }
596     }
597   }
598   return NS_OK;
599 }
600 
601 NS_IMETHODIMP
Initialize(nsIJSCID * cid,const char * str)602 nsXPCComponents_Classes::Initialize(nsIJSCID* cid, const char* str) {
603   return cid->Initialize(str);
604 }
605 
606 /***************************************************************************/
607 /***************************************************************************/
608 /***************************************************************************/
609 
610 class nsXPCComponents_ClassesByID final : public nsIXPCComponents_ClassesByID,
611                                           public nsIXPCScriptable,
612                                           public nsIClassInfo {
613  public:
614   // all the interface method declarations...
615   NS_DECL_ISUPPORTS
616   NS_DECL_NSIXPCCOMPONENTS_CLASSESBYID
617   NS_DECL_NSIXPCSCRIPTABLE
618   NS_DECL_NSICLASSINFO
619 
620  public:
621   nsXPCComponents_ClassesByID();
622 
623  private:
624   virtual ~nsXPCComponents_ClassesByID();
625 };
626 
627 /***************************************************************************/
628 NS_IMETHODIMP
GetInterfaces(uint32_t * aCount,nsIID *** aArray)629 nsXPCComponents_ClassesByID::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
630   *aCount = 2;
631   nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
632   *aArray = array;
633 
634   array[0] = NS_GET_IID(nsIXPCComponents_ClassesByID).Clone();
635   array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
636   return NS_OK;
637 }
638 
639 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)640 nsXPCComponents_ClassesByID::GetScriptableHelper(nsIXPCScriptable** retval) {
641   *retval = nullptr;
642   return NS_OK;
643 }
644 
645 NS_IMETHODIMP
GetContractID(nsACString & aContractID)646 nsXPCComponents_ClassesByID::GetContractID(nsACString& aContractID) {
647   aContractID.SetIsVoid(true);
648   return NS_ERROR_NOT_AVAILABLE;
649 }
650 
651 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)652 nsXPCComponents_ClassesByID::GetClassDescription(
653     nsACString& aClassDescription) {
654   aClassDescription.AssignLiteral("XPCComponents_ClassesByID");
655   return NS_OK;
656 }
657 
658 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)659 nsXPCComponents_ClassesByID::GetClassID(nsCID** aClassID) {
660   *aClassID = nullptr;
661   return NS_OK;
662 }
663 
664 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)665 nsXPCComponents_ClassesByID::GetFlags(uint32_t* aFlags) {
666   *aFlags = 0;
667   return NS_OK;
668 }
669 
670 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)671 nsXPCComponents_ClassesByID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
672   return NS_ERROR_NOT_AVAILABLE;
673 }
674 
nsXPCComponents_ClassesByID()675 nsXPCComponents_ClassesByID::nsXPCComponents_ClassesByID() {}
676 
~nsXPCComponents_ClassesByID()677 nsXPCComponents_ClassesByID::~nsXPCComponents_ClassesByID() {
678   // empty
679 }
680 
NS_IMPL_ISUPPORTS(nsXPCComponents_ClassesByID,nsIXPCComponents_ClassesByID,nsIXPCScriptable,nsIClassInfo)681 NS_IMPL_ISUPPORTS(nsXPCComponents_ClassesByID, nsIXPCComponents_ClassesByID,
682                   nsIXPCScriptable, nsIClassInfo)
683 
684 // The nsIXPCScriptable map declaration that will generate stubs for us...
685 #define XPC_MAP_CLASSNAME nsXPCComponents_ClassesByID
686 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_ClassesByID"
687 #define XPC_MAP_FLAGS                                               \
688   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
689    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
690 #include "xpc_map_end.h" /* This will #undef the above */
691 
692 NS_IMETHODIMP
693 nsXPCComponents_ClassesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
694                                           JSContext* cx, JSObject* obj,
695                                           JS::AutoIdVector& properties,
696                                           bool* _retval) {
697   nsCOMPtr<nsIComponentRegistrar> compMgr;
698   if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr)
699     return NS_ERROR_UNEXPECTED;
700 
701   nsISimpleEnumerator* e;
702   if (NS_FAILED(compMgr->EnumerateCIDs(&e)) || !e) return NS_ERROR_UNEXPECTED;
703 
704   bool hasMore;
705   nsCOMPtr<nsISupports> isup;
706   while (NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore &&
707          NS_SUCCEEDED(e->GetNext(getter_AddRefs(isup))) && isup) {
708     nsCOMPtr<nsISupportsID> holder(do_QueryInterface(isup));
709     if (!holder) continue;
710 
711     char* name;
712     if (NS_SUCCEEDED(holder->ToString(&name)) && name) {
713       RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
714       if (!idstr) {
715         *_retval = false;
716         return NS_OK;
717       }
718 
719       RootedId id(cx);
720       if (!JS_StringToId(cx, idstr, &id)) {
721         *_retval = false;
722         return NS_OK;
723       }
724 
725       if (!properties.append(id)) {
726         *_retval = false;
727         return NS_OK;
728       }
729     }
730   }
731 
732   return NS_OK;
733 }
734 
IsRegisteredCLSID(const char * str)735 static bool IsRegisteredCLSID(const char* str) {
736   bool registered;
737   nsID id;
738 
739   if (!id.Parse(str)) return false;
740 
741   nsCOMPtr<nsIComponentRegistrar> compMgr;
742   if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) ||
743       !compMgr || NS_FAILED(compMgr->IsCIDRegistered(id, &registered)))
744     return false;
745 
746   return registered;
747 }
748 
749 NS_IMETHODIMP
Resolve(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,jsid idArg,bool * resolvedp,bool * _retval)750 nsXPCComponents_ClassesByID::Resolve(nsIXPConnectWrappedNative* wrapper,
751                                      JSContext* cx, JSObject* objArg,
752                                      jsid idArg, bool* resolvedp,
753                                      bool* _retval) {
754   RootedObject obj(cx, objArg);
755   RootedId id(cx, idArg);
756 
757   if (!JSID_IS_STRING(id)) return NS_OK;
758 
759   JSAutoByteString name;
760   RootedString str(cx, JSID_TO_STRING(id));
761   if (name.encodeLatin1(cx, str) && name.ptr()[0] == '{' &&
762       IsRegisteredCLSID(name.ptr()))  // we only allow canonical CLSIDs here
763   {
764     nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.ptr());
765     if (nsid) {
766       nsXPConnect* xpc = nsXPConnect::XPConnect();
767       RootedObject idobj(cx);
768       if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, static_cast<nsIJSCID*>(nsid),
769                                        NS_GET_IID(nsIJSCID),
770                                        idobj.address()))) {
771         if (idobj) {
772           *resolvedp = true;
773           *_retval =
774               JS_DefinePropertyById(cx, obj, id, idobj,
775                                     JSPROP_ENUMERATE | JSPROP_READONLY |
776                                         JSPROP_PERMANENT | JSPROP_RESOLVING);
777         }
778       }
779     }
780   }
781   return NS_OK;
782 }
783 
784 /***************************************************************************/
785 
786 // Currently the possible results do not change at runtime, so they are only
787 // cached once (unlike ContractIDs, CLSIDs, and IIDs)
788 
789 class nsXPCComponents_Results final : public nsIXPCComponents_Results,
790                                       public nsIXPCScriptable,
791                                       public nsIClassInfo {
792  public:
793   // all the interface method declarations...
794   NS_DECL_ISUPPORTS
795   NS_DECL_NSIXPCCOMPONENTS_RESULTS
796   NS_DECL_NSIXPCSCRIPTABLE
797   NS_DECL_NSICLASSINFO
798 
799  public:
800   nsXPCComponents_Results();
801 
802  private:
803   virtual ~nsXPCComponents_Results();
804 };
805 
806 /***************************************************************************/
807 NS_IMETHODIMP
GetInterfaces(uint32_t * aCount,nsIID *** aArray)808 nsXPCComponents_Results::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
809   *aCount = 2;
810   nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
811   *aArray = array;
812 
813   array[0] = NS_GET_IID(nsIXPCComponents_Results).Clone();
814   array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
815   return NS_OK;
816 }
817 
818 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)819 nsXPCComponents_Results::GetScriptableHelper(nsIXPCScriptable** retval) {
820   *retval = nullptr;
821   return NS_OK;
822 }
823 
824 NS_IMETHODIMP
GetContractID(nsACString & aContractID)825 nsXPCComponents_Results::GetContractID(nsACString& aContractID) {
826   aContractID.SetIsVoid(true);
827   return NS_ERROR_NOT_AVAILABLE;
828 }
829 
830 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)831 nsXPCComponents_Results::GetClassDescription(nsACString& aClassDescription) {
832   aClassDescription.AssignLiteral("XPCComponents_Results");
833   return NS_OK;
834 }
835 
836 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)837 nsXPCComponents_Results::GetClassID(nsCID** aClassID) {
838   *aClassID = nullptr;
839   return NS_OK;
840 }
841 
842 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)843 nsXPCComponents_Results::GetFlags(uint32_t* aFlags) {
844   // Mark ourselves as a DOM object so that instances may be created in
845   // unprivileged scopes.
846   *aFlags = nsIClassInfo::DOM_OBJECT;
847   return NS_OK;
848 }
849 
850 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)851 nsXPCComponents_Results::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
852   return NS_ERROR_NOT_AVAILABLE;
853 }
854 
nsXPCComponents_Results()855 nsXPCComponents_Results::nsXPCComponents_Results() {}
856 
~nsXPCComponents_Results()857 nsXPCComponents_Results::~nsXPCComponents_Results() {
858   // empty
859 }
860 
NS_IMPL_ISUPPORTS(nsXPCComponents_Results,nsIXPCComponents_Results,nsIXPCScriptable,nsIClassInfo)861 NS_IMPL_ISUPPORTS(nsXPCComponents_Results, nsIXPCComponents_Results,
862                   nsIXPCScriptable, nsIClassInfo)
863 
864 // The nsIXPCScriptable map declaration that will generate stubs for us...
865 #define XPC_MAP_CLASSNAME nsXPCComponents_Results
866 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Results"
867 #define XPC_MAP_FLAGS                                               \
868   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_WANT_NEWENUMERATE | \
869    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
870 #include "xpc_map_end.h" /* This will #undef the above */
871 
872 NS_IMETHODIMP
873 nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative* wrapper,
874                                       JSContext* cx, JSObject* obj,
875                                       JS::AutoIdVector& properties,
876                                       bool* _retval) {
877   const char* name;
878   const void* iter = nullptr;
879   while (nsXPCException::IterateNSResults(nullptr, &name, nullptr, &iter)) {
880     RootedString idstr(cx, JS_NewStringCopyZ(cx, name));
881     if (!idstr) {
882       *_retval = false;
883       return NS_OK;
884     }
885 
886     RootedId id(cx);
887     if (!JS_StringToId(cx, idstr, &id)) {
888       *_retval = false;
889       return NS_OK;
890     }
891 
892     if (!properties.append(id)) {
893       *_retval = false;
894       return NS_OK;
895     }
896   }
897 
898   return NS_OK;
899 }
900 
901 NS_IMETHODIMP
Resolve(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,jsid idArg,bool * resolvedp,bool * _retval)902 nsXPCComponents_Results::Resolve(nsIXPConnectWrappedNative* wrapper,
903                                  JSContext* cx, JSObject* objArg, jsid idArg,
904                                  bool* resolvedp, bool* _retval) {
905   RootedObject obj(cx, objArg);
906   RootedId id(cx, idArg);
907   JSAutoByteString name;
908 
909   if (JSID_IS_STRING(id) && name.encodeLatin1(cx, JSID_TO_STRING(id))) {
910     const char* rv_name;
911     const void* iter = nullptr;
912     nsresult rv;
913     while (nsXPCException::IterateNSResults(&rv, &rv_name, nullptr, &iter)) {
914       if (!strcmp(name.ptr(), rv_name)) {
915         *resolvedp = true;
916         if (!JS_DefinePropertyById(cx, obj, id, (uint32_t)rv,
917                                    JSPROP_ENUMERATE | JSPROP_READONLY |
918                                        JSPROP_PERMANENT | JSPROP_RESOLVING)) {
919           return NS_ERROR_UNEXPECTED;
920         }
921       }
922     }
923   }
924   return NS_OK;
925 }
926 
927 /***************************************************************************/
928 // JavaScript Constructor for nsIJSID objects (Components.ID)
929 
930 class nsXPCComponents_ID final : public nsIXPCComponents_ID,
931                                  public nsIXPCScriptable,
932                                  public nsIClassInfo {
933  public:
934   // all the interface method declarations...
935   NS_DECL_ISUPPORTS
936   NS_DECL_NSIXPCCOMPONENTS_ID
937   NS_DECL_NSIXPCSCRIPTABLE
938   NS_DECL_NSICLASSINFO
939 
940  public:
941   nsXPCComponents_ID();
942 
943  private:
944   virtual ~nsXPCComponents_ID();
945   static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
946                                   JSContext* cx, HandleObject obj,
947                                   const CallArgs& args, bool* _retval);
948 };
949 
950 /***************************************************************************/
951 NS_IMETHODIMP
GetInterfaces(uint32_t * aCount,nsIID *** aArray)952 nsXPCComponents_ID::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
953   *aCount = 2;
954   nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
955   *aArray = array;
956 
957   array[0] = NS_GET_IID(nsIXPCComponents_ID).Clone();
958   array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
959   return NS_OK;
960 }
961 
962 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)963 nsXPCComponents_ID::GetScriptableHelper(nsIXPCScriptable** retval) {
964   *retval = nullptr;
965   return NS_OK;
966 }
967 
968 NS_IMETHODIMP
GetContractID(nsACString & aContractID)969 nsXPCComponents_ID::GetContractID(nsACString& aContractID) {
970   aContractID.SetIsVoid(true);
971   return NS_ERROR_NOT_AVAILABLE;
972 }
973 
974 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)975 nsXPCComponents_ID::GetClassDescription(nsACString& aClassDescription) {
976   aClassDescription.AssignLiteral("XPCComponents_ID");
977   return NS_OK;
978 }
979 
980 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)981 nsXPCComponents_ID::GetClassID(nsCID** aClassID) {
982   *aClassID = nullptr;
983   return NS_OK;
984 }
985 
986 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)987 nsXPCComponents_ID::GetFlags(uint32_t* aFlags) {
988   *aFlags = 0;
989   return NS_OK;
990 }
991 
992 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)993 nsXPCComponents_ID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
994   return NS_ERROR_NOT_AVAILABLE;
995 }
996 
nsXPCComponents_ID()997 nsXPCComponents_ID::nsXPCComponents_ID() {}
998 
~nsXPCComponents_ID()999 nsXPCComponents_ID::~nsXPCComponents_ID() {
1000   // empty
1001 }
1002 
NS_IMPL_ISUPPORTS(nsXPCComponents_ID,nsIXPCComponents_ID,nsIXPCScriptable,nsIClassInfo)1003 NS_IMPL_ISUPPORTS(nsXPCComponents_ID, nsIXPCComponents_ID, nsIXPCScriptable,
1004                   nsIClassInfo)
1005 
1006 // The nsIXPCScriptable map declaration that will generate stubs for us...
1007 #define XPC_MAP_CLASSNAME nsXPCComponents_ID
1008 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_ID"
1009 #define XPC_MAP_FLAGS                                         \
1010   (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT | \
1011    XPC_SCRIPTABLE_WANT_HASINSTANCE |                          \
1012    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
1013 #include "xpc_map_end.h" /* This will #undef the above */
1014 
1015 NS_IMETHODIMP
1016 nsXPCComponents_ID::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
1017                          JSObject* objArg, const CallArgs& args,
1018                          bool* _retval) {
1019   RootedObject obj(cx, objArg);
1020   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1021 }
1022 
1023 NS_IMETHODIMP
Construct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,const CallArgs & args,bool * _retval)1024 nsXPCComponents_ID::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
1025                               JSObject* objArg, const CallArgs& args,
1026                               bool* _retval) {
1027   RootedObject obj(cx, objArg);
1028   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1029 }
1030 
1031 // static
CallOrConstruct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,HandleObject obj,const CallArgs & args,bool * _retval)1032 nsresult nsXPCComponents_ID::CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
1033                                              JSContext* cx, HandleObject obj,
1034                                              const CallArgs& args,
1035                                              bool* _retval) {
1036   // make sure we have at least one arg
1037 
1038   if (args.length() < 1)
1039     return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval);
1040 
1041   // Do the security check if necessary
1042 
1043   if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(
1044           cx, nsJSID::GetCID()))) {
1045     // the security manager vetoed. It should have set an exception.
1046     *_retval = false;
1047     return NS_OK;
1048   }
1049 
1050   // convert the first argument into a string and see if it looks like an id
1051 
1052   JSString* jsstr;
1053   JSAutoByteString bytes;
1054   nsID id;
1055 
1056   if (!(jsstr = ToString(cx, args[0])) || !bytes.encodeLatin1(cx, jsstr) ||
1057       !id.Parse(bytes.ptr())) {
1058     return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
1059   }
1060 
1061   // make the new object and return it.
1062 
1063   JSObject* newobj = xpc_NewIDObject(cx, obj, id);
1064   if (!newobj) return NS_ERROR_UNEXPECTED;
1065 
1066   args.rval().setObject(*newobj);
1067   return NS_OK;
1068 }
1069 
1070 NS_IMETHODIMP
HasInstance(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * obj,HandleValue val,bool * bp,bool * _retval)1071 nsXPCComponents_ID::HasInstance(nsIXPConnectWrappedNative* wrapper,
1072                                 JSContext* cx, JSObject* obj, HandleValue val,
1073                                 bool* bp, bool* _retval) {
1074   if (bp) *bp = JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIJSID));
1075   return NS_OK;
1076 }
1077 
1078 /***************************************************************************/
1079 // JavaScript Constructor for Exception objects (Components.Exception)
1080 
1081 class nsXPCComponents_Exception final : public nsIXPCComponents_Exception,
1082                                         public nsIXPCScriptable,
1083                                         public nsIClassInfo {
1084  public:
1085   // all the interface method declarations...
1086   NS_DECL_ISUPPORTS
1087   NS_DECL_NSIXPCCOMPONENTS_EXCEPTION
1088   NS_DECL_NSIXPCSCRIPTABLE
1089   NS_DECL_NSICLASSINFO
1090 
1091  public:
1092   nsXPCComponents_Exception();
1093 
1094  private:
1095   virtual ~nsXPCComponents_Exception();
1096   static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
1097                                   JSContext* cx, HandleObject obj,
1098                                   const CallArgs& args, bool* _retval);
1099 };
1100 
1101 /***************************************************************************/
1102 NS_IMETHODIMP
GetInterfaces(uint32_t * aCount,nsIID *** aArray)1103 nsXPCComponents_Exception::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
1104   *aCount = 2;
1105   nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
1106   *aArray = array;
1107 
1108   array[0] = NS_GET_IID(nsIXPCComponents_Exception).Clone();
1109   array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
1110   return NS_OK;
1111 }
1112 
1113 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)1114 nsXPCComponents_Exception::GetScriptableHelper(nsIXPCScriptable** retval) {
1115   *retval = nullptr;
1116   return NS_OK;
1117 }
1118 
1119 NS_IMETHODIMP
GetContractID(nsACString & aContractID)1120 nsXPCComponents_Exception::GetContractID(nsACString& aContractID) {
1121   aContractID.SetIsVoid(true);
1122   return NS_ERROR_NOT_AVAILABLE;
1123 }
1124 
1125 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)1126 nsXPCComponents_Exception::GetClassDescription(nsACString& aClassDescription) {
1127   aClassDescription.AssignLiteral("XPCComponents_Exception");
1128   return NS_OK;
1129 }
1130 
1131 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)1132 nsXPCComponents_Exception::GetClassID(nsCID** aClassID) {
1133   *aClassID = nullptr;
1134   return NS_OK;
1135 }
1136 
1137 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)1138 nsXPCComponents_Exception::GetFlags(uint32_t* aFlags) {
1139   *aFlags = 0;
1140   return NS_OK;
1141 }
1142 
1143 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)1144 nsXPCComponents_Exception::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
1145   return NS_ERROR_NOT_AVAILABLE;
1146 }
1147 
nsXPCComponents_Exception()1148 nsXPCComponents_Exception::nsXPCComponents_Exception() {}
1149 
~nsXPCComponents_Exception()1150 nsXPCComponents_Exception::~nsXPCComponents_Exception() {
1151   // empty
1152 }
1153 
NS_IMPL_ISUPPORTS(nsXPCComponents_Exception,nsIXPCComponents_Exception,nsIXPCScriptable,nsIClassInfo)1154 NS_IMPL_ISUPPORTS(nsXPCComponents_Exception, nsIXPCComponents_Exception,
1155                   nsIXPCScriptable, nsIClassInfo)
1156 
1157 // The nsIXPCScriptable map declaration that will generate stubs for us...
1158 #define XPC_MAP_CLASSNAME nsXPCComponents_Exception
1159 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Exception"
1160 #define XPC_MAP_FLAGS                                         \
1161   (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT | \
1162    XPC_SCRIPTABLE_WANT_HASINSTANCE |                          \
1163    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
1164 #include "xpc_map_end.h" /* This will #undef the above */
1165 
1166 NS_IMETHODIMP
1167 nsXPCComponents_Exception::Call(nsIXPConnectWrappedNative* wrapper,
1168                                 JSContext* cx, JSObject* objArg,
1169                                 const CallArgs& args, bool* _retval) {
1170   RootedObject obj(cx, objArg);
1171   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1172 }
1173 
1174 NS_IMETHODIMP
Construct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,const CallArgs & args,bool * _retval)1175 nsXPCComponents_Exception::Construct(nsIXPConnectWrappedNative* wrapper,
1176                                      JSContext* cx, JSObject* objArg,
1177                                      const CallArgs& args, bool* _retval) {
1178   RootedObject obj(cx, objArg);
1179   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1180 }
1181 
1182 struct MOZ_STACK_CLASS ExceptionArgParser {
ExceptionArgParserExceptionArgParser1183   ExceptionArgParser(JSContext* context, nsXPConnect* xpconnect)
1184       : eMsg("exception"),
1185         eResult(NS_ERROR_FAILURE),
1186         cx(context),
1187         xpc(xpconnect) {}
1188 
1189   // Public exception parameter values. During construction, these are
1190   // initialized to the appropriate defaults.
1191   const char* eMsg;
1192   nsresult eResult;
1193   nsCOMPtr<nsIStackFrame> eStack;
1194   nsCOMPtr<nsISupports> eData;
1195 
1196   // Parse the constructor arguments into the above |eFoo| parameter values.
parseExceptionArgParser1197   bool parse(const CallArgs& args) {
1198     /*
1199      * The Components.Exception takes a series of arguments, all of them
1200      * optional:
1201      *
1202      * Argument 0: Exception message (defaults to 'exception').
1203      * Argument 1: Result code (defaults to NS_ERROR_FAILURE) _or_ options
1204      *             object (see below).
1205      * Argument 2: Stack (defaults to the current stack, which we trigger
1206      *                    by leaving this nullptr in the parser).
1207      * Argument 3: Optional user data (defaults to nullptr).
1208      *
1209      * To dig our way out of this clunky API, we now support passing an
1210      * options object as the second parameter (as opposed to a result code).
1211      * If this is the case, all subsequent arguments are ignored, and the
1212      * following properties are parsed out of the object (using the
1213      * associated default if the property does not exist):
1214      *
1215      *   result:    Result code (see argument 1).
1216      *   stack:     Call stack (see argument 2).
1217      *   data:      User data (see argument 3).
1218      */
1219     if (args.length() > 0 && !parseMessage(args[0])) return false;
1220     if (args.length() > 1) {
1221       if (args[1].isObject()) {
1222         RootedObject obj(cx, &args[1].toObject());
1223         return parseOptionsObject(obj);
1224       }
1225       if (!parseResult(args[1])) return false;
1226     }
1227     if (args.length() > 2) {
1228       if (!parseStack(args[2])) return false;
1229     }
1230     if (args.length() > 3) {
1231       if (!parseData(args[3])) return false;
1232     }
1233     return true;
1234   }
1235 
1236  protected:
1237   /*
1238    * Parsing helpers.
1239    */
1240 
parseMessageExceptionArgParser1241   bool parseMessage(HandleValue v) {
1242     JSString* str = ToString(cx, v);
1243     if (!str) return false;
1244     eMsg = messageBytes.encodeLatin1(cx, str);
1245     return !!eMsg;
1246   }
1247 
parseResultExceptionArgParser1248   bool parseResult(HandleValue v) {
1249     return JS::ToUint32(cx, v, (uint32_t*)&eResult);
1250   }
1251 
parseStackExceptionArgParser1252   bool parseStack(HandleValue v) {
1253     if (!v.isObject()) {
1254       // eStack has already been initialized to null, which is what we want
1255       // for any non-object values (including null).
1256       return true;
1257     }
1258 
1259     return NS_SUCCEEDED(xpc->WrapJS(
1260         cx, &v.toObject(), NS_GET_IID(nsIStackFrame), getter_AddRefs(eStack)));
1261   }
1262 
parseDataExceptionArgParser1263   bool parseData(HandleValue v) {
1264     if (!v.isObject()) {
1265       // eData has already been initialized to null, which is what we want
1266       // for any non-object values (including null).
1267       return true;
1268     }
1269 
1270     return NS_SUCCEEDED(xpc->WrapJS(cx, &v.toObject(), NS_GET_IID(nsISupports),
1271                                     getter_AddRefs(eData)));
1272   }
1273 
parseOptionsObjectExceptionArgParser1274   bool parseOptionsObject(HandleObject obj) {
1275     RootedValue v(cx);
1276 
1277     if (!getOption(obj, "result", &v) || (!v.isUndefined() && !parseResult(v)))
1278       return false;
1279 
1280     if (!getOption(obj, "stack", &v) || (!v.isUndefined() && !parseStack(v)))
1281       return false;
1282 
1283     if (!getOption(obj, "data", &v) || (!v.isUndefined() && !parseData(v)))
1284       return false;
1285 
1286     return true;
1287   }
1288 
getOptionExceptionArgParser1289   bool getOption(HandleObject obj, const char* name, MutableHandleValue rv) {
1290     // Look for the property.
1291     bool found;
1292     if (!JS_HasProperty(cx, obj, name, &found)) return false;
1293 
1294     // If it wasn't found, indicate with undefined.
1295     if (!found) {
1296       rv.setUndefined();
1297       return true;
1298     }
1299 
1300     // Get the property.
1301     return JS_GetProperty(cx, obj, name, rv);
1302   }
1303 
1304   /*
1305    * Internal data members.
1306    */
1307 
1308   // If there's a non-default exception string, hold onto the allocated bytes.
1309   JSAutoByteString messageBytes;
1310 
1311   // Various bits and pieces that are helpful to have around.
1312   JSContext* cx;
1313   nsXPConnect* xpc;
1314 };
1315 
1316 // static
CallOrConstruct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,HandleObject obj,const CallArgs & args,bool * _retval)1317 nsresult nsXPCComponents_Exception::CallOrConstruct(
1318     nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj,
1319     const CallArgs& args, bool* _retval) {
1320   nsXPConnect* xpc = nsXPConnect::XPConnect();
1321 
1322   MOZ_DIAGNOSTIC_ASSERT(nsContentUtils::IsCallerChrome());
1323 
1324   // Parse the arguments to the Exception constructor.
1325   ExceptionArgParser parser(cx, xpc);
1326   if (!parser.parse(args))
1327     return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
1328 
1329   RefPtr<Exception> e =
1330       new Exception(nsCString(parser.eMsg), parser.eResult, EmptyCString(),
1331                     parser.eStack, parser.eData);
1332 
1333   RootedObject newObj(cx);
1334   if (NS_FAILED(xpc->WrapNative(cx, obj, e, NS_GET_IID(nsIException),
1335                                 newObj.address())) ||
1336       !newObj) {
1337     return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval);
1338   }
1339 
1340   args.rval().setObject(*newObj);
1341   return NS_OK;
1342 }
1343 
1344 NS_IMETHODIMP
HasInstance(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * obj,HandleValue val,bool * bp,bool * _retval)1345 nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative* wrapper,
1346                                        JSContext* cx, JSObject* obj,
1347                                        HandleValue val, bool* bp,
1348                                        bool* _retval) {
1349   using namespace mozilla::dom;
1350 
1351   if (bp) {
1352     *bp = (val.isObject() && IS_INSTANCE_OF(Exception, &val.toObject())) ||
1353           JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIException));
1354   }
1355   return NS_OK;
1356 }
1357 
1358 /***************************************************************************/
1359 // This class is for the thing returned by "new Component.Constructor".
1360 
1361 // XXXjband we use this CID for security check, but security system can't see
1362 // it since it has no registed factory. Security really kicks in when we try
1363 // to build a wrapper around an instance.
1364 
1365 // {B4A95150-E25A-11d3-8F61-0010A4E73D9A}
1366 #define NS_XPCCONSTRUCTOR_CID                       \
1367   {                                                 \
1368     0xb4a95150, 0xe25a, 0x11d3, {                   \
1369       0x8f, 0x61, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a \
1370     }                                               \
1371   }
1372 
1373 class nsXPCConstructor : public nsIXPCConstructor,
1374                          public nsIXPCScriptable,
1375                          public nsIClassInfo {
1376  public:
1377   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCCONSTRUCTOR_CID)
1378  public:
1379   // all the interface method declarations...
1380   NS_DECL_ISUPPORTS
1381   NS_DECL_NSIXPCCONSTRUCTOR
1382   NS_DECL_NSIXPCSCRIPTABLE
1383   NS_DECL_NSICLASSINFO
1384 
1385  public:
1386   nsXPCConstructor() = delete;
1387   nsXPCConstructor(nsIJSCID* aClassID, nsIJSIID* aInterfaceID,
1388                    const char* aInitializer);
1389 
1390  private:
1391   virtual ~nsXPCConstructor();
1392   nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
1393                            HandleObject obj, const CallArgs& args,
1394                            bool* _retval);
1395 
1396  private:
1397   RefPtr<nsIJSCID> mClassID;
1398   RefPtr<nsIJSIID> mInterfaceID;
1399   char* mInitializer;
1400 };
1401 
1402 /***************************************************************************/
1403 NS_IMETHODIMP
GetInterfaces(uint32_t * aCount,nsIID *** aArray)1404 nsXPCConstructor::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
1405   *aCount = 2;
1406   nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
1407   *aArray = array;
1408 
1409   array[0] = NS_GET_IID(nsIXPCConstructor).Clone();
1410   array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
1411   return NS_OK;
1412 }
1413 
1414 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)1415 nsXPCConstructor::GetScriptableHelper(nsIXPCScriptable** retval) {
1416   *retval = nullptr;
1417   return NS_OK;
1418 }
1419 
1420 NS_IMETHODIMP
GetContractID(nsACString & aContractID)1421 nsXPCConstructor::GetContractID(nsACString& aContractID) {
1422   aContractID.SetIsVoid(true);
1423   return NS_ERROR_NOT_AVAILABLE;
1424 }
1425 
1426 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)1427 nsXPCConstructor::GetClassDescription(nsACString& aClassDescription) {
1428   aClassDescription.AssignLiteral("XPCConstructor");
1429   return NS_OK;
1430 }
1431 
1432 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)1433 nsXPCConstructor::GetClassID(nsCID** aClassID) {
1434   *aClassID = nullptr;
1435   return NS_OK;
1436 }
1437 
1438 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)1439 nsXPCConstructor::GetFlags(uint32_t* aFlags) {
1440   *aFlags = 0;
1441   return NS_OK;
1442 }
1443 
1444 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)1445 nsXPCConstructor::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
1446   return NS_ERROR_NOT_AVAILABLE;
1447 }
1448 
nsXPCConstructor(nsIJSCID * aClassID,nsIJSIID * aInterfaceID,const char * aInitializer)1449 nsXPCConstructor::nsXPCConstructor(nsIJSCID* aClassID, nsIJSIID* aInterfaceID,
1450                                    const char* aInitializer)
1451     : mClassID(aClassID), mInterfaceID(aInterfaceID) {
1452   mInitializer = aInitializer ? moz_xstrdup(aInitializer) : nullptr;
1453 }
1454 
~nsXPCConstructor()1455 nsXPCConstructor::~nsXPCConstructor() {
1456   if (mInitializer) free(mInitializer);
1457 }
1458 
1459 NS_IMETHODIMP
GetClassID(nsIJSCID ** aClassID)1460 nsXPCConstructor::GetClassID(nsIJSCID** aClassID) {
1461   RefPtr<nsIJSCID> rval = mClassID;
1462   rval.forget(aClassID);
1463   return NS_OK;
1464 }
1465 
1466 NS_IMETHODIMP
GetInterfaceID(nsIJSIID ** aInterfaceID)1467 nsXPCConstructor::GetInterfaceID(nsIJSIID** aInterfaceID) {
1468   RefPtr<nsIJSIID> rval = mInterfaceID;
1469   rval.forget(aInterfaceID);
1470   return NS_OK;
1471 }
1472 
1473 NS_IMETHODIMP
GetInitializer(char ** aInitializer)1474 nsXPCConstructor::GetInitializer(char** aInitializer) {
1475   XPC_STRING_GETTER_BODY(aInitializer, mInitializer);
1476 }
1477 
NS_IMPL_ISUPPORTS(nsXPCConstructor,nsIXPCConstructor,nsIXPCScriptable,nsIClassInfo)1478 NS_IMPL_ISUPPORTS(nsXPCConstructor, nsIXPCConstructor, nsIXPCScriptable,
1479                   nsIClassInfo)
1480 
1481 // The nsIXPCScriptable map declaration that will generate stubs for us...
1482 #define XPC_MAP_CLASSNAME nsXPCConstructor
1483 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCConstructor"
1484 #define XPC_MAP_FLAGS (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT)
1485 #include "xpc_map_end.h" /* This will #undef the above */
1486 
1487 NS_IMETHODIMP
1488 nsXPCConstructor::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
1489                        JSObject* objArg, const CallArgs& args, bool* _retval) {
1490   RootedObject obj(cx, objArg);
1491   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1492 }
1493 
1494 NS_IMETHODIMP
Construct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,const CallArgs & args,bool * _retval)1495 nsXPCConstructor::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
1496                             JSObject* objArg, const CallArgs& args,
1497                             bool* _retval) {
1498   RootedObject obj(cx, objArg);
1499   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1500 }
1501 
1502 // static
CallOrConstruct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,HandleObject obj,const CallArgs & args,bool * _retval)1503 nsresult nsXPCConstructor::CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
1504                                            JSContext* cx, HandleObject obj,
1505                                            const CallArgs& args,
1506                                            bool* _retval) {
1507   nsXPConnect* xpc = nsXPConnect::XPConnect();
1508 
1509   // security check not required because we are going to call through the
1510   // code which is reflected into JS which will do that for us later.
1511 
1512   RootedObject cidObj(cx);
1513   RootedObject iidObj(cx);
1514 
1515   if (NS_FAILED(xpc->WrapNative(cx, obj, mClassID, NS_GET_IID(nsIJSCID),
1516                                 cidObj.address())) ||
1517       !cidObj ||
1518       NS_FAILED(xpc->WrapNative(cx, obj, mInterfaceID, NS_GET_IID(nsIJSIID),
1519                                 iidObj.address())) ||
1520       !iidObj) {
1521     return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval);
1522   }
1523 
1524   JS::Rooted<JS::Value> arg(cx, ObjectValue(*iidObj));
1525   RootedValue rval(cx);
1526   if (!JS_CallFunctionName(cx, cidObj, "createInstance",
1527                            JS::HandleValueArray(arg), &rval) ||
1528       rval.isPrimitive()) {
1529     // createInstance will have thrown an exception
1530     *_retval = false;
1531     return NS_OK;
1532   }
1533 
1534   args.rval().set(rval);
1535 
1536   // call initializer method if supplied
1537   if (mInitializer) {
1538     RootedObject newObj(cx, &rval.toObject());
1539     // first check existence of function property for better error reporting
1540     RootedValue fun(cx);
1541     if (!JS_GetProperty(cx, newObj, mInitializer, &fun) || fun.isPrimitive()) {
1542       return ThrowAndFail(NS_ERROR_XPC_BAD_INITIALIZER_NAME, cx, _retval);
1543     }
1544 
1545     RootedValue dummy(cx);
1546     if (!JS_CallFunctionValue(cx, newObj, fun, args, &dummy)) {
1547       // function should have thrown an exception
1548       *_retval = false;
1549       return NS_OK;
1550     }
1551   }
1552 
1553   return NS_OK;
1554 }
1555 
1556 /*******************************************************/
1557 // JavaScript Constructor for nsIXPCConstructor objects (Components.Constructor)
1558 
1559 class nsXPCComponents_Constructor final : public nsIXPCComponents_Constructor,
1560                                           public nsIXPCScriptable,
1561                                           public nsIClassInfo {
1562  public:
1563   // all the interface method declarations...
1564   NS_DECL_ISUPPORTS
1565   NS_DECL_NSIXPCCOMPONENTS_CONSTRUCTOR
1566   NS_DECL_NSIXPCSCRIPTABLE
1567   NS_DECL_NSICLASSINFO
1568 
1569  public:
1570   nsXPCComponents_Constructor();
1571 
1572  private:
1573   virtual ~nsXPCComponents_Constructor();
1574   static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
1575                                   JSContext* cx, HandleObject obj,
1576                                   const CallArgs& args, bool* _retval);
1577 };
1578 
1579 /***************************************************************************/
1580 NS_IMETHODIMP
GetInterfaces(uint32_t * aCount,nsIID *** aArray)1581 nsXPCComponents_Constructor::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
1582   *aCount = 2;
1583   nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
1584   *aArray = array;
1585 
1586   array[0] = NS_GET_IID(nsIXPCComponents_Constructor).Clone();
1587   array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
1588   return NS_OK;
1589 }
1590 
1591 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** retval)1592 nsXPCComponents_Constructor::GetScriptableHelper(nsIXPCScriptable** retval) {
1593   *retval = nullptr;
1594   return NS_OK;
1595 }
1596 
1597 NS_IMETHODIMP
GetContractID(nsACString & aContractID)1598 nsXPCComponents_Constructor::GetContractID(nsACString& aContractID) {
1599   aContractID.SetIsVoid(true);
1600   return NS_ERROR_NOT_AVAILABLE;
1601 }
1602 
1603 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)1604 nsXPCComponents_Constructor::GetClassDescription(
1605     nsACString& aClassDescription) {
1606   aClassDescription.AssignLiteral("XPCComponents_Constructor");
1607   return NS_OK;
1608 }
1609 
1610 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)1611 nsXPCComponents_Constructor::GetClassID(nsCID** aClassID) {
1612   *aClassID = nullptr;
1613   return NS_OK;
1614 }
1615 
1616 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)1617 nsXPCComponents_Constructor::GetFlags(uint32_t* aFlags) {
1618   *aFlags = 0;
1619   return NS_OK;
1620 }
1621 
1622 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)1623 nsXPCComponents_Constructor::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
1624   return NS_ERROR_NOT_AVAILABLE;
1625 }
1626 
nsXPCComponents_Constructor()1627 nsXPCComponents_Constructor::nsXPCComponents_Constructor() {}
1628 
~nsXPCComponents_Constructor()1629 nsXPCComponents_Constructor::~nsXPCComponents_Constructor() {
1630   // empty
1631 }
1632 
NS_IMPL_ISUPPORTS(nsXPCComponents_Constructor,nsIXPCComponents_Constructor,nsIXPCScriptable,nsIClassInfo)1633 NS_IMPL_ISUPPORTS(nsXPCComponents_Constructor, nsIXPCComponents_Constructor,
1634                   nsIXPCScriptable, nsIClassInfo)
1635 
1636 // The nsIXPCScriptable map declaration that will generate stubs for us...
1637 #define XPC_MAP_CLASSNAME nsXPCComponents_Constructor
1638 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Constructor"
1639 #define XPC_MAP_FLAGS                                         \
1640   (XPC_SCRIPTABLE_WANT_CALL | XPC_SCRIPTABLE_WANT_CONSTRUCT | \
1641    XPC_SCRIPTABLE_WANT_HASINSTANCE |                          \
1642    XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
1643 #include "xpc_map_end.h" /* This will #undef the above */
1644 
1645 NS_IMETHODIMP
1646 nsXPCComponents_Constructor::Call(nsIXPConnectWrappedNative* wrapper,
1647                                   JSContext* cx, JSObject* objArg,
1648                                   const CallArgs& args, bool* _retval) {
1649   RootedObject obj(cx, objArg);
1650   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1651 }
1652 
1653 NS_IMETHODIMP
Construct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * objArg,const CallArgs & args,bool * _retval)1654 nsXPCComponents_Constructor::Construct(nsIXPConnectWrappedNative* wrapper,
1655                                        JSContext* cx, JSObject* objArg,
1656                                        const CallArgs& args, bool* _retval) {
1657   RootedObject obj(cx, objArg);
1658   return CallOrConstruct(wrapper, cx, obj, args, _retval);
1659 }
1660 
1661 // static
CallOrConstruct(nsIXPConnectWrappedNative * wrapper,JSContext * cx,HandleObject obj,const CallArgs & args,bool * _retval)1662 nsresult nsXPCComponents_Constructor::CallOrConstruct(
1663     nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj,
1664     const CallArgs& args, bool* _retval) {
1665   // make sure we have at least one arg
1666 
1667   if (args.length() < 1)
1668     return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval);
1669 
1670   // get the various other object pointers we need
1671 
1672   nsXPConnect* xpc = nsXPConnect::XPConnect();
1673   XPCWrappedNativeScope* scope = ObjectScope(obj);
1674   nsCOMPtr<nsIXPCComponents> comp;
1675 
1676   if (!xpc || !scope || !(comp = do_QueryInterface(scope->GetComponents())))
1677     return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
1678 
1679   // Do the security check if necessary
1680 
1681   if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(
1682           cx, nsXPCConstructor::GetCID()))) {
1683     // the security manager vetoed. It should have set an exception.
1684     *_retval = false;
1685     return NS_OK;
1686   }
1687 
1688   // initialization params for the Constructor object we will create
1689   nsCOMPtr<nsIJSCID> cClassID;
1690   nsCOMPtr<nsIJSIID> cInterfaceID;
1691   const char* cInitializer = nullptr;
1692   JSAutoByteString cInitializerBytes;
1693 
1694   if (args.length() >= 3) {
1695     // args[2] is an initializer function or property name
1696     RootedString str(cx, ToString(cx, args[2]));
1697     if (!str || !(cInitializer = cInitializerBytes.encodeLatin1(cx, str)))
1698       return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
1699   }
1700 
1701   if (args.length() >= 2) {
1702     // args[1] is an iid name string
1703     // XXXjband support passing "Components.interfaces.foo"?
1704 
1705     nsCOMPtr<nsIXPCComponents_Interfaces> ifaces;
1706     RootedObject ifacesObj(cx);
1707 
1708     // we do the lookup by asking the Components.interfaces object
1709     // for the property with this name - i.e. we let its caching of these
1710     // nsIJSIID objects work for us.
1711 
1712     if (NS_FAILED(comp->GetInterfaces(getter_AddRefs(ifaces))) ||
1713         NS_FAILED(xpc->WrapNative(cx, obj, ifaces,
1714                                   NS_GET_IID(nsIXPCComponents_Interfaces),
1715                                   ifacesObj.address())) ||
1716         !ifacesObj) {
1717       return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
1718     }
1719 
1720     RootedString str(cx, ToString(cx, args[1]));
1721     RootedId id(cx);
1722     if (!str || !JS_StringToId(cx, str, &id))
1723       return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
1724 
1725     RootedValue val(cx);
1726     if (!JS_GetPropertyById(cx, ifacesObj, id, &val) || val.isPrimitive())
1727       return ThrowAndFail(NS_ERROR_XPC_BAD_IID, cx, _retval);
1728 
1729     nsCOMPtr<nsIXPConnectWrappedNative> wn;
1730     if (NS_FAILED(xpc->GetWrappedNativeOfJSObject(cx, &val.toObject(),
1731                                                   getter_AddRefs(wn))) ||
1732         !wn || !(cInterfaceID = do_QueryWrappedNative(wn))) {
1733       return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
1734     }
1735   } else {
1736     nsCOMPtr<nsIInterfaceInfo> info;
1737     xpc->GetInfoForIID(&NS_GET_IID(nsISupports), getter_AddRefs(info));
1738 
1739     if (info) {
1740       cInterfaceID = nsJSIID::NewID(info);
1741     }
1742     if (!cInterfaceID)
1743       return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
1744   }
1745 
1746   // a new scope to avoid warnings about shadowed names
1747   {
1748     // argv[0] is a contractid name string
1749     // XXXjband support passing "Components.classes.foo"?
1750 
1751     // we do the lookup by asking the Components.classes object
1752     // for the property with this name - i.e. we let its caching of these
1753     // nsIJSCID objects work for us.
1754 
1755     nsCOMPtr<nsIXPCComponents_Classes> classes;
1756     RootedObject classesObj(cx);
1757 
1758     if (NS_FAILED(comp->GetClasses(getter_AddRefs(classes))) ||
1759         NS_FAILED(xpc->WrapNative(cx, obj, classes,
1760                                   NS_GET_IID(nsIXPCComponents_Classes),
1761                                   classesObj.address())) ||
1762         !classesObj) {
1763       return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
1764     }
1765 
1766     RootedString str(cx, ToString(cx, args[0]));
1767     RootedId id(cx);
1768     if (!str || !JS_StringToId(cx, str, &id))
1769       return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
1770 
1771     RootedValue val(cx);
1772     if (!JS_GetPropertyById(cx, classesObj, id, &val) || val.isPrimitive())
1773       return ThrowAndFail(NS_ERROR_XPC_BAD_CID, cx, _retval);
1774 
1775     nsCOMPtr<nsIXPConnectWrappedNative> wn;
1776     if (NS_FAILED(xpc->GetWrappedNativeOfJSObject(cx, val.toObjectOrNull(),
1777                                                   getter_AddRefs(wn))) ||
1778         !wn || !(cClassID = do_QueryWrappedNative(wn))) {
1779       return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
1780     }
1781   }
1782 
1783   nsCOMPtr<nsIXPCConstructor> ctor =
1784       new nsXPCConstructor(cClassID, cInterfaceID, cInitializer);
1785   RootedObject newObj(cx);
1786 
1787   if (NS_FAILED(xpc->WrapNative(cx, obj, ctor, NS_GET_IID(nsIXPCConstructor),
1788                                 newObj.address())) ||
1789       !newObj) {
1790     return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval);
1791   }
1792 
1793   args.rval().setObject(*newObj);
1794   return NS_OK;
1795 }
1796 
1797 NS_IMETHODIMP
HasInstance(nsIXPConnectWrappedNative * wrapper,JSContext * cx,JSObject * obj,HandleValue val,bool * bp,bool * _retval)1798 nsXPCComponents_Constructor::HasInstance(nsIXPConnectWrappedNative* wrapper,
1799                                          JSContext* cx, JSObject* obj,
1800                                          HandleValue val, bool* bp,
1801                                          bool* _retval) {
1802   if (bp) *bp = JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIXPCConstructor));
1803   return NS_OK;
1804 }
1805 
1806 class nsXPCComponents_Utils final : public nsIXPCComponents_Utils,
1807                                     public nsIXPCScriptable {
1808  public:
1809   // all the interface method declarations...
1810   NS_DECL_ISUPPORTS
1811   NS_DECL_NSIXPCSCRIPTABLE
1812   NS_DECL_NSIXPCCOMPONENTS_UTILS
1813 
1814  public:
nsXPCComponents_Utils()1815   nsXPCComponents_Utils() {}
1816 
1817  private:
~nsXPCComponents_Utils()1818   virtual ~nsXPCComponents_Utils() {}
1819   nsCOMPtr<nsIXPCComponents_utils_Sandbox> mSandbox;
1820 };
1821 
NS_IMPL_ISUPPORTS(nsXPCComponents_Utils,nsIXPCComponents_Utils,nsIXPCScriptable)1822 NS_IMPL_ISUPPORTS(nsXPCComponents_Utils, nsIXPCComponents_Utils,
1823                   nsIXPCScriptable)
1824 
1825 // The nsIXPCScriptable map declaration that will generate stubs for us...
1826 #define XPC_MAP_CLASSNAME nsXPCComponents_Utils
1827 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Utils"
1828 #define XPC_MAP_FLAGS XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE
1829 #include "xpc_map_end.h" /* This will #undef the above */
1830 
1831 NS_IMETHODIMP
1832 nsXPCComponents_Utils::GetSandbox(nsIXPCComponents_utils_Sandbox** aSandbox) {
1833   NS_ENSURE_ARG_POINTER(aSandbox);
1834   if (!mSandbox) mSandbox = NewSandboxConstructor();
1835 
1836   nsCOMPtr<nsIXPCComponents_utils_Sandbox> rval = mSandbox;
1837   rval.forget(aSandbox);
1838   return NS_OK;
1839 }
1840 
1841 NS_IMETHODIMP
ReportError(HandleValue error,HandleValue stack,JSContext * cx)1842 nsXPCComponents_Utils::ReportError(HandleValue error, HandleValue stack,
1843                                    JSContext* cx) {
1844   // This function shall never fail! Silently eat any failure conditions.
1845 
1846   nsCOMPtr<nsIConsoleService> console(
1847       do_GetService(NS_CONSOLESERVICE_CONTRACTID));
1848   if (!console) return NS_OK;
1849 
1850   nsGlobalWindowInner* globalWin = CurrentWindowOrNull(cx);
1851   nsPIDOMWindowInner* win = globalWin ? globalWin->AsInner() : nullptr;
1852   const uint64_t innerWindowID = win ? win->WindowID() : 0;
1853 
1854   RootedObject errorObj(cx, error.isObject() ? &error.toObject() : nullptr);
1855   JSErrorReport* err = errorObj ? JS_ErrorFromException(cx, errorObj) : nullptr;
1856 
1857   nsCOMPtr<nsIScriptError> scripterr;
1858 
1859   if (errorObj) {
1860     JS::RootedObject stackVal(cx,
1861                               FindExceptionStackForConsoleReport(win, error));
1862     if (stackVal) {
1863       scripterr = new nsScriptErrorWithStack(stackVal);
1864     }
1865   }
1866 
1867   nsString fileName;
1868   uint32_t lineNo = 0;
1869 
1870   if (!scripterr) {
1871     RootedObject stackObj(cx);
1872     if (stack.isObject()) {
1873       if (!JS::IsSavedFrame(&stack.toObject())) {
1874         return NS_ERROR_INVALID_ARG;
1875       }
1876 
1877       stackObj = &stack.toObject();
1878 
1879       if (GetSavedFrameLine(cx, stackObj, &lineNo) != SavedFrameResult::Ok) {
1880         JS_ClearPendingException(cx);
1881       }
1882 
1883       RootedString source(cx);
1884       nsAutoJSString str;
1885       if (GetSavedFrameSource(cx, stackObj, &source) == SavedFrameResult::Ok &&
1886           str.init(cx, source)) {
1887         fileName = str;
1888       } else {
1889         JS_ClearPendingException(cx);
1890       }
1891     } else {
1892       nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
1893       if (frame) {
1894         frame->GetFilename(cx, fileName);
1895         lineNo = frame->GetLineNumber(cx);
1896         JS::Rooted<JS::Value> stack(cx);
1897         nsresult rv = frame->GetNativeSavedFrame(&stack);
1898         if (NS_SUCCEEDED(rv) && stack.isObject()) {
1899           stackObj = &stack.toObject();
1900         }
1901       }
1902     }
1903 
1904     if (stackObj) {
1905       scripterr = new nsScriptErrorWithStack(stackObj);
1906     }
1907   }
1908 
1909   if (!scripterr) {
1910     scripterr = new nsScriptError();
1911   }
1912 
1913   if (err) {
1914     // It's a proper JS Error
1915     nsAutoString fileUni;
1916     CopyUTF8toUTF16(err->filename, fileUni);
1917 
1918     uint32_t column = err->tokenOffset();
1919 
1920     const char16_t* linebuf = err->linebuf();
1921 
1922     nsresult rv = scripterr->InitWithWindowID(
1923         err->message() ? NS_ConvertUTF8toUTF16(err->message().c_str())
1924                        : EmptyString(),
1925         fileUni,
1926         linebuf ? nsDependentString(linebuf, err->linebufLength())
1927                 : EmptyString(),
1928         err->lineno, column, err->flags, "XPConnect JavaScript", innerWindowID);
1929     NS_ENSURE_SUCCESS(rv, NS_OK);
1930 
1931     console->LogMessage(scripterr);
1932     return NS_OK;
1933   }
1934 
1935   // It's not a JS Error object, so we synthesize as best we're able.
1936   RootedString msgstr(cx, ToString(cx, error));
1937   if (!msgstr) return NS_OK;
1938 
1939   nsAutoJSString msg;
1940   if (!msg.init(cx, msgstr)) return NS_OK;
1941 
1942   nsresult rv =
1943       scripterr->InitWithWindowID(msg, fileName, EmptyString(), lineNo, 0, 0,
1944                                   "XPConnect JavaScript", innerWindowID);
1945   NS_ENSURE_SUCCESS(rv, NS_OK);
1946 
1947   console->LogMessage(scripterr);
1948   return NS_OK;
1949 }
1950 
1951 NS_IMETHODIMP
EvalInSandbox(const nsAString & source,HandleValue sandboxVal,HandleValue version,const nsACString & filenameArg,int32_t lineNumber,JSContext * cx,uint8_t optionalArgc,MutableHandleValue retval)1952 nsXPCComponents_Utils::EvalInSandbox(
1953     const nsAString& source, HandleValue sandboxVal, HandleValue version,
1954     const nsACString& filenameArg, int32_t lineNumber, JSContext* cx,
1955     uint8_t optionalArgc, MutableHandleValue retval) {
1956   RootedObject sandbox(cx);
1957   if (!JS_ValueToObject(cx, sandboxVal, &sandbox) || !sandbox)
1958     return NS_ERROR_INVALID_ARG;
1959 
1960   // Optional third argument: JS version, as a string, is unused.
1961 
1962   // Optional fourth and fifth arguments: filename and line number.
1963   int32_t lineNo = (optionalArgc >= 3) ? lineNumber : 1;
1964   nsCString filename;
1965   if (!filenameArg.IsVoid()) {
1966     filename.Assign(filenameArg);
1967   } else {
1968     // Get the current source info.
1969     nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
1970     if (frame) {
1971       nsString frameFile;
1972       frame->GetFilename(cx, frameFile);
1973       CopyUTF16toUTF8(frameFile, filename);
1974       lineNo = frame->GetLineNumber(cx);
1975     }
1976   }
1977 
1978   return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo, retval);
1979 }
1980 
1981 NS_IMETHODIMP
GetSandboxAddonId(HandleValue sandboxVal,JSContext * cx,MutableHandleValue rval)1982 nsXPCComponents_Utils::GetSandboxAddonId(HandleValue sandboxVal, JSContext* cx,
1983                                          MutableHandleValue rval) {
1984   if (!sandboxVal.isObject()) return NS_ERROR_INVALID_ARG;
1985 
1986   RootedObject sandbox(cx, &sandboxVal.toObject());
1987   sandbox = js::CheckedUnwrap(sandbox);
1988   if (!sandbox || !xpc::IsSandbox(sandbox)) return NS_ERROR_INVALID_ARG;
1989 
1990   return xpc::GetSandboxAddonId(cx, sandbox, rval);
1991 }
1992 
1993 NS_IMETHODIMP
GetSandboxMetadata(HandleValue sandboxVal,JSContext * cx,MutableHandleValue rval)1994 nsXPCComponents_Utils::GetSandboxMetadata(HandleValue sandboxVal, JSContext* cx,
1995                                           MutableHandleValue rval) {
1996   if (!sandboxVal.isObject()) return NS_ERROR_INVALID_ARG;
1997 
1998   RootedObject sandbox(cx, &sandboxVal.toObject());
1999   sandbox = js::CheckedUnwrap(sandbox);
2000   if (!sandbox || !xpc::IsSandbox(sandbox)) return NS_ERROR_INVALID_ARG;
2001 
2002   return xpc::GetSandboxMetadata(cx, sandbox, rval);
2003 }
2004 
2005 NS_IMETHODIMP
SetSandboxMetadata(HandleValue sandboxVal,HandleValue metadataVal,JSContext * cx)2006 nsXPCComponents_Utils::SetSandboxMetadata(HandleValue sandboxVal,
2007                                           HandleValue metadataVal,
2008                                           JSContext* cx) {
2009   if (!sandboxVal.isObject()) return NS_ERROR_INVALID_ARG;
2010 
2011   RootedObject sandbox(cx, &sandboxVal.toObject());
2012   sandbox = js::CheckedUnwrap(sandbox);
2013   if (!sandbox || !xpc::IsSandbox(sandbox)) return NS_ERROR_INVALID_ARG;
2014 
2015   nsresult rv = xpc::SetSandboxMetadata(cx, sandbox, metadataVal);
2016   NS_ENSURE_SUCCESS(rv, rv);
2017 
2018   return NS_OK;
2019 }
2020 
2021 NS_IMETHODIMP
Import(const nsACString & registryLocation,HandleValue targetObj,JSContext * cx,uint8_t optionalArgc,MutableHandleValue retval)2022 nsXPCComponents_Utils::Import(const nsACString& registryLocation,
2023                               HandleValue targetObj, JSContext* cx,
2024                               uint8_t optionalArgc, MutableHandleValue retval) {
2025   RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
2026   MOZ_ASSERT(moduleloader);
2027 
2028   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("nsXPCComponents_Utils::Import", OTHER,
2029                                         registryLocation);
2030 
2031   return moduleloader->ImportInto(registryLocation, targetObj, cx, optionalArgc,
2032                                   retval);
2033 }
2034 
2035 NS_IMETHODIMP
IsModuleLoaded(const nsACString & registryLocation,bool * retval)2036 nsXPCComponents_Utils::IsModuleLoaded(const nsACString& registryLocation,
2037                                       bool* retval) {
2038   RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
2039   MOZ_ASSERT(moduleloader);
2040   return moduleloader->IsModuleLoaded(registryLocation, retval);
2041 }
2042 
2043 NS_IMETHODIMP
Unload(const nsACString & registryLocation)2044 nsXPCComponents_Utils::Unload(const nsACString& registryLocation) {
2045   RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
2046   MOZ_ASSERT(moduleloader);
2047   return moduleloader->Unload(registryLocation);
2048 }
2049 
2050 NS_IMETHODIMP
ImportGlobalProperties(HandleValue aPropertyList,JSContext * cx)2051 nsXPCComponents_Utils::ImportGlobalProperties(HandleValue aPropertyList,
2052                                               JSContext* cx) {
2053   RootedObject global(cx, CurrentGlobalOrNull(cx));
2054   MOZ_ASSERT(global);
2055 
2056   // Don't allow doing this if the global is a Window
2057   nsGlobalWindowInner* win;
2058   if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, &global, win))) {
2059     return NS_ERROR_NOT_AVAILABLE;
2060   }
2061 
2062   GlobalProperties options;
2063   NS_ENSURE_TRUE(aPropertyList.isObject(), NS_ERROR_INVALID_ARG);
2064 
2065   RootedObject propertyList(cx, &aPropertyList.toObject());
2066   bool isArray;
2067   if (NS_WARN_IF(!JS_IsArrayObject(cx, propertyList, &isArray))) {
2068     return NS_ERROR_FAILURE;
2069   }
2070   if (NS_WARN_IF(!isArray)) {
2071     return NS_ERROR_INVALID_ARG;
2072   }
2073 
2074   if (!options.Parse(cx, propertyList) ||
2075       !options.DefineInXPCComponents(cx, global)) {
2076     return NS_ERROR_FAILURE;
2077   }
2078 
2079   return NS_OK;
2080 }
2081 
2082 NS_IMETHODIMP
GetWeakReference(HandleValue object,JSContext * cx,xpcIJSWeakReference ** _retval)2083 nsXPCComponents_Utils::GetWeakReference(HandleValue object, JSContext* cx,
2084                                         xpcIJSWeakReference** _retval) {
2085   RefPtr<xpcJSWeakReference> ref = new xpcJSWeakReference();
2086   nsresult rv = ref->Init(cx, object);
2087   NS_ENSURE_SUCCESS(rv, rv);
2088   ref.forget(_retval);
2089   return NS_OK;
2090 }
2091 
2092 NS_IMETHODIMP
ForceGC()2093 nsXPCComponents_Utils::ForceGC() {
2094   JSContext* cx = XPCJSContext::Get()->Context();
2095   PrepareForFullGC(cx);
2096   GCForReason(cx, GC_NORMAL, gcreason::COMPONENT_UTILS);
2097   return NS_OK;
2098 }
2099 
2100 NS_IMETHODIMP
ForceCC(nsICycleCollectorListener * listener)2101 nsXPCComponents_Utils::ForceCC(nsICycleCollectorListener* listener) {
2102   nsJSContext::CycleCollectNow(listener);
2103   return NS_OK;
2104 }
2105 
2106 NS_IMETHODIMP
FinishCC()2107 nsXPCComponents_Utils::FinishCC() {
2108   nsCycleCollector_finishAnyCurrentCollection();
2109   return NS_OK;
2110 }
2111 
2112 NS_IMETHODIMP
CcSlice(int64_t budget)2113 nsXPCComponents_Utils::CcSlice(int64_t budget) {
2114   nsJSContext::RunCycleCollectorWorkSlice(budget);
2115   return NS_OK;
2116 }
2117 
2118 NS_IMETHODIMP
GetMaxCCSliceTimeSinceClear(int32_t * out)2119 nsXPCComponents_Utils::GetMaxCCSliceTimeSinceClear(int32_t* out) {
2120   *out = nsJSContext::GetMaxCCSliceTimeSinceClear();
2121   return NS_OK;
2122 }
2123 
2124 NS_IMETHODIMP
ClearMaxCCTime()2125 nsXPCComponents_Utils::ClearMaxCCTime() {
2126   nsJSContext::ClearMaxCCSliceTime();
2127   return NS_OK;
2128 }
2129 
2130 NS_IMETHODIMP
ForceShrinkingGC()2131 nsXPCComponents_Utils::ForceShrinkingGC() {
2132   JSContext* cx = dom::danger::GetJSContext();
2133   PrepareForFullGC(cx);
2134   GCForReason(cx, GC_SHRINK, gcreason::COMPONENT_UTILS);
2135   return NS_OK;
2136 }
2137 
2138 class PreciseGCRunnable : public Runnable {
2139  public:
PreciseGCRunnable(ScheduledGCCallback * aCallback,bool aShrinking)2140   PreciseGCRunnable(ScheduledGCCallback* aCallback, bool aShrinking)
2141       : mozilla::Runnable("PreciseGCRunnable"),
2142         mCallback(aCallback),
2143         mShrinking(aShrinking) {}
2144 
Run()2145   NS_IMETHOD Run() override {
2146     nsJSContext::GarbageCollectNow(
2147         gcreason::COMPONENT_UTILS, nsJSContext::NonIncrementalGC,
2148         mShrinking ? nsJSContext::ShrinkingGC : nsJSContext::NonShrinkingGC);
2149 
2150     mCallback->Callback();
2151     return NS_OK;
2152   }
2153 
2154  private:
2155   RefPtr<ScheduledGCCallback> mCallback;
2156   bool mShrinking;
2157 };
2158 
2159 NS_IMETHODIMP
SchedulePreciseGC(ScheduledGCCallback * aCallback)2160 nsXPCComponents_Utils::SchedulePreciseGC(ScheduledGCCallback* aCallback) {
2161   RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, false);
2162   return NS_DispatchToMainThread(event);
2163 }
2164 
2165 NS_IMETHODIMP
SchedulePreciseShrinkingGC(ScheduledGCCallback * aCallback)2166 nsXPCComponents_Utils::SchedulePreciseShrinkingGC(
2167     ScheduledGCCallback* aCallback) {
2168   RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, true);
2169   return NS_DispatchToMainThread(event);
2170 }
2171 
2172 NS_IMETHODIMP
UnlinkGhostWindows()2173 nsXPCComponents_Utils::UnlinkGhostWindows() {
2174 #ifdef DEBUG
2175   nsWindowMemoryReporter::UnlinkGhostWindows();
2176 
2177   if (XRE_IsParentProcess()) {
2178     nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
2179     if (obsvc) {
2180       obsvc->NotifyObservers(nullptr, "child-ghost-request", nullptr);
2181     }
2182   }
2183 
2184   return NS_OK;
2185 #else
2186   return NS_ERROR_NOT_IMPLEMENTED;
2187 #endif
2188 }
2189 
2190 NS_IMETHODIMP
GetJSTestingFunctions(JSContext * cx,MutableHandleValue retval)2191 nsXPCComponents_Utils::GetJSTestingFunctions(JSContext* cx,
2192                                              MutableHandleValue retval) {
2193   JSObject* obj = js::GetTestingFunctions(cx);
2194   if (!obj) return NS_ERROR_XPC_JAVASCRIPT_ERROR;
2195   retval.setObject(*obj);
2196   return NS_OK;
2197 }
2198 
2199 NS_IMETHODIMP
CallFunctionWithAsyncStack(HandleValue function,nsIStackFrame * stack,const nsAString & asyncCause,JSContext * cx,MutableHandleValue retval)2200 nsXPCComponents_Utils::CallFunctionWithAsyncStack(HandleValue function,
2201                                                   nsIStackFrame* stack,
2202                                                   const nsAString& asyncCause,
2203                                                   JSContext* cx,
2204                                                   MutableHandleValue retval) {
2205   nsresult rv;
2206 
2207   if (!stack || asyncCause.IsEmpty()) {
2208     return NS_ERROR_INVALID_ARG;
2209   }
2210 
2211   JS::Rooted<JS::Value> asyncStack(cx);
2212   rv = stack->GetNativeSavedFrame(&asyncStack);
2213   if (NS_FAILED(rv)) return rv;
2214   if (!asyncStack.isObject()) {
2215     JS_ReportErrorASCII(cx, "Must use a native JavaScript stack frame");
2216     return NS_ERROR_INVALID_ARG;
2217   }
2218 
2219   JS::Rooted<JSObject*> asyncStackObj(cx, &asyncStack.toObject());
2220 
2221   NS_ConvertUTF16toUTF8 utf8Cause(asyncCause);
2222   JS::AutoSetAsyncStackForNewCalls sas(
2223       cx, asyncStackObj, utf8Cause.get(),
2224       JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT);
2225 
2226   if (!JS_CallFunctionValue(cx, nullptr, function,
2227                             JS::HandleValueArray::empty(), retval)) {
2228     return NS_ERROR_XPC_JAVASCRIPT_ERROR;
2229   }
2230 
2231   return NS_OK;
2232 }
2233 
2234 NS_IMETHODIMP
GetGlobalForObject(HandleValue object,JSContext * cx,MutableHandleValue retval)2235 nsXPCComponents_Utils::GetGlobalForObject(HandleValue object, JSContext* cx,
2236                                           MutableHandleValue retval) {
2237   // First argument must be an object.
2238   if (object.isPrimitive()) return NS_ERROR_XPC_BAD_CONVERT_JS;
2239 
2240   // Wrappers are parented to their the global in their home compartment. But
2241   // when getting the global for a cross-compartment wrapper, we really want
2242   // a wrapper for the foreign global. So we need to unwrap before getting the
2243   // parent, enter the compartment for the duration of the call, and wrap the
2244   // result.
2245   Rooted<JSObject*> obj(cx, &object.toObject());
2246   obj = js::UncheckedUnwrap(obj);
2247   {
2248     JSAutoCompartment ac(cx, obj);
2249     obj = JS_GetGlobalForObject(cx, obj);
2250   }
2251 
2252   if (!JS_WrapObject(cx, &obj)) return NS_ERROR_FAILURE;
2253 
2254   // Get the WindowProxy if necessary.
2255   obj = js::ToWindowProxyIfWindow(obj);
2256 
2257   retval.setObject(*obj);
2258   return NS_OK;
2259 }
2260 
2261 NS_IMETHODIMP
IsProxy(HandleValue vobj,JSContext * cx,bool * rval)2262 nsXPCComponents_Utils::IsProxy(HandleValue vobj, JSContext* cx, bool* rval) {
2263   if (!vobj.isObject()) {
2264     *rval = false;
2265     return NS_OK;
2266   }
2267 
2268   RootedObject obj(cx, &vobj.toObject());
2269   obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
2270   NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
2271 
2272   *rval = js::IsScriptedProxy(obj);
2273   return NS_OK;
2274 }
2275 
2276 NS_IMETHODIMP
ExportFunction(HandleValue vfunction,HandleValue vscope,HandleValue voptions,JSContext * cx,MutableHandleValue rval)2277 nsXPCComponents_Utils::ExportFunction(HandleValue vfunction, HandleValue vscope,
2278                                       HandleValue voptions, JSContext* cx,
2279                                       MutableHandleValue rval) {
2280   if (!xpc::ExportFunction(cx, vfunction, vscope, voptions, rval))
2281     return NS_ERROR_FAILURE;
2282   return NS_OK;
2283 }
2284 
2285 NS_IMETHODIMP
CreateObjectIn(HandleValue vobj,HandleValue voptions,JSContext * cx,MutableHandleValue rval)2286 nsXPCComponents_Utils::CreateObjectIn(HandleValue vobj, HandleValue voptions,
2287                                       JSContext* cx, MutableHandleValue rval) {
2288   RootedObject optionsObject(
2289       cx, voptions.isObject() ? &voptions.toObject() : nullptr);
2290   CreateObjectInOptions options(cx, optionsObject);
2291   if (voptions.isObject() && !options.Parse()) {
2292     return NS_ERROR_FAILURE;
2293   }
2294 
2295   if (!xpc::CreateObjectIn(cx, vobj, options, rval)) return NS_ERROR_FAILURE;
2296   return NS_OK;
2297 }
2298 
2299 NS_IMETHODIMP
MakeObjectPropsNormal(HandleValue vobj,JSContext * cx)2300 nsXPCComponents_Utils::MakeObjectPropsNormal(HandleValue vobj, JSContext* cx) {
2301   if (!cx) return NS_ERROR_FAILURE;
2302 
2303   // first argument must be an object
2304   if (vobj.isPrimitive()) return NS_ERROR_XPC_BAD_CONVERT_JS;
2305 
2306   RootedObject obj(cx, js::UncheckedUnwrap(&vobj.toObject()));
2307   JSAutoCompartment ac(cx, obj);
2308   Rooted<IdVector> ida(cx, IdVector(cx));
2309   if (!JS_Enumerate(cx, obj, &ida)) return NS_ERROR_FAILURE;
2310 
2311   RootedId id(cx);
2312   RootedValue v(cx);
2313   for (size_t i = 0; i < ida.length(); ++i) {
2314     id = ida[i];
2315 
2316     if (!JS_GetPropertyById(cx, obj, id, &v)) return NS_ERROR_FAILURE;
2317 
2318     if (v.isPrimitive()) continue;
2319 
2320     RootedObject propobj(cx, &v.toObject());
2321     // TODO Deal with non-functions.
2322     if (!js::IsWrapper(propobj) || !JS::IsCallable(propobj)) continue;
2323 
2324     FunctionForwarderOptions forwarderOptions;
2325     if (!NewFunctionForwarder(cx, id, propobj, forwarderOptions, &v) ||
2326         !JS_SetPropertyById(cx, obj, id, v))
2327       return NS_ERROR_FAILURE;
2328   }
2329 
2330   return NS_OK;
2331 }
2332 
2333 NS_IMETHODIMP
IsDeadWrapper(HandleValue obj,bool * out)2334 nsXPCComponents_Utils::IsDeadWrapper(HandleValue obj, bool* out) {
2335   *out = false;
2336   if (obj.isPrimitive()) return NS_ERROR_INVALID_ARG;
2337 
2338   // We should never have cross-compartment wrappers for dead wrappers.
2339   MOZ_ASSERT_IF(js::IsCrossCompartmentWrapper(&obj.toObject()),
2340                 !JS_IsDeadWrapper(js::UncheckedUnwrap(&obj.toObject())));
2341 
2342   *out = JS_IsDeadWrapper(&obj.toObject());
2343   return NS_OK;
2344 }
2345 
2346 NS_IMETHODIMP
IsCrossProcessWrapper(HandleValue obj,bool * out)2347 nsXPCComponents_Utils::IsCrossProcessWrapper(HandleValue obj, bool* out) {
2348   *out = false;
2349   if (obj.isPrimitive()) return NS_ERROR_INVALID_ARG;
2350 
2351   *out = jsipc::IsWrappedCPOW(&obj.toObject());
2352   return NS_OK;
2353 }
2354 
2355 NS_IMETHODIMP
GetCrossProcessWrapperTag(HandleValue obj,nsACString & out)2356 nsXPCComponents_Utils::GetCrossProcessWrapperTag(HandleValue obj,
2357                                                  nsACString& out) {
2358   if (obj.isPrimitive() || !jsipc::IsWrappedCPOW(&obj.toObject()))
2359     return NS_ERROR_INVALID_ARG;
2360 
2361   jsipc::GetWrappedCPOWTag(&obj.toObject(), out);
2362   return NS_OK;
2363 }
2364 
2365 NS_IMETHODIMP
PermitCPOWsInScope(HandleValue obj)2366 nsXPCComponents_Utils::PermitCPOWsInScope(HandleValue obj) {
2367   if (!obj.isObject()) return NS_ERROR_INVALID_ARG;
2368 
2369   JSObject* scopeObj = js::UncheckedUnwrap(&obj.toObject());
2370   MOZ_DIAGNOSTIC_ASSERT(
2371       !mozJSComponentLoader::Get()->IsLoaderGlobal(scopeObj),
2372       "Don't call Cu.PermitCPOWsInScope() in a JSM that shares its global");
2373   CompartmentPrivate::Get(scopeObj)->allowCPOWs = true;
2374   return NS_OK;
2375 }
2376 
2377 NS_IMETHODIMP
RecomputeWrappers(HandleValue vobj,JSContext * cx)2378 nsXPCComponents_Utils::RecomputeWrappers(HandleValue vobj, JSContext* cx) {
2379   // Determine the compartment of the given object, if any.
2380   JSCompartment* c =
2381       vobj.isObject()
2382           ? js::GetObjectCompartment(js::UncheckedUnwrap(&vobj.toObject()))
2383           : nullptr;
2384 
2385   // If no compartment was given, recompute all.
2386   if (!c)
2387     js::RecomputeWrappers(cx, js::AllCompartments(), js::AllCompartments());
2388   // Otherwise, recompute wrappers for the given compartment.
2389   else
2390     js::RecomputeWrappers(cx, js::SingleCompartment(c),
2391                           js::AllCompartments()) &&
2392         js::RecomputeWrappers(cx, js::AllCompartments(),
2393                               js::SingleCompartment(c));
2394 
2395   return NS_OK;
2396 }
2397 
2398 NS_IMETHODIMP
SetWantXrays(HandleValue vscope,JSContext * cx)2399 nsXPCComponents_Utils::SetWantXrays(HandleValue vscope, JSContext* cx) {
2400   if (!vscope.isObject()) return NS_ERROR_INVALID_ARG;
2401   JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject());
2402   MOZ_DIAGNOSTIC_ASSERT(
2403       !mozJSComponentLoader::Get()->IsLoaderGlobal(scopeObj),
2404       "Don't call Cu.setWantXrays() in a JSM that shares its global");
2405   JSCompartment* compartment = js::GetObjectCompartment(scopeObj);
2406   CompartmentPrivate::Get(scopeObj)->wantXrays = true;
2407   bool ok = js::RecomputeWrappers(cx, js::SingleCompartment(compartment),
2408                                   js::AllCompartments());
2409   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
2410   return NS_OK;
2411 }
2412 
2413 NS_IMETHODIMP
ForcePermissiveCOWs(JSContext * cx)2414 nsXPCComponents_Utils::ForcePermissiveCOWs(JSContext* cx) {
2415   xpc::CrashIfNotInAutomation();
2416   JSObject* currentGlobal = CurrentGlobalOrNull(cx);
2417   MOZ_DIAGNOSTIC_ASSERT(
2418       !mozJSComponentLoader::Get()->IsLoaderGlobal(currentGlobal),
2419       "Don't call Cu.forcePermissiveCOWs() in a JSM that shares its global");
2420   CompartmentPrivate::Get(currentGlobal)->forcePermissiveCOWs = true;
2421   return NS_OK;
2422 }
2423 
2424 NS_IMETHODIMP
ForcePrivilegedComponentsForScope(HandleValue vscope,JSContext * cx)2425 nsXPCComponents_Utils::ForcePrivilegedComponentsForScope(HandleValue vscope,
2426                                                          JSContext* cx) {
2427   if (!vscope.isObject()) return NS_ERROR_INVALID_ARG;
2428   xpc::CrashIfNotInAutomation();
2429   JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject());
2430   XPCWrappedNativeScope* scope = ObjectScope(scopeObj);
2431   scope->ForcePrivilegedComponents();
2432   return NS_OK;
2433 }
2434 
2435 NS_IMETHODIMP
GetComponentsForScope(HandleValue vscope,JSContext * cx,MutableHandleValue rval)2436 nsXPCComponents_Utils::GetComponentsForScope(HandleValue vscope, JSContext* cx,
2437                                              MutableHandleValue rval) {
2438   if (!vscope.isObject()) return NS_ERROR_INVALID_ARG;
2439   JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject());
2440   XPCWrappedNativeScope* scope = ObjectScope(scopeObj);
2441   RootedObject components(cx);
2442   if (!scope->GetComponentsJSObject(&components)) return NS_ERROR_FAILURE;
2443   if (!JS_WrapObject(cx, &components)) return NS_ERROR_FAILURE;
2444   rval.setObject(*components);
2445   return NS_OK;
2446 }
2447 
2448 NS_IMETHODIMP
Dispatch(HandleValue runnableArg,HandleValue scope,JSContext * cx)2449 nsXPCComponents_Utils::Dispatch(HandleValue runnableArg, HandleValue scope,
2450                                 JSContext* cx) {
2451   RootedValue runnable(cx, runnableArg);
2452   // Enter the given compartment, if any, and rewrap runnable.
2453   Maybe<JSAutoCompartment> ac;
2454   if (scope.isObject()) {
2455     JSObject* scopeObj = js::UncheckedUnwrap(&scope.toObject());
2456     if (!scopeObj) return NS_ERROR_FAILURE;
2457     ac.emplace(cx, scopeObj);
2458     if (!JS_WrapValue(cx, &runnable)) return NS_ERROR_FAILURE;
2459   }
2460 
2461   // Get an XPCWrappedJS for |runnable|.
2462   if (!runnable.isObject()) return NS_ERROR_INVALID_ARG;
2463 
2464   nsCOMPtr<nsIRunnable> run;
2465   nsresult rv = nsXPConnect::XPConnect()->WrapJS(
2466       cx, &runnable.toObject(), NS_GET_IID(nsIRunnable), getter_AddRefs(run));
2467   NS_ENSURE_SUCCESS(rv, rv);
2468   MOZ_ASSERT(run);
2469 
2470   // Dispatch.
2471   return NS_DispatchToMainThread(run);
2472 }
2473 
2474 #define GENERATE_JSCONTEXTOPTION_GETTER_SETTER(_attr, _getter, _setter) \
2475   NS_IMETHODIMP                                                         \
2476   nsXPCComponents_Utils::Get##_attr(JSContext* cx, bool* aValue) {      \
2477     *aValue = ContextOptionsRef(cx)._getter();                          \
2478     return NS_OK;                                                       \
2479   }                                                                     \
2480   NS_IMETHODIMP                                                         \
2481   nsXPCComponents_Utils::Set##_attr(JSContext* cx, bool aValue) {       \
2482     ContextOptionsRef(cx)._setter(aValue);                              \
2483     return NS_OK;                                                       \
2484   }
2485 
GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict,extraWarnings,setExtraWarnings)2486 GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict, extraWarnings, setExtraWarnings)
2487 GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Werror, werror, setWerror)
2488 GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict_mode, strictMode, setStrictMode)
2489 GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Ion, ion, setIon)
2490 
2491 #undef GENERATE_JSCONTEXTOPTION_GETTER_SETTER
2492 
2493 NS_IMETHODIMP
2494 nsXPCComponents_Utils::SetGCZeal(int32_t aValue, JSContext* cx) {
2495 #ifdef JS_GC_ZEAL
2496   JS_SetGCZeal(cx, uint8_t(aValue), JS_DEFAULT_ZEAL_FREQ);
2497 #endif
2498   return NS_OK;
2499 }
2500 
2501 NS_IMETHODIMP
GetIsInAutomation(bool * aResult)2502 nsXPCComponents_Utils::GetIsInAutomation(bool* aResult) {
2503   NS_ENSURE_ARG_POINTER(aResult);
2504 
2505   *aResult = xpc::IsInAutomation();
2506   return NS_OK;
2507 }
2508 
2509 NS_IMETHODIMP
CrashIfNotInAutomation()2510 nsXPCComponents_Utils::CrashIfNotInAutomation() {
2511   xpc::CrashIfNotInAutomation();
2512   return NS_OK;
2513 }
2514 
2515 NS_IMETHODIMP
NukeSandbox(HandleValue obj,JSContext * cx)2516 nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx) {
2517   AUTO_PROFILER_LABEL("nsXPCComponents_Utils::NukeSandbox", JS);
2518   NS_ENSURE_TRUE(obj.isObject(), NS_ERROR_INVALID_ARG);
2519   JSObject* wrapper = &obj.toObject();
2520   NS_ENSURE_TRUE(IsWrapper(wrapper), NS_ERROR_INVALID_ARG);
2521   RootedObject sb(cx, UncheckedUnwrap(wrapper));
2522   NS_ENSURE_TRUE(IsSandbox(sb), NS_ERROR_INVALID_ARG);
2523 
2524   xpc::NukeAllWrappersForCompartment(cx, GetObjectCompartment(sb));
2525 
2526   return NS_OK;
2527 }
2528 
2529 NS_IMETHODIMP
BlockScriptForGlobal(HandleValue globalArg,JSContext * cx)2530 nsXPCComponents_Utils::BlockScriptForGlobal(HandleValue globalArg,
2531                                             JSContext* cx) {
2532   NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
2533   RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
2534                                           /* stopAtWindowProxy = */ false));
2535   NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
2536   if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) {
2537     JS_ReportErrorASCII(cx, "Script may not be disabled for system globals");
2538     return NS_ERROR_FAILURE;
2539   }
2540   Scriptability::Get(global).Block();
2541   return NS_OK;
2542 }
2543 
2544 NS_IMETHODIMP
UnblockScriptForGlobal(HandleValue globalArg,JSContext * cx)2545 nsXPCComponents_Utils::UnblockScriptForGlobal(HandleValue globalArg,
2546                                               JSContext* cx) {
2547   NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
2548   RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
2549                                           /* stopAtWindowProxy = */ false));
2550   NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
2551   if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) {
2552     JS_ReportErrorASCII(cx, "Script may not be disabled for system globals");
2553     return NS_ERROR_FAILURE;
2554   }
2555   Scriptability::Get(global).Unblock();
2556   return NS_OK;
2557 }
2558 
2559 NS_IMETHODIMP
IsXrayWrapper(HandleValue obj,bool * aRetval)2560 nsXPCComponents_Utils::IsXrayWrapper(HandleValue obj, bool* aRetval) {
2561   *aRetval =
2562       obj.isObject() && xpc::WrapperFactory::IsXrayWrapper(&obj.toObject());
2563   return NS_OK;
2564 }
2565 
2566 NS_IMETHODIMP
WaiveXrays(HandleValue aVal,JSContext * aCx,MutableHandleValue aRetval)2567 nsXPCComponents_Utils::WaiveXrays(HandleValue aVal, JSContext* aCx,
2568                                   MutableHandleValue aRetval) {
2569   RootedValue value(aCx, aVal);
2570   if (!xpc::WrapperFactory::WaiveXrayAndWrap(aCx, &value))
2571     return NS_ERROR_FAILURE;
2572   aRetval.set(value);
2573   return NS_OK;
2574 }
2575 
2576 NS_IMETHODIMP
UnwaiveXrays(HandleValue aVal,JSContext * aCx,MutableHandleValue aRetval)2577 nsXPCComponents_Utils::UnwaiveXrays(HandleValue aVal, JSContext* aCx,
2578                                     MutableHandleValue aRetval) {
2579   if (!aVal.isObject()) {
2580     aRetval.set(aVal);
2581     return NS_OK;
2582   }
2583 
2584   RootedObject obj(aCx, js::UncheckedUnwrap(&aVal.toObject()));
2585   if (!JS_WrapObject(aCx, &obj)) return NS_ERROR_FAILURE;
2586   aRetval.setObject(*obj);
2587   return NS_OK;
2588 }
2589 
2590 NS_IMETHODIMP
GetClassName(HandleValue aObj,bool aUnwrap,JSContext * aCx,char ** aRv)2591 nsXPCComponents_Utils::GetClassName(HandleValue aObj, bool aUnwrap,
2592                                     JSContext* aCx, char** aRv) {
2593   if (!aObj.isObject()) return NS_ERROR_INVALID_ARG;
2594   RootedObject obj(aCx, &aObj.toObject());
2595   if (aUnwrap) obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
2596   *aRv = NS_strdup(js::GetObjectClass(obj)->name);
2597   NS_ENSURE_TRUE(*aRv, NS_ERROR_OUT_OF_MEMORY);
2598   return NS_OK;
2599 }
2600 
2601 NS_IMETHODIMP
GetDOMClassInfo(const nsAString & aClassName,nsIClassInfo ** aClassInfo)2602 nsXPCComponents_Utils::GetDOMClassInfo(const nsAString& aClassName,
2603                                        nsIClassInfo** aClassInfo) {
2604   *aClassInfo = nullptr;
2605   return NS_ERROR_NOT_AVAILABLE;
2606 }
2607 
2608 NS_IMETHODIMP
GetIncumbentGlobal(HandleValue aCallback,JSContext * aCx,MutableHandleValue aOut)2609 nsXPCComponents_Utils::GetIncumbentGlobal(HandleValue aCallback, JSContext* aCx,
2610                                           MutableHandleValue aOut) {
2611   nsCOMPtr<nsIGlobalObject> global = mozilla::dom::GetIncumbentGlobal();
2612   RootedValue globalVal(aCx);
2613 
2614   if (!global) {
2615     globalVal = NullValue();
2616   } else {
2617     // Note: We rely on the wrap call for outerization.
2618     globalVal = ObjectValue(*global->GetGlobalJSObject());
2619     if (!JS_WrapValue(aCx, &globalVal)) return NS_ERROR_FAILURE;
2620   }
2621 
2622   // Invoke the callback, if passed.
2623   if (aCallback.isObject()) {
2624     RootedValue ignored(aCx);
2625     if (!JS_CallFunctionValue(aCx, nullptr, aCallback,
2626                               JS::HandleValueArray(globalVal), &ignored))
2627       return NS_ERROR_FAILURE;
2628   }
2629 
2630   aOut.set(globalVal);
2631   return NS_OK;
2632 }
2633 
2634 /*
2635  * Below is a bunch of awkward junk to allow JS test code to trigger the
2636  * creation of an XPCWrappedJS, such that it ends up in the map. We need to
2637  * hand the caller some sort of reference to hold onto (to prevent the
2638  * refcount from dropping to zero as soon as the function returns), but trying
2639  * to return a bonafide XPCWrappedJS to script causes all sorts of trouble. So
2640  * we create a benign holder class instead, which acts as an opaque reference
2641  * that script can use to keep the XPCWrappedJS alive and in the map.
2642  */
2643 
2644 class WrappedJSHolder : public nsISupports {
2645   NS_DECL_ISUPPORTS
WrappedJSHolder()2646   WrappedJSHolder() {}
2647 
2648   RefPtr<nsXPCWrappedJS> mWrappedJS;
2649 
2650  private:
~WrappedJSHolder()2651   virtual ~WrappedJSHolder() {}
2652 };
2653 
2654 NS_IMPL_ADDREF(WrappedJSHolder)
2655 NS_IMPL_RELEASE(WrappedJSHolder)
2656 
2657 // nsINamed is always supported by nsXPCWrappedJSClass.
2658 // We expose this interface only for the identity in telemetry analysis.
2659 NS_INTERFACE_TABLE_HEAD(WrappedJSHolder)
2660   if (aIID.Equals(NS_GET_IID(nsINamed))) {
2661     return mWrappedJS->QueryInterface(aIID, aInstancePtr);
2662   }
NS_INTERFACE_TABLE0(WrappedJSHolder)2663   NS_INTERFACE_TABLE0(WrappedJSHolder)
2664 NS_INTERFACE_TABLE_TAIL
2665 
2666 NS_IMETHODIMP
2667 nsXPCComponents_Utils::GenerateXPCWrappedJS(HandleValue aObj,
2668                                             HandleValue aScope, JSContext* aCx,
2669                                             nsISupports** aOut) {
2670   if (!aObj.isObject()) return NS_ERROR_INVALID_ARG;
2671   RootedObject obj(aCx, &aObj.toObject());
2672   RootedObject scope(aCx, aScope.isObject()
2673                               ? js::UncheckedUnwrap(&aScope.toObject())
2674                               : CurrentGlobalOrNull(aCx));
2675   JSAutoCompartment ac(aCx, scope);
2676   if (!JS_WrapObject(aCx, &obj)) return NS_ERROR_FAILURE;
2677 
2678   RefPtr<WrappedJSHolder> holder = new WrappedJSHolder();
2679   nsresult rv = nsXPCWrappedJS::GetNewOrUsed(
2680       obj, NS_GET_IID(nsISupports), getter_AddRefs(holder->mWrappedJS));
2681   holder.forget(aOut);
2682   return rv;
2683 }
2684 
2685 NS_IMETHODIMP
GetWatchdogTimestamp(const nsAString & aCategory,PRTime * aOut)2686 nsXPCComponents_Utils::GetWatchdogTimestamp(const nsAString& aCategory,
2687                                             PRTime* aOut) {
2688   WatchdogTimestampCategory category;
2689   if (aCategory.EqualsLiteral("ContextStateChange"))
2690     category = TimestampContextStateChange;
2691   else if (aCategory.EqualsLiteral("WatchdogWakeup"))
2692     category = TimestampWatchdogWakeup;
2693   else if (aCategory.EqualsLiteral("WatchdogHibernateStart"))
2694     category = TimestampWatchdogHibernateStart;
2695   else if (aCategory.EqualsLiteral("WatchdogHibernateStop"))
2696     category = TimestampWatchdogHibernateStop;
2697   else
2698     return NS_ERROR_INVALID_ARG;
2699   *aOut = XPCJSContext::Get()->GetWatchdogTimestamp(category);
2700   return NS_OK;
2701 }
2702 
2703 NS_IMETHODIMP
GetJSEngineTelemetryValue(JSContext * cx,MutableHandleValue rval)2704 nsXPCComponents_Utils::GetJSEngineTelemetryValue(JSContext* cx,
2705                                                  MutableHandleValue rval) {
2706   RootedObject obj(cx, JS_NewPlainObject(cx));
2707   if (!obj) return NS_ERROR_OUT_OF_MEMORY;
2708 
2709   // No JS engine telemetry in use at the moment.
2710 
2711   rval.setObject(*obj);
2712   return NS_OK;
2713 }
2714 
CloneInto(JSContext * aCx,HandleValue aValue,HandleValue aScope,HandleValue aOptions,MutableHandleValue aCloned)2715 bool xpc::CloneInto(JSContext* aCx, HandleValue aValue, HandleValue aScope,
2716                     HandleValue aOptions, MutableHandleValue aCloned) {
2717   if (!aScope.isObject()) return false;
2718 
2719   RootedObject scope(aCx, &aScope.toObject());
2720   scope = js::CheckedUnwrap(scope);
2721   if (!scope) {
2722     JS_ReportErrorASCII(aCx, "Permission denied to clone object into scope");
2723     return false;
2724   }
2725 
2726   if (!aOptions.isUndefined() && !aOptions.isObject()) {
2727     JS_ReportErrorASCII(aCx, "Invalid argument");
2728     return false;
2729   }
2730 
2731   RootedObject optionsObject(
2732       aCx, aOptions.isObject() ? &aOptions.toObject() : nullptr);
2733   StackScopedCloneOptions options(aCx, optionsObject);
2734   if (aOptions.isObject() && !options.Parse()) return false;
2735 
2736   {
2737     JSAutoCompartment ac(aCx, scope);
2738     aCloned.set(aValue);
2739     if (!StackScopedClone(aCx, options, aCloned)) return false;
2740   }
2741 
2742   return JS_WrapValue(aCx, aCloned);
2743 }
2744 
2745 NS_IMETHODIMP
CloneInto(HandleValue aValue,HandleValue aScope,HandleValue aOptions,JSContext * aCx,MutableHandleValue aCloned)2746 nsXPCComponents_Utils::CloneInto(HandleValue aValue, HandleValue aScope,
2747                                  HandleValue aOptions, JSContext* aCx,
2748                                  MutableHandleValue aCloned) {
2749   return xpc::CloneInto(aCx, aValue, aScope, aOptions, aCloned)
2750              ? NS_OK
2751              : NS_ERROR_FAILURE;
2752 }
2753 
2754 NS_IMETHODIMP
GetWebIDLCallerPrincipal(nsIPrincipal ** aResult)2755 nsXPCComponents_Utils::GetWebIDLCallerPrincipal(nsIPrincipal** aResult) {
2756   // This API may only be when the Entry Settings Object corresponds to a
2757   // JS-implemented WebIDL call. In all other cases, the value will be null,
2758   // and we throw.
2759   nsCOMPtr<nsIPrincipal> callerPrin = mozilla::dom::GetWebIDLCallerPrincipal();
2760   if (!callerPrin) return NS_ERROR_NOT_AVAILABLE;
2761   callerPrin.forget(aResult);
2762   return NS_OK;
2763 }
2764 
2765 NS_IMETHODIMP
GetObjectPrincipal(HandleValue val,JSContext * cx,nsIPrincipal ** result)2766 nsXPCComponents_Utils::GetObjectPrincipal(HandleValue val, JSContext* cx,
2767                                           nsIPrincipal** result) {
2768   if (!val.isObject()) return NS_ERROR_INVALID_ARG;
2769   RootedObject obj(cx, &val.toObject());
2770   obj = js::CheckedUnwrap(obj);
2771   MOZ_ASSERT(obj);
2772 
2773   nsCOMPtr<nsIPrincipal> prin = nsContentUtils::ObjectPrincipal(obj);
2774   prin.forget(result);
2775   return NS_OK;
2776 }
2777 
2778 NS_IMETHODIMP
GetCompartmentLocation(HandleValue val,JSContext * cx,nsACString & result)2779 nsXPCComponents_Utils::GetCompartmentLocation(HandleValue val, JSContext* cx,
2780                                               nsACString& result) {
2781   if (!val.isObject()) return NS_ERROR_INVALID_ARG;
2782   RootedObject obj(cx, &val.toObject());
2783   obj = js::CheckedUnwrap(obj);
2784   MOZ_ASSERT(obj);
2785 
2786   result = xpc::CompartmentPrivate::Get(obj)->GetLocation();
2787   return NS_OK;
2788 }
2789 
2790 NS_IMETHODIMP
AllowCPOWsInAddon(const nsACString & addonIdStr,bool allow,JSContext * cx)2791 nsXPCComponents_Utils::AllowCPOWsInAddon(const nsACString& addonIdStr,
2792                                          bool allow, JSContext* cx) {
2793   JSAddonId* addonId = xpc::NewAddonId(cx, addonIdStr);
2794   if (!addonId) return NS_ERROR_FAILURE;
2795   if (!XPCWrappedNativeScope::AllowCPOWsInAddon(cx, addonId, allow))
2796     return NS_ERROR_FAILURE;
2797 
2798   return NS_OK;
2799 }
2800 
2801 NS_IMETHODIMP
ReadUTF8File(nsIFile * aFile,nsACString & aResult)2802 nsXPCComponents_Utils::ReadUTF8File(nsIFile* aFile, nsACString& aResult) {
2803   NS_ENSURE_TRUE(aFile, NS_ERROR_INVALID_ARG);
2804 
2805   MOZ_TRY_VAR(aResult, URLPreloader::ReadFile(aFile));
2806   return NS_OK;
2807 }
2808 
2809 NS_IMETHODIMP
ReadUTF8URI(nsIURI * aURI,nsACString & aResult)2810 nsXPCComponents_Utils::ReadUTF8URI(nsIURI* aURI, nsACString& aResult) {
2811   NS_ENSURE_TRUE(aURI, NS_ERROR_INVALID_ARG);
2812 
2813   MOZ_TRY_VAR(aResult, URLPreloader::ReadURI(aURI));
2814   return NS_OK;
2815 }
2816 
2817 NS_IMETHODIMP
Now(double * aRetval)2818 nsXPCComponents_Utils::Now(double* aRetval) {
2819   TimeStamp start = TimeStamp::ProcessCreation();
2820   *aRetval = (TimeStamp::Now() - start).ToMilliseconds();
2821   return NS_OK;
2822 }
2823 
2824 NS_IMETHODIMP
BlockThreadedExecution(nsIBlockThreadedExecutionCallback * aCallback)2825 nsXPCComponents_Utils::BlockThreadedExecution(
2826     nsIBlockThreadedExecutionCallback* aCallback) {
2827   Scheduler::BlockThreadedExecution(aCallback);
2828   return NS_OK;
2829 }
2830 
2831 NS_IMETHODIMP
UnblockThreadedExecution()2832 nsXPCComponents_Utils::UnblockThreadedExecution() {
2833   Scheduler::UnblockThreadedExecution();
2834   return NS_OK;
2835 }
2836 
2837 /***************************************************************************/
2838 /***************************************************************************/
2839 /***************************************************************************/
2840 
nsXPCComponentsBase(XPCWrappedNativeScope * aScope)2841 nsXPCComponentsBase::nsXPCComponentsBase(XPCWrappedNativeScope* aScope)
2842     : mScope(aScope) {
2843   MOZ_ASSERT(aScope, "aScope must not be null");
2844 }
2845 
nsXPCComponents(XPCWrappedNativeScope * aScope)2846 nsXPCComponents::nsXPCComponents(XPCWrappedNativeScope* aScope)
2847     : nsXPCComponentsBase(aScope) {}
2848 
~nsXPCComponentsBase()2849 nsXPCComponentsBase::~nsXPCComponentsBase() {}
2850 
~nsXPCComponents()2851 nsXPCComponents::~nsXPCComponents() {}
2852 
ClearMembers()2853 void nsXPCComponentsBase::ClearMembers() {
2854   mInterfaces = nullptr;
2855   mInterfacesByID = nullptr;
2856   mResults = nullptr;
2857 }
2858 
ClearMembers()2859 void nsXPCComponents::ClearMembers() {
2860   mClasses = nullptr;
2861   mClassesByID = nullptr;
2862   mID = nullptr;
2863   mException = nullptr;
2864   mConstructor = nullptr;
2865   mUtils = nullptr;
2866 
2867   nsXPCComponentsBase::ClearMembers();
2868 }
2869 
2870 /*******************************************/
2871 #define XPC_IMPL_GET_OBJ_METHOD(_class, _n)                      \
2872   NS_IMETHODIMP _class::Get##_n(nsIXPCComponents_##_n** a##_n) { \
2873     NS_ENSURE_ARG_POINTER(a##_n);                                \
2874     if (!m##_n) m##_n = new nsXPCComponents_##_n();              \
2875     RefPtr<nsXPCComponents_##_n> ret = m##_n;                    \
2876     ret.forget(a##_n);                                           \
2877     return NS_OK;                                                \
2878   }
2879 
XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase,Interfaces)2880 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase, Interfaces)
2881 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase, InterfacesByID)
2882 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Classes)
2883 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, ClassesByID)
2884 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase, Results)
2885 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, ID)
2886 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Exception)
2887 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Constructor)
2888 XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Utils)
2889 
2890 #undef XPC_IMPL_GET_OBJ_METHOD
2891 /*******************************************/
2892 
2893 NS_IMETHODIMP
2894 nsXPCComponentsBase::IsSuccessCode(nsresult result, bool* out) {
2895   *out = NS_SUCCEEDED(result);
2896   return NS_OK;
2897 }
2898 
2899 NS_IMETHODIMP
GetStack(nsIStackFrame ** aStack)2900 nsXPCComponents::GetStack(nsIStackFrame** aStack) {
2901   nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
2902   frame.forget(aStack);
2903   return NS_OK;
2904 }
2905 
2906 NS_IMETHODIMP
GetManager(nsIComponentManager ** aManager)2907 nsXPCComponents::GetManager(nsIComponentManager** aManager) {
2908   MOZ_ASSERT(aManager, "bad param");
2909   return NS_GetComponentManager(aManager);
2910 }
2911 
2912 NS_IMETHODIMP
GetReturnCode(JSContext * aCx,MutableHandleValue aOut)2913 nsXPCComponents::GetReturnCode(JSContext* aCx, MutableHandleValue aOut) {
2914   nsresult res = XPCJSContext::Get()->GetPendingResult();
2915   aOut.setNumber(static_cast<uint32_t>(res));
2916   return NS_OK;
2917 }
2918 
2919 NS_IMETHODIMP
SetReturnCode(JSContext * aCx,HandleValue aCode)2920 nsXPCComponents::SetReturnCode(JSContext* aCx, HandleValue aCode) {
2921   nsresult rv;
2922   if (!ToUint32(aCx, aCode, (uint32_t*)&rv)) return NS_ERROR_FAILURE;
2923   XPCJSContext::Get()->SetPendingResult(rv);
2924   return NS_OK;
2925 }
2926 
2927 /**********************************************/
2928 
2929 class ComponentsSH : public nsIXPCScriptable {
2930  public:
ComponentsSH(unsigned dummy)2931   explicit constexpr ComponentsSH(unsigned dummy) {}
2932 
2933   // We don't actually inherit any ref counting infrastructure, but we don't
2934   // need an nsAutoRefCnt member, so the _INHERITED macro is a hack to avoid
2935   // having one.
2936   NS_DECL_ISUPPORTS_INHERITED
2937   NS_DECL_NSIXPCSCRIPTABLE
Get(nsIXPCScriptable ** helper)2938   static nsresult Get(nsIXPCScriptable** helper) {
2939     *helper = &singleton;
2940     return NS_OK;
2941   }
2942 
2943  private:
2944   static ComponentsSH singleton;
2945 };
2946 
2947 ComponentsSH ComponentsSH::singleton(0);
2948 
2949 // Singleton refcounting.
NS_IMETHODIMP_(MozExternalRefCountType)2950 NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::AddRef(void) { return 1; }
NS_IMETHODIMP_(MozExternalRefCountType)2951 NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::Release(void) {
2952   return 1;
2953 }
2954 
NS_IMPL_QUERY_INTERFACE(ComponentsSH,nsIXPCScriptable)2955 NS_IMPL_QUERY_INTERFACE(ComponentsSH, nsIXPCScriptable)
2956 
2957 #define NSXPCCOMPONENTSBASE_CID                      \
2958   {                                                  \
2959     0xc62998e5, 0x95f1, 0x4058, {                    \
2960       0xa5, 0x09, 0xec, 0x21, 0x66, 0x18, 0x92, 0xb9 \
2961     }                                                \
2962   }
2963 
2964 #define NSXPCCOMPONENTS_CID                          \
2965   {                                                  \
2966     0x3649f405, 0xf0ec, 0x4c28, {                    \
2967       0xae, 0xb0, 0xaf, 0x9a, 0x51, 0xe4, 0x4c, 0x81 \
2968     }                                                \
2969   }
2970 
2971 NS_IMPL_CLASSINFO(nsXPCComponentsBase, &ComponentsSH::Get,
2972                   nsIClassInfo::DOM_OBJECT, NSXPCCOMPONENTSBASE_CID)
2973 NS_IMPL_ISUPPORTS_CI(nsXPCComponentsBase, nsIXPCComponentsBase)
2974 
2975 NS_IMPL_CLASSINFO(nsXPCComponents, &ComponentsSH::Get, nsIClassInfo::DOM_OBJECT,
2976                   NSXPCCOMPONENTS_CID)
2977 // Below is more or less what NS_IMPL_ISUPPORTS_CI_INHERITED1 would look like
2978 // if it existed.
2979 NS_IMPL_ADDREF_INHERITED(nsXPCComponents, nsXPCComponentsBase)
2980 NS_IMPL_RELEASE_INHERITED(nsXPCComponents, nsXPCComponentsBase)
2981 NS_INTERFACE_MAP_BEGIN(nsXPCComponents)
2982   NS_INTERFACE_MAP_ENTRY(nsIXPCComponents)
2983   NS_IMPL_QUERY_CLASSINFO(nsXPCComponents)
2984 NS_INTERFACE_MAP_END_INHERITING(nsXPCComponentsBase)
2985 NS_IMPL_CI_INTERFACE_GETTER(nsXPCComponents, nsIXPCComponents)
2986 
2987 // The nsIXPCScriptable map declaration that will generate stubs for us
2988 #define XPC_MAP_CLASSNAME ComponentsSH
2989 #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents"
2990 #define XPC_MAP_FLAGS XPC_SCRIPTABLE_WANT_PRECREATE
2991 #include "xpc_map_end.h" /* This will #undef the above */
2992 
2993 NS_IMETHODIMP
2994 ComponentsSH::PreCreate(nsISupports* nativeObj, JSContext* cx,
2995                         JSObject* globalObj, JSObject** parentObj) {
2996   nsXPCComponentsBase* self = static_cast<nsXPCComponentsBase*>(nativeObj);
2997   // this should never happen
2998   if (!self->GetScope()) {
2999     NS_WARNING(
3000         "mScope must not be null when nsXPCComponents::PreCreate is called");
3001     return NS_ERROR_FAILURE;
3002   }
3003   *parentObj = self->GetScope()->GetGlobalJSObject();
3004   return NS_OK;
3005 }
3006