/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* vim: set ts=8 sts=4 et sw=4 tw=99: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* The "Components" xpcom objects for JavaScript. */ #include "xpcprivate.h" #include "xpc_make_class.h" #include "xpcIJSModuleLoader.h" #include "XPCJSWeakReference.h" #include "WrapperFactory.h" #include "nsJSUtils.h" #include "mozJSComponentLoader.h" #include "nsContentUtils.h" #include "nsCycleCollector.h" #include "jsfriendapi.h" #include "js/StructuredClone.h" #include "mozilla/Attributes.h" #include "mozilla/jsipc/CrossProcessObjectWrappers.h" #include "mozilla/Preferences.h" #include "nsJSEnvironment.h" #include "mozilla/TimeStamp.h" #include "mozilla/XPTInterfaceInfoManager.h" #include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMExceptionBinding.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/StructuredCloneTags.h" #include "mozilla/dom/WindowBinding.h" #include "nsZipArchive.h" #include "nsIDOMFileList.h" #include "nsWindowMemoryReporter.h" #include "nsDOMClassInfo.h" #include "ShimInterfaceInfo.h" #include "nsIAddonInterposition.h" #include "nsISimpleEnumerator.h" #include "nsPIDOMWindow.h" #include "nsGlobalWindow.h" using namespace mozilla; using namespace JS; using namespace js; using namespace xpc; using mozilla::dom::Exception; /***************************************************************************/ // stuff used by all nsresult xpc::ThrowAndFail(nsresult errNum, JSContext* cx, bool* retval) { XPCThrower::Throw(errNum, cx); *retval = false; return NS_OK; } static bool JSValIsInterfaceOfType(JSContext* cx, HandleValue v, REFNSIID iid) { nsCOMPtr<nsIXPConnectWrappedNative> wn; nsCOMPtr<nsISupports> iface; if (v.isPrimitive()) return false; nsXPConnect* xpc = nsXPConnect::XPConnect(); RootedObject obj(cx, &v.toObject()); return NS_SUCCEEDED(xpc->GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wn))) && wn && NS_SUCCEEDED(wn->Native()->QueryInterface(iid, getter_AddRefs(iface))) && iface; } char* xpc::CloneAllAccess() { static const char allAccess[] = "AllAccess"; return (char*)nsMemory::Clone(allAccess, sizeof(allAccess)); } char* xpc::CheckAccessList(const char16_t* wideName, const char* const list[]) { nsAutoCString asciiName; CopyUTF16toUTF8(nsDependentString(wideName), asciiName); for (const char* const* p = list; *p; p++) if (!strcmp(*p, asciiName.get())) return CloneAllAccess(); return nullptr; } /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ class nsXPCComponents_Interfaces final : public nsIXPCComponents_Interfaces, public nsIXPCScriptable, public nsIClassInfo { public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCCOMPONENTS_INTERFACES NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSICLASSINFO public: nsXPCComponents_Interfaces(); private: virtual ~nsXPCComponents_Interfaces(); nsCOMArray<nsIInterfaceInfo> mInterfaces; }; NS_IMETHODIMP nsXPCComponents_Interfaces::GetInterfaces(uint32_t* aCount, nsIID * **aArray) { const uint32_t count = 2; *aCount = count; nsIID** array; *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); if (!array) return NS_ERROR_OUT_OF_MEMORY; uint32_t index = 0; nsIID* clone; #define PUSH_IID(id) \ clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ sizeof(nsIID))); \ if (!clone) \ goto oom; \ array[index++] = clone; PUSH_IID(nsIXPCComponents_Interfaces) PUSH_IID(nsIXPCScriptable) #undef PUSH_IID return NS_OK; oom: while (index) free(array[--index]); free(array); *aArray = nullptr; return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Interfaces::GetScriptableHelper(nsIXPCScriptable** retval) { *retval = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Interfaces::GetContractID(char * *aContractID) { *aContractID = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCComponents_Interfaces::GetClassDescription(char * *aClassDescription) { static const char classDescription[] = "XPCComponents_Interfaces"; *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Interfaces::GetClassID(nsCID * *aClassID) { *aClassID = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Interfaces::GetFlags(uint32_t* aFlags) { // Mark ourselves as a DOM object so that instances may be created in // unprivileged scopes. *aFlags = nsIClassInfo::DOM_OBJECT; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Interfaces::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } nsXPCComponents_Interfaces::nsXPCComponents_Interfaces() { } nsXPCComponents_Interfaces::~nsXPCComponents_Interfaces() { // empty } NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Interfaces) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Interfaces) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Interfaces) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCComponents_Interfaces) NS_IMPL_RELEASE(nsXPCComponents_Interfaces) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCComponents_Interfaces #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Interfaces" #define XPC_MAP_WANT_RESOLVE #define XPC_MAP_WANT_NEWENUMERATE #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, bool* _retval) { // Lazily init the list of interfaces when someone tries to // enumerate them. if (mInterfaces.IsEmpty()) { XPTInterfaceInfoManager::GetSingleton()-> GetScriptableInterfaces(mInterfaces); } if (!properties.reserve(mInterfaces.Length())) { *_retval = false; return NS_OK; } for (uint32_t index = 0; index < mInterfaces.Length(); index++) { nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(index); if (!interface) continue; const char* name; if (NS_SUCCEEDED(interface->GetNameShared(&name)) && name) { RootedString idstr(cx, JS_NewStringCopyZ(cx, name)); if (!idstr) { *_retval = false; return NS_OK; } RootedId id(cx); if (!JS_StringToId(cx, idstr, &id)) { *_retval = false; return NS_OK; } properties.infallibleAppend(id); } } return NS_OK; } NS_IMETHODIMP nsXPCComponents_Interfaces::Resolve(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, jsid idArg, bool* resolvedp, bool* _retval) { RootedObject obj(cx, objArg); RootedId id(cx, idArg); if (!JSID_IS_STRING(id)) return NS_OK; JSAutoByteString name; RootedString str(cx, JSID_TO_STRING(id)); // we only allow interfaces by name here if (name.encodeLatin1(cx, str) && name.ptr()[0] != '{') { nsCOMPtr<nsIInterfaceInfo> info = ShimInterfaceInfo::MaybeConstruct(name.ptr(), cx); if (!info) { XPTInterfaceInfoManager::GetSingleton()-> GetInfoForName(name.ptr(), getter_AddRefs(info)); } if (!info) return NS_OK; nsCOMPtr<nsIJSIID> nsid = nsJSIID::NewID(info); if (nsid) { nsXPConnect* xpc = nsXPConnect::XPConnect(); RootedObject idobj(cx); if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, static_cast<nsIJSIID*>(nsid), NS_GET_IID(nsIJSIID), idobj.address()))) { if (idobj) { *resolvedp = true; *_retval = JS_DefinePropertyById(cx, obj, id, idobj, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING); } } } } return NS_OK; } /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ class nsXPCComponents_InterfacesByID final : public nsIXPCComponents_InterfacesByID, public nsIXPCScriptable, public nsIClassInfo { public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCCOMPONENTS_INTERFACESBYID NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSICLASSINFO public: nsXPCComponents_InterfacesByID(); private: virtual ~nsXPCComponents_InterfacesByID(); nsCOMArray<nsIInterfaceInfo> mInterfaces; }; /***************************************************************************/ NS_IMETHODIMP nsXPCComponents_InterfacesByID::GetInterfaces(uint32_t* aCount, nsIID * **aArray) { const uint32_t count = 2; *aCount = count; nsIID** array; *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); if (!array) return NS_ERROR_OUT_OF_MEMORY; uint32_t index = 0; nsIID* clone; #define PUSH_IID(id) \ clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ sizeof(nsIID))); \ if (!clone) \ goto oom; \ array[index++] = clone; PUSH_IID(nsIXPCComponents_InterfacesByID) PUSH_IID(nsIXPCScriptable) #undef PUSH_IID return NS_OK; oom: while (index) free(array[--index]); free(array); *aArray = nullptr; return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_InterfacesByID::GetScriptableHelper(nsIXPCScriptable** retval) { *retval = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_InterfacesByID::GetContractID(char * *aContractID) { *aContractID = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCComponents_InterfacesByID::GetClassDescription(char * *aClassDescription) { static const char classDescription[] = "XPCComponents_InterfacesByID"; *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_InterfacesByID::GetClassID(nsCID * *aClassID) { *aClassID = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_InterfacesByID::GetFlags(uint32_t* aFlags) { // Mark ourselves as a DOM object so that instances may be created in // unprivileged scopes. *aFlags = nsIClassInfo::DOM_OBJECT; return NS_OK; } NS_IMETHODIMP nsXPCComponents_InterfacesByID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } nsXPCComponents_InterfacesByID::nsXPCComponents_InterfacesByID() { } nsXPCComponents_InterfacesByID::~nsXPCComponents_InterfacesByID() { // empty } NS_INTERFACE_MAP_BEGIN(nsXPCComponents_InterfacesByID) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_InterfacesByID) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_InterfacesByID) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCComponents_InterfacesByID) NS_IMPL_RELEASE(nsXPCComponents_InterfacesByID) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCComponents_InterfacesByID #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_InterfacesByID" #define XPC_MAP_WANT_RESOLVE #define XPC_MAP_WANT_NEWENUMERATE #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCComponents_InterfacesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, bool* _retval) { if (mInterfaces.IsEmpty()) { XPTInterfaceInfoManager::GetSingleton()-> GetScriptableInterfaces(mInterfaces); } if (!properties.reserve(mInterfaces.Length())) { *_retval = false; return NS_OK; } for (uint32_t index = 0; index < mInterfaces.Length(); index++) { nsIInterfaceInfo* interface = mInterfaces.SafeElementAt(index); if (!interface) continue; nsIID const* iid; if (NS_SUCCEEDED(interface->GetIIDShared(&iid))) { char idstr[NSID_LENGTH]; iid->ToProvidedString(idstr); RootedString jsstr(cx, JS_NewStringCopyZ(cx, idstr)); if (!jsstr) { *_retval = false; return NS_OK; } RootedId id(cx); if (!JS_StringToId(cx, jsstr, &id)) { *_retval = false; return NS_OK; } properties.infallibleAppend(id); } } return NS_OK; } NS_IMETHODIMP nsXPCComponents_InterfacesByID::Resolve(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, jsid idArg, bool* resolvedp, bool* _retval) { RootedObject obj(cx, objArg); RootedId id(cx, idArg); if (!JSID_IS_STRING(id)) return NS_OK; RootedString str(cx, JSID_TO_STRING(id)); if (38 != JS_GetStringLength(str)) return NS_OK; JSAutoByteString utf8str; if (utf8str.encodeUtf8(cx, str)) { nsID iid; if (!iid.Parse(utf8str.ptr())) return NS_OK; nsCOMPtr<nsIInterfaceInfo> info; XPTInterfaceInfoManager::GetSingleton()-> GetInfoForIID(&iid, getter_AddRefs(info)); if (!info) return NS_OK; nsCOMPtr<nsIJSIID> nsid = nsJSIID::NewID(info); if (!nsid) return NS_ERROR_OUT_OF_MEMORY; nsXPConnect* xpc = nsXPConnect::XPConnect(); RootedObject idobj(cx); if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, static_cast<nsIJSIID*>(nsid), NS_GET_IID(nsIJSIID), idobj.address()))) { if (idobj) { *resolvedp = true; *_retval = JS_DefinePropertyById(cx, obj, id, idobj, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING); } } } return NS_OK; } /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ class nsXPCComponents_Classes final : public nsIXPCComponents_Classes, public nsIXPCScriptable, public nsIClassInfo { public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCCOMPONENTS_CLASSES NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSICLASSINFO public: nsXPCComponents_Classes(); private: virtual ~nsXPCComponents_Classes(); }; /***************************************************************************/ NS_IMETHODIMP nsXPCComponents_Classes::GetInterfaces(uint32_t* aCount, nsIID * **aArray) { const uint32_t count = 2; *aCount = count; nsIID** array; *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); if (!array) return NS_ERROR_OUT_OF_MEMORY; uint32_t index = 0; nsIID* clone; #define PUSH_IID(id) \ clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ sizeof(nsIID))); \ if (!clone) \ goto oom; \ array[index++] = clone; PUSH_IID(nsIXPCComponents_Classes) PUSH_IID(nsIXPCScriptable) #undef PUSH_IID return NS_OK; oom: while (index) free(array[--index]); free(array); *aArray = nullptr; return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Classes::GetScriptableHelper(nsIXPCScriptable** retval) { *retval = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Classes::GetContractID(char * *aContractID) { *aContractID = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCComponents_Classes::GetClassDescription(char * *aClassDescription) { static const char classDescription[] = "XPCComponents_Classes"; *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Classes::GetClassID(nsCID * *aClassID) { *aClassID = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Classes::GetFlags(uint32_t* aFlags) { *aFlags = 0; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Classes::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } nsXPCComponents_Classes::nsXPCComponents_Classes() { } nsXPCComponents_Classes::~nsXPCComponents_Classes() { // empty } NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Classes) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Classes) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Classes) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCComponents_Classes) NS_IMPL_RELEASE(nsXPCComponents_Classes) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCComponents_Classes #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Classes" #define XPC_MAP_WANT_RESOLVE #define XPC_MAP_WANT_NEWENUMERATE #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, bool* _retval) { nsCOMPtr<nsIComponentRegistrar> compMgr; if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr) return NS_ERROR_UNEXPECTED; nsCOMPtr<nsISimpleEnumerator> e; if (NS_FAILED(compMgr->EnumerateContractIDs(getter_AddRefs(e))) || !e) return NS_ERROR_UNEXPECTED; bool hasMore; nsCOMPtr<nsISupports> isup; while(NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore && NS_SUCCEEDED(e->GetNext(getter_AddRefs(isup))) && isup) { nsCOMPtr<nsISupportsCString> holder(do_QueryInterface(isup)); if (!holder) continue; nsAutoCString name; if (NS_SUCCEEDED(holder->GetData(name))) { RootedString idstr(cx, JS_NewStringCopyN(cx, name.get(), name.Length())); if (!idstr) { *_retval = false; return NS_OK; } RootedId id(cx); if (!JS_StringToId(cx, idstr, &id)) { *_retval = false; return NS_OK; } if (!properties.append(id)) { *_retval = false; return NS_OK; } } } return NS_OK; } NS_IMETHODIMP nsXPCComponents_Classes::Resolve(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, jsid idArg, bool* resolvedp, bool* _retval) { RootedId id(cx, idArg); RootedObject obj(cx, objArg); JSAutoByteString name; if (JSID_IS_STRING(id) && name.encodeLatin1(cx, JSID_TO_STRING(id)) && name.ptr()[0] != '{') { // we only allow contractids here nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.ptr()); if (nsid) { nsXPConnect* xpc = nsXPConnect::XPConnect(); RootedObject idobj(cx); if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, static_cast<nsIJSCID*>(nsid), NS_GET_IID(nsIJSCID), idobj.address()))) { if (idobj) { *resolvedp = true; *_retval = JS_DefinePropertyById(cx, obj, id, idobj, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING); } } } } return NS_OK; } /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ class nsXPCComponents_ClassesByID final : public nsIXPCComponents_ClassesByID, public nsIXPCScriptable, public nsIClassInfo { public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCCOMPONENTS_CLASSESBYID NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSICLASSINFO public: nsXPCComponents_ClassesByID(); private: virtual ~nsXPCComponents_ClassesByID(); }; /***************************************************************************/ NS_IMETHODIMP nsXPCComponents_ClassesByID::GetInterfaces(uint32_t* aCount, nsIID * **aArray) { const uint32_t count = 2; *aCount = count; nsIID** array; *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); if (!array) return NS_ERROR_OUT_OF_MEMORY; uint32_t index = 0; nsIID* clone; #define PUSH_IID(id) \ clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ sizeof(nsIID))); \ if (!clone) \ goto oom; \ array[index++] = clone; PUSH_IID(nsIXPCComponents_ClassesByID) PUSH_IID(nsIXPCScriptable) #undef PUSH_IID return NS_OK; oom: while (index) free(array[--index]); free(array); *aArray = nullptr; return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_ClassesByID::GetScriptableHelper(nsIXPCScriptable** retval) { *retval = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_ClassesByID::GetContractID(char * *aContractID) { *aContractID = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCComponents_ClassesByID::GetClassDescription(char * *aClassDescription) { static const char classDescription[] = "XPCComponents_ClassesByID"; *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_ClassesByID::GetClassID(nsCID * *aClassID) { *aClassID = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_ClassesByID::GetFlags(uint32_t* aFlags) { *aFlags = 0; return NS_OK; } NS_IMETHODIMP nsXPCComponents_ClassesByID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } nsXPCComponents_ClassesByID::nsXPCComponents_ClassesByID() { } nsXPCComponents_ClassesByID::~nsXPCComponents_ClassesByID() { // empty } NS_INTERFACE_MAP_BEGIN(nsXPCComponents_ClassesByID) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_ClassesByID) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_ClassesByID) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCComponents_ClassesByID) NS_IMPL_RELEASE(nsXPCComponents_ClassesByID) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCComponents_ClassesByID #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_ClassesByID" #define XPC_MAP_WANT_RESOLVE #define XPC_MAP_WANT_NEWENUMERATE #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCComponents_ClassesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, bool* _retval) { nsCOMPtr<nsIComponentRegistrar> compMgr; if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr) return NS_ERROR_UNEXPECTED; nsISimpleEnumerator* e; if (NS_FAILED(compMgr->EnumerateCIDs(&e)) || !e) return NS_ERROR_UNEXPECTED; bool hasMore; nsCOMPtr<nsISupports> isup; while(NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore && NS_SUCCEEDED(e->GetNext(getter_AddRefs(isup))) && isup) { nsCOMPtr<nsISupportsID> holder(do_QueryInterface(isup)); if (!holder) continue; char* name; if (NS_SUCCEEDED(holder->ToString(&name)) && name) { RootedString idstr(cx, JS_NewStringCopyZ(cx, name)); if (!idstr) { *_retval = false; return NS_OK; } RootedId id(cx); if (!JS_StringToId(cx, idstr, &id)) { *_retval = false; return NS_OK; } if (!properties.append(id)) { *_retval = false; return NS_OK; } } } return NS_OK; } static bool IsRegisteredCLSID(const char* str) { bool registered; nsID id; if (!id.Parse(str)) return false; nsCOMPtr<nsIComponentRegistrar> compMgr; if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr || NS_FAILED(compMgr->IsCIDRegistered(id, ®istered))) return false; return registered; } NS_IMETHODIMP nsXPCComponents_ClassesByID::Resolve(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, jsid idArg, bool* resolvedp, bool* _retval) { RootedObject obj(cx, objArg); RootedId id(cx, idArg); if (!JSID_IS_STRING(id)) return NS_OK; JSAutoByteString name; RootedString str(cx, JSID_TO_STRING(id)); if (name.encodeLatin1(cx, str) && name.ptr()[0] == '{' && IsRegisteredCLSID(name.ptr())) // we only allow canonical CLSIDs here { nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.ptr()); if (nsid) { nsXPConnect* xpc = nsXPConnect::XPConnect(); RootedObject idobj(cx); if (NS_SUCCEEDED(xpc->WrapNative(cx, obj, static_cast<nsIJSCID*>(nsid), NS_GET_IID(nsIJSCID), idobj.address()))) { if (idobj) { *resolvedp = true; *_retval = JS_DefinePropertyById(cx, obj, id, idobj, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING); } } } } return NS_OK; } /***************************************************************************/ // Currently the possible results do not change at runtime, so they are only // cached once (unlike ContractIDs, CLSIDs, and IIDs) class nsXPCComponents_Results final : public nsIXPCComponents_Results, public nsIXPCScriptable, public nsIClassInfo { public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCCOMPONENTS_RESULTS NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSICLASSINFO public: nsXPCComponents_Results(); private: virtual ~nsXPCComponents_Results(); }; /***************************************************************************/ NS_IMETHODIMP nsXPCComponents_Results::GetInterfaces(uint32_t* aCount, nsIID * **aArray) { const uint32_t count = 2; *aCount = count; nsIID** array; *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); if (!array) return NS_ERROR_OUT_OF_MEMORY; uint32_t index = 0; nsIID* clone; #define PUSH_IID(id) \ clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ sizeof(nsIID))); \ if (!clone) \ goto oom; \ array[index++] = clone; PUSH_IID(nsIXPCComponents_Results) PUSH_IID(nsIXPCScriptable) #undef PUSH_IID return NS_OK; oom: while (index) free(array[--index]); free(array); *aArray = nullptr; return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Results::GetScriptableHelper(nsIXPCScriptable** retval) { *retval = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Results::GetContractID(char * *aContractID) { *aContractID = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCComponents_Results::GetClassDescription(char * *aClassDescription) { static const char classDescription[] = "XPCComponents_Results"; *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Results::GetClassID(nsCID * *aClassID) { *aClassID = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Results::GetFlags(uint32_t* aFlags) { // Mark ourselves as a DOM object so that instances may be created in // unprivileged scopes. *aFlags = nsIClassInfo::DOM_OBJECT; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Results::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } nsXPCComponents_Results::nsXPCComponents_Results() { } nsXPCComponents_Results::~nsXPCComponents_Results() { // empty } NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Results) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Results) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Results) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCComponents_Results) NS_IMPL_RELEASE(nsXPCComponents_Results) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCComponents_Results #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Results" #define XPC_MAP_WANT_RESOLVE #define XPC_MAP_WANT_NEWENUMERATE #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, bool* _retval) { const char* name; const void* iter = nullptr; while (nsXPCException::IterateNSResults(nullptr, &name, nullptr, &iter)) { RootedString idstr(cx, JS_NewStringCopyZ(cx, name)); if (!idstr) { *_retval = false; return NS_OK; } RootedId id(cx); if (!JS_StringToId(cx, idstr, &id)) { *_retval = false; return NS_OK; } if (!properties.append(id)) { *_retval = false; return NS_OK; } } return NS_OK; } NS_IMETHODIMP nsXPCComponents_Results::Resolve(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, jsid idArg, bool* resolvedp, bool* _retval) { RootedObject obj(cx, objArg); RootedId id(cx, idArg); JSAutoByteString name; if (JSID_IS_STRING(id) && name.encodeLatin1(cx, JSID_TO_STRING(id))) { const char* rv_name; const void* iter = nullptr; nsresult rv; while (nsXPCException::IterateNSResults(&rv, &rv_name, nullptr, &iter)) { if (!strcmp(name.ptr(), rv_name)) { *resolvedp = true; if (!JS_DefinePropertyById(cx, obj, id, (uint32_t)rv, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING)) { return NS_ERROR_UNEXPECTED; } } } } return NS_OK; } /***************************************************************************/ // JavaScript Constructor for nsIJSID objects (Components.ID) class nsXPCComponents_ID final : public nsIXPCComponents_ID, public nsIXPCScriptable, public nsIClassInfo { public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCCOMPONENTS_ID NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSICLASSINFO public: nsXPCComponents_ID(); private: virtual ~nsXPCComponents_ID(); static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj, const CallArgs& args, bool* _retval); }; /***************************************************************************/ NS_IMETHODIMP nsXPCComponents_ID::GetInterfaces(uint32_t* aCount, nsIID * **aArray) { const uint32_t count = 2; *aCount = count; nsIID** array; *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); if (!array) return NS_ERROR_OUT_OF_MEMORY; uint32_t index = 0; nsIID* clone; #define PUSH_IID(id) \ clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ sizeof(nsIID))); \ if (!clone) \ goto oom; \ array[index++] = clone; PUSH_IID(nsIXPCComponents_ID) PUSH_IID(nsIXPCScriptable) #undef PUSH_IID return NS_OK; oom: while (index) free(array[--index]); free(array); *aArray = nullptr; return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_ID::GetScriptableHelper(nsIXPCScriptable** retval) { *retval = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_ID::GetContractID(char * *aContractID) { *aContractID = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCComponents_ID::GetClassDescription(char * *aClassDescription) { static const char classDescription[] = "XPCComponents_ID"; *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_ID::GetClassID(nsCID * *aClassID) { *aClassID = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_ID::GetFlags(uint32_t* aFlags) { *aFlags = 0; return NS_OK; } NS_IMETHODIMP nsXPCComponents_ID::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } nsXPCComponents_ID::nsXPCComponents_ID() { } nsXPCComponents_ID::~nsXPCComponents_ID() { // empty } NS_INTERFACE_MAP_BEGIN(nsXPCComponents_ID) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_ID) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_ID) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCComponents_ID) NS_IMPL_RELEASE(nsXPCComponents_ID) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCComponents_ID #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_ID" #define XPC_MAP_WANT_CALL #define XPC_MAP_WANT_CONSTRUCT #define XPC_MAP_WANT_HASINSTANCE #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCComponents_ID::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, const CallArgs& args, bool* _retval) { RootedObject obj(cx, objArg); return CallOrConstruct(wrapper, cx, obj, args, _retval); } NS_IMETHODIMP nsXPCComponents_ID::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, const CallArgs& args, bool* _retval) { RootedObject obj(cx, objArg); return CallOrConstruct(wrapper, cx, obj, args, _retval); } // static nsresult nsXPCComponents_ID::CallOrConstruct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj, const CallArgs& args, bool* _retval) { // make sure we have at least one arg if (args.length() < 1) return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval); // Do the security check if necessary if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(cx, nsJSID::GetCID()))) { // the security manager vetoed. It should have set an exception. *_retval = false; return NS_OK; } // convert the first argument into a string and see if it looks like an id JSString* jsstr; JSAutoByteString bytes; nsID id; if (!(jsstr = ToString(cx, args[0])) || !bytes.encodeLatin1(cx, jsstr) || !id.Parse(bytes.ptr())) { return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval); } // make the new object and return it. JSObject* newobj = xpc_NewIDObject(cx, obj, id); if (!newobj) return NS_ERROR_UNEXPECTED; args.rval().setObject(*newobj); return NS_OK; } NS_IMETHODIMP nsXPCComponents_ID::HasInstance(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, HandleValue val, bool* bp, bool* _retval) { if (bp) *bp = JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIJSID)); return NS_OK; } /***************************************************************************/ // JavaScript Constructor for nsIXPCException objects (Components.Exception) class nsXPCComponents_Exception final : public nsIXPCComponents_Exception, public nsIXPCScriptable, public nsIClassInfo { public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCCOMPONENTS_EXCEPTION NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSICLASSINFO public: nsXPCComponents_Exception(); private: virtual ~nsXPCComponents_Exception(); static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj, const CallArgs& args, bool* _retval); }; /***************************************************************************/ NS_IMETHODIMP nsXPCComponents_Exception::GetInterfaces(uint32_t* aCount, nsIID * **aArray) { const uint32_t count = 2; *aCount = count; nsIID** array; *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); if (!array) return NS_ERROR_OUT_OF_MEMORY; uint32_t index = 0; nsIID* clone; #define PUSH_IID(id) \ clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ sizeof(nsIID))); \ if (!clone) \ goto oom; \ array[index++] = clone; PUSH_IID(nsIXPCComponents_Exception) PUSH_IID(nsIXPCScriptable) #undef PUSH_IID return NS_OK; oom: while (index) free(array[--index]); free(array); *aArray = nullptr; return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Exception::GetScriptableHelper(nsIXPCScriptable** retval) { *retval = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Exception::GetContractID(char * *aContractID) { *aContractID = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCComponents_Exception::GetClassDescription(char * *aClassDescription) { static const char classDescription[] = "XPCComponents_Exception"; *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Exception::GetClassID(nsCID * *aClassID) { *aClassID = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Exception::GetFlags(uint32_t* aFlags) { *aFlags = 0; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Exception::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } nsXPCComponents_Exception::nsXPCComponents_Exception() { } nsXPCComponents_Exception::~nsXPCComponents_Exception() { // empty } NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Exception) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Exception) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Exception) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCComponents_Exception) NS_IMPL_RELEASE(nsXPCComponents_Exception) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCComponents_Exception #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Exception" #define XPC_MAP_WANT_CALL #define XPC_MAP_WANT_CONSTRUCT #define XPC_MAP_WANT_HASINSTANCE #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCComponents_Exception::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, const CallArgs& args, bool* _retval) { RootedObject obj(cx, objArg); return CallOrConstruct(wrapper, cx, obj, args, _retval); } NS_IMETHODIMP nsXPCComponents_Exception::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, const CallArgs& args, bool* _retval) { RootedObject obj(cx, objArg); return CallOrConstruct(wrapper, cx, obj, args, _retval); } struct MOZ_STACK_CLASS ExceptionArgParser { ExceptionArgParser(JSContext* context, nsXPConnect* xpconnect) : eMsg("exception") , eResult(NS_ERROR_FAILURE) , cx(context) , xpc(xpconnect) {} // Public exception parameter values. During construction, these are // initialized to the appropriate defaults. const char* eMsg; nsresult eResult; nsCOMPtr<nsIStackFrame> eStack; nsCOMPtr<nsISupports> eData; // Parse the constructor arguments into the above |eFoo| parameter values. bool parse(const CallArgs& args) { /* * The Components.Exception takes a series of arguments, all of them * optional: * * Argument 0: Exception message (defaults to 'exception'). * Argument 1: Result code (defaults to NS_ERROR_FAILURE) _or_ options * object (see below). * Argument 2: Stack (defaults to the current stack, which we trigger * by leaving this nullptr in the parser). * Argument 3: Optional user data (defaults to nullptr). * * To dig our way out of this clunky API, we now support passing an * options object as the second parameter (as opposed to a result code). * If this is the case, all subsequent arguments are ignored, and the * following properties are parsed out of the object (using the * associated default if the property does not exist): * * result: Result code (see argument 1). * stack: Call stack (see argument 2). * data: User data (see argument 3). */ if (args.length() > 0 && !parseMessage(args[0])) return false; if (args.length() > 1) { if (args[1].isObject()) { RootedObject obj(cx, &args[1].toObject()); return parseOptionsObject(obj); } if (!parseResult(args[1])) return false; } if (args.length() > 2) { if (!parseStack(args[2])) return false; } if (args.length() > 3) { if (!parseData(args[3])) return false; } return true; } protected: /* * Parsing helpers. */ bool parseMessage(HandleValue v) { JSString* str = ToString(cx, v); if (!str) return false; eMsg = messageBytes.encodeLatin1(cx, str); return !!eMsg; } bool parseResult(HandleValue v) { return JS::ToUint32(cx, v, (uint32_t*) &eResult); } bool parseStack(HandleValue v) { if (!v.isObject()) { // eStack has already been initialized to null, which is what we want // for any non-object values (including null). return true; } return NS_SUCCEEDED(xpc->WrapJS(cx, &v.toObject(), NS_GET_IID(nsIStackFrame), getter_AddRefs(eStack))); } bool parseData(HandleValue v) { if (!v.isObject()) { // eData has already been initialized to null, which is what we want // for any non-object values (including null). return true; } return NS_SUCCEEDED(xpc->WrapJS(cx, &v.toObject(), NS_GET_IID(nsISupports), getter_AddRefs(eData))); } bool parseOptionsObject(HandleObject obj) { RootedValue v(cx); if (!getOption(obj, "result", &v) || (!v.isUndefined() && !parseResult(v))) return false; if (!getOption(obj, "stack", &v) || (!v.isUndefined() && !parseStack(v))) return false; if (!getOption(obj, "data", &v) || (!v.isUndefined() && !parseData(v))) return false; return true; } bool getOption(HandleObject obj, const char* name, MutableHandleValue rv) { // Look for the property. bool found; if (!JS_HasProperty(cx, obj, name, &found)) return false; // If it wasn't found, indicate with undefined. if (!found) { rv.setUndefined(); return true; } // Get the property. return JS_GetProperty(cx, obj, name, rv); } /* * Internal data members. */ // If there's a non-default exception string, hold onto the allocated bytes. JSAutoByteString messageBytes; // Various bits and pieces that are helpful to have around. JSContext* cx; nsXPConnect* xpc; }; // static nsresult nsXPCComponents_Exception::CallOrConstruct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj, const CallArgs& args, bool* _retval) { nsXPConnect* xpc = nsXPConnect::XPConnect(); // Do the security check if necessary if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(cx, Exception::GetCID()))) { // the security manager vetoed. It should have set an exception. *_retval = false; return NS_OK; } // Parse the arguments to the Exception constructor. ExceptionArgParser parser(cx, xpc); if (!parser.parse(args)) return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); nsCOMPtr<nsIException> e = new Exception(nsCString(parser.eMsg), parser.eResult, EmptyCString(), parser.eStack, parser.eData); RootedObject newObj(cx); if (NS_FAILED(xpc->WrapNative(cx, obj, e, NS_GET_IID(nsIXPCException), newObj.address())) || !newObj) { return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval); } args.rval().setObject(*newObj); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative* wrapper, JSContext * cx, JSObject * obj, HandleValue val, bool* bp, bool* _retval) { using namespace mozilla::dom; if (bp) { *bp = (val.isObject() && IS_INSTANCE_OF(Exception, &val.toObject())) || JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIException)); } return NS_OK; } /***************************************************************************/ // This class is for the thing returned by "new Component.Constructor". // XXXjband we use this CID for security check, but security system can't see // it since it has no registed factory. Security really kicks in when we try // to build a wrapper around an instance. // {B4A95150-E25A-11d3-8F61-0010A4E73D9A} #define NS_XPCCONSTRUCTOR_CID \ { 0xb4a95150, 0xe25a, 0x11d3, \ { 0x8f, 0x61, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a } } class nsXPCConstructor : public nsIXPCConstructor, public nsIXPCScriptable, public nsIClassInfo { public: NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCCONSTRUCTOR_CID) public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCCONSTRUCTOR NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSICLASSINFO public: nsXPCConstructor() = delete; nsXPCConstructor(nsIJSCID* aClassID, nsIJSIID* aInterfaceID, const char* aInitializer); private: virtual ~nsXPCConstructor(); nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj, const CallArgs& args, bool* _retval); private: RefPtr<nsIJSCID> mClassID; RefPtr<nsIJSIID> mInterfaceID; char* mInitializer; }; /***************************************************************************/ NS_IMETHODIMP nsXPCConstructor::GetInterfaces(uint32_t* aCount, nsIID * **aArray) { const uint32_t count = 2; *aCount = count; nsIID** array; *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); if (!array) return NS_ERROR_OUT_OF_MEMORY; uint32_t index = 0; nsIID* clone; #define PUSH_IID(id) \ clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ sizeof(nsIID))); \ if (!clone) \ goto oom; \ array[index++] = clone; PUSH_IID(nsIXPCConstructor) PUSH_IID(nsIXPCScriptable) #undef PUSH_IID return NS_OK; oom: while (index) free(array[--index]); free(array); *aArray = nullptr; return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCConstructor::GetScriptableHelper(nsIXPCScriptable** retval) { *retval = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCConstructor::GetContractID(char * *aContractID) { *aContractID = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCConstructor::GetClassDescription(char * *aClassDescription) { static const char classDescription[] = "XPCConstructor"; *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCConstructor::GetClassID(nsCID * *aClassID) { *aClassID = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCConstructor::GetFlags(uint32_t* aFlags) { *aFlags = 0; return NS_OK; } NS_IMETHODIMP nsXPCConstructor::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } nsXPCConstructor::nsXPCConstructor(nsIJSCID* aClassID, nsIJSIID* aInterfaceID, const char* aInitializer) : mClassID(aClassID), mInterfaceID(aInterfaceID) { mInitializer = aInitializer ? (char*) nsMemory::Clone(aInitializer, strlen(aInitializer)+1) : nullptr; } nsXPCConstructor::~nsXPCConstructor() { if (mInitializer) free(mInitializer); } NS_IMETHODIMP nsXPCConstructor::GetClassID(nsIJSCID * *aClassID) { RefPtr<nsIJSCID> rval = mClassID; rval.forget(aClassID); return NS_OK; } NS_IMETHODIMP nsXPCConstructor::GetInterfaceID(nsIJSIID * *aInterfaceID) { RefPtr<nsIJSIID> rval = mInterfaceID; rval.forget(aInterfaceID); return NS_OK; } NS_IMETHODIMP nsXPCConstructor::GetInitializer(char * *aInitializer) { XPC_STRING_GETTER_BODY(aInitializer, mInitializer); } NS_INTERFACE_MAP_BEGIN(nsXPCConstructor) NS_INTERFACE_MAP_ENTRY(nsIXPCConstructor) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCConstructor) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCConstructor) NS_IMPL_RELEASE(nsXPCConstructor) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCConstructor #define XPC_MAP_QUOTED_CLASSNAME "nsXPCConstructor" #define XPC_MAP_WANT_CALL #define XPC_MAP_WANT_CONSTRUCT #define XPC_MAP_FLAGS 0 #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCConstructor::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, const CallArgs& args, bool* _retval) { RootedObject obj(cx, objArg); return CallOrConstruct(wrapper, cx, obj, args, _retval); } NS_IMETHODIMP nsXPCConstructor::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, const CallArgs& args, bool* _retval) { RootedObject obj(cx, objArg); return CallOrConstruct(wrapper, cx, obj, args, _retval); } // static nsresult nsXPCConstructor::CallOrConstruct(nsIXPConnectWrappedNative* wrapper,JSContext* cx, HandleObject obj, const CallArgs& args, bool* _retval) { nsXPConnect* xpc = nsXPConnect::XPConnect(); // security check not required because we are going to call through the // code which is reflected into JS which will do that for us later. RootedObject cidObj(cx); RootedObject iidObj(cx); if (NS_FAILED(xpc->WrapNative(cx, obj, mClassID, NS_GET_IID(nsIJSCID), cidObj.address())) || !cidObj || NS_FAILED(xpc->WrapNative(cx, obj, mInterfaceID, NS_GET_IID(nsIJSIID), iidObj.address())) || !iidObj) { return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval); } JS::Rooted<JS::Value> arg(cx, ObjectValue(*iidObj)); RootedValue rval(cx); if (!JS_CallFunctionName(cx, cidObj, "createInstance", JS::HandleValueArray(arg), &rval) || rval.isPrimitive()) { // createInstance will have thrown an exception *_retval = false; return NS_OK; } args.rval().set(rval); // call initializer method if supplied if (mInitializer) { RootedObject newObj(cx, &rval.toObject()); // first check existence of function property for better error reporting RootedValue fun(cx); if (!JS_GetProperty(cx, newObj, mInitializer, &fun) || fun.isPrimitive()) { return ThrowAndFail(NS_ERROR_XPC_BAD_INITIALIZER_NAME, cx, _retval); } RootedValue dummy(cx); if (!JS_CallFunctionValue(cx, newObj, fun, args, &dummy)) { // function should have thrown an exception *_retval = false; return NS_OK; } } return NS_OK; } /*******************************************************/ // JavaScript Constructor for nsIXPCConstructor objects (Components.Constructor) class nsXPCComponents_Constructor final : public nsIXPCComponents_Constructor, public nsIXPCScriptable, public nsIClassInfo { public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCCOMPONENTS_CONSTRUCTOR NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSICLASSINFO public: nsXPCComponents_Constructor(); private: virtual ~nsXPCComponents_Constructor(); static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj, const CallArgs& args, bool* _retval); }; /***************************************************************************/ NS_IMETHODIMP nsXPCComponents_Constructor::GetInterfaces(uint32_t* aCount, nsIID * **aArray) { const uint32_t count = 2; *aCount = count; nsIID** array; *aArray = array = static_cast<nsIID**>(moz_xmalloc(count * sizeof(nsIID*))); if (!array) return NS_ERROR_OUT_OF_MEMORY; uint32_t index = 0; nsIID* clone; #define PUSH_IID(id) \ clone = static_cast<nsIID*>(nsMemory::Clone(&NS_GET_IID( id ), \ sizeof(nsIID))); \ if (!clone) \ goto oom; \ array[index++] = clone; PUSH_IID(nsIXPCComponents_Constructor) PUSH_IID(nsIXPCScriptable) #undef PUSH_IID return NS_OK; oom: while (index) free(array[--index]); free(array); *aArray = nullptr; return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Constructor::GetScriptableHelper(nsIXPCScriptable** retval) { *retval = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Constructor::GetContractID(char * *aContractID) { *aContractID = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCComponents_Constructor::GetClassDescription(char * *aClassDescription) { static const char classDescription[] = "XPCComponents_Constructor"; *aClassDescription = (char*)nsMemory::Clone(classDescription, sizeof(classDescription)); return *aClassDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsXPCComponents_Constructor::GetClassID(nsCID * *aClassID) { *aClassID = nullptr; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Constructor::GetFlags(uint32_t* aFlags) { *aFlags = 0; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Constructor::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { return NS_ERROR_NOT_AVAILABLE; } nsXPCComponents_Constructor::nsXPCComponents_Constructor() { } nsXPCComponents_Constructor::~nsXPCComponents_Constructor() { // empty } NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Constructor) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Constructor) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Constructor) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCComponents_Constructor) NS_IMPL_RELEASE(nsXPCComponents_Constructor) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCComponents_Constructor #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Constructor" #define XPC_MAP_WANT_CALL #define XPC_MAP_WANT_CONSTRUCT #define XPC_MAP_WANT_HASINSTANCE #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCComponents_Constructor::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, const CallArgs& args, bool* _retval) { RootedObject obj(cx, objArg); return CallOrConstruct(wrapper, cx, obj, args, _retval); } NS_IMETHODIMP nsXPCComponents_Constructor::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* objArg, const CallArgs& args, bool* _retval) { RootedObject obj(cx, objArg); return CallOrConstruct(wrapper, cx, obj, args, _retval); } // static nsresult nsXPCComponents_Constructor::CallOrConstruct(nsIXPConnectWrappedNative* wrapper, JSContext* cx, HandleObject obj, const CallArgs& args, bool* _retval) { // make sure we have at least one arg if (args.length() < 1) return ThrowAndFail(NS_ERROR_XPC_NOT_ENOUGH_ARGS, cx, _retval); // get the various other object pointers we need nsXPConnect* xpc = nsXPConnect::XPConnect(); XPCWrappedNativeScope* scope = ObjectScope(obj); nsCOMPtr<nsIXPCComponents> comp; if (!xpc || !scope || !(comp = do_QueryInterface(scope->GetComponents()))) return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); // Do the security check if necessary if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(cx, nsXPCConstructor::GetCID()))) { // the security manager vetoed. It should have set an exception. *_retval = false; return NS_OK; } // initialization params for the Constructor object we will create nsCOMPtr<nsIJSCID> cClassID; nsCOMPtr<nsIJSIID> cInterfaceID; const char* cInitializer = nullptr; JSAutoByteString cInitializerBytes; if (args.length() >= 3) { // args[2] is an initializer function or property name RootedString str(cx, ToString(cx, args[2])); if (!str || !(cInitializer = cInitializerBytes.encodeLatin1(cx, str))) return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); } if (args.length() >= 2) { // args[1] is an iid name string // XXXjband support passing "Components.interfaces.foo"? nsCOMPtr<nsIXPCComponents_Interfaces> ifaces; RootedObject ifacesObj(cx); // we do the lookup by asking the Components.interfaces object // for the property with this name - i.e. we let its caching of these // nsIJSIID objects work for us. if (NS_FAILED(comp->GetInterfaces(getter_AddRefs(ifaces))) || NS_FAILED(xpc->WrapNative(cx, obj, ifaces, NS_GET_IID(nsIXPCComponents_Interfaces), ifacesObj.address())) || !ifacesObj) { return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); } RootedString str(cx, ToString(cx, args[1])); RootedId id(cx); if (!str || !JS_StringToId(cx, str, &id)) return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); RootedValue val(cx); if (!JS_GetPropertyById(cx, ifacesObj, id, &val) || val.isPrimitive()) return ThrowAndFail(NS_ERROR_XPC_BAD_IID, cx, _retval); nsCOMPtr<nsIXPConnectWrappedNative> wn; if (NS_FAILED(xpc->GetWrappedNativeOfJSObject(cx, &val.toObject(), getter_AddRefs(wn))) || !wn || !(cInterfaceID = do_QueryWrappedNative(wn))) { return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); } } else { nsCOMPtr<nsIInterfaceInfo> info; xpc->GetInfoForIID(&NS_GET_IID(nsISupports), getter_AddRefs(info)); if (info) { cInterfaceID = nsJSIID::NewID(info); } if (!cInterfaceID) return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); } // a new scope to avoid warnings about shadowed names { // argv[0] is a contractid name string // XXXjband support passing "Components.classes.foo"? // we do the lookup by asking the Components.classes object // for the property with this name - i.e. we let its caching of these // nsIJSCID objects work for us. nsCOMPtr<nsIXPCComponents_Classes> classes; RootedObject classesObj(cx); if (NS_FAILED(comp->GetClasses(getter_AddRefs(classes))) || NS_FAILED(xpc->WrapNative(cx, obj, classes, NS_GET_IID(nsIXPCComponents_Classes), classesObj.address())) || !classesObj) { return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); } RootedString str(cx, ToString(cx, args[0])); RootedId id(cx); if (!str || !JS_StringToId(cx, str, &id)) return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval); RootedValue val(cx); if (!JS_GetPropertyById(cx, classesObj, id, &val) || val.isPrimitive()) return ThrowAndFail(NS_ERROR_XPC_BAD_CID, cx, _retval); nsCOMPtr<nsIXPConnectWrappedNative> wn; if (NS_FAILED(xpc->GetWrappedNativeOfJSObject(cx, val.toObjectOrNull(), getter_AddRefs(wn))) || !wn || !(cClassID = do_QueryWrappedNative(wn))) { return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval); } } nsCOMPtr<nsIXPCConstructor> ctor = new nsXPCConstructor(cClassID, cInterfaceID, cInitializer); RootedObject newObj(cx); if (NS_FAILED(xpc->WrapNative(cx, obj, ctor, NS_GET_IID(nsIXPCConstructor), newObj.address())) || !newObj) { return ThrowAndFail(NS_ERROR_XPC_CANT_CREATE_WN, cx, _retval); } args.rval().setObject(*newObj); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Constructor::HasInstance(nsIXPConnectWrappedNative* wrapper, JSContext * cx, JSObject * obj, HandleValue val, bool* bp, bool* _retval) { if (bp) *bp = JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIXPCConstructor)); return NS_OK; } class nsXPCComponents_Utils final : public nsIXPCComponents_Utils, public nsIXPCScriptable { public: // all the interface method declarations... NS_DECL_ISUPPORTS NS_DECL_NSIXPCSCRIPTABLE NS_DECL_NSIXPCCOMPONENTS_UTILS public: nsXPCComponents_Utils() { } private: virtual ~nsXPCComponents_Utils() { } nsCOMPtr<nsIXPCComponents_utils_Sandbox> mSandbox; }; NS_INTERFACE_MAP_BEGIN(nsXPCComponents_Utils) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents_Utils) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXPCComponents_Utils) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsXPCComponents_Utils) NS_IMPL_RELEASE(nsXPCComponents_Utils) // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME nsXPCComponents_Utils #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents_Utils" #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP nsXPCComponents_Utils::GetSandbox(nsIXPCComponents_utils_Sandbox** aSandbox) { NS_ENSURE_ARG_POINTER(aSandbox); if (!mSandbox) mSandbox = NewSandboxConstructor(); nsCOMPtr<nsIXPCComponents_utils_Sandbox> rval = mSandbox; rval.forget(aSandbox); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::ReportError(HandleValue error, JSContext* cx) { // This function shall never fail! Silently eat any failure conditions. nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); if (!console) return NS_OK; nsGlobalWindow* globalWin = CurrentWindowOrNull(cx); nsPIDOMWindowInner* win = globalWin ? globalWin->AsInner() : nullptr; const uint64_t innerWindowID = win ? win->WindowID() : 0; RootedObject errorObj(cx, error.isObject() ? &error.toObject() : nullptr); JSErrorReport* err = errorObj ? JS_ErrorFromException(cx, errorObj) : nullptr; nsCOMPtr<nsIScriptError> scripterr; if (errorObj) { JS::RootedObject stackVal(cx, FindExceptionStackForConsoleReport(win, error)); if (stackVal) { scripterr = new nsScriptErrorWithStack(stackVal); } } nsString fileName; int32_t lineNo = 0; if (!scripterr) { nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack(); if (frame) { frame->GetFilename(cx, fileName); frame->GetLineNumber(cx, &lineNo); JS::Rooted<JS::Value> stack(cx); nsresult rv = frame->GetNativeSavedFrame(&stack); if (NS_SUCCEEDED(rv) && stack.isObject()) { JS::Rooted<JSObject*> stackObj(cx, &stack.toObject()); scripterr = new nsScriptErrorWithStack(stackObj); } } } if (!scripterr) { scripterr = new nsScriptError(); } if (err) { // It's a proper JS Error nsAutoString fileUni; CopyUTF8toUTF16(err->filename, fileUni); uint32_t column = err->tokenOffset(); const char16_t* linebuf = err->linebuf(); nsresult rv = scripterr->InitWithWindowID( err->message() ? NS_ConvertUTF8toUTF16(err->message().c_str()) : EmptyString(), fileUni, linebuf ? nsDependentString(linebuf, err->linebufLength()) : EmptyString(), err->lineno, column, err->flags, "XPConnect JavaScript", innerWindowID); NS_ENSURE_SUCCESS(rv, NS_OK); console->LogMessage(scripterr); return NS_OK; } // It's not a JS Error object, so we synthesize as best we're able. RootedString msgstr(cx, ToString(cx, error)); if (!msgstr) return NS_OK; nsAutoJSString msg; if (!msg.init(cx, msgstr)) return NS_OK; nsresult rv = scripterr->InitWithWindowID( msg, fileName, EmptyString(), lineNo, 0, 0, "XPConnect JavaScript", innerWindowID); NS_ENSURE_SUCCESS(rv, NS_OK); console->LogMessage(scripterr); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::EvalInSandbox(const nsAString& source, HandleValue sandboxVal, HandleValue version, const nsACString& filenameArg, int32_t lineNumber, JSContext* cx, uint8_t optionalArgc, MutableHandleValue retval) { RootedObject sandbox(cx); if (!JS_ValueToObject(cx, sandboxVal, &sandbox) || !sandbox) return NS_ERROR_INVALID_ARG; // Optional third argument: JS version, as a string. JSVersion jsVersion = JSVERSION_DEFAULT; if (optionalArgc >= 1) { JSString* jsVersionStr = ToString(cx, version); if (!jsVersionStr) return NS_ERROR_INVALID_ARG; JSAutoByteString bytes(cx, jsVersionStr); if (!bytes) return NS_ERROR_INVALID_ARG; jsVersion = JS_StringToVersion(bytes.ptr()); // Explicitly check for "latest", which we support for sandboxes but // isn't in the set of web-exposed version strings. if (jsVersion == JSVERSION_UNKNOWN && !strcmp(bytes.ptr(), "latest")) { jsVersion = JSVERSION_LATEST; } if (jsVersion == JSVERSION_UNKNOWN) return NS_ERROR_INVALID_ARG; } // Optional fourth and fifth arguments: filename and line number. int32_t lineNo = (optionalArgc >= 3) ? lineNumber : 1; nsCString filename; if (!filenameArg.IsVoid()) { filename.Assign(filenameArg); } else { // Get the current source info from xpc. nsresult rv; nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIStackFrame> frame; xpc->GetCurrentJSStack(getter_AddRefs(frame)); if (frame) { nsString frameFile; frame->GetFilename(cx, frameFile); CopyUTF16toUTF8(frameFile, filename); frame->GetLineNumber(cx, &lineNo); } } return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo, jsVersion, retval); } NS_IMETHODIMP nsXPCComponents_Utils::GetSandboxAddonId(HandleValue sandboxVal, JSContext* cx, MutableHandleValue rval) { if (!sandboxVal.isObject()) return NS_ERROR_INVALID_ARG; RootedObject sandbox(cx, &sandboxVal.toObject()); sandbox = js::CheckedUnwrap(sandbox); if (!sandbox || !xpc::IsSandbox(sandbox)) return NS_ERROR_INVALID_ARG; return xpc::GetSandboxAddonId(cx, sandbox, rval); } NS_IMETHODIMP nsXPCComponents_Utils::GetSandboxMetadata(HandleValue sandboxVal, JSContext* cx, MutableHandleValue rval) { if (!sandboxVal.isObject()) return NS_ERROR_INVALID_ARG; RootedObject sandbox(cx, &sandboxVal.toObject()); sandbox = js::CheckedUnwrap(sandbox); if (!sandbox || !xpc::IsSandbox(sandbox)) return NS_ERROR_INVALID_ARG; return xpc::GetSandboxMetadata(cx, sandbox, rval); } NS_IMETHODIMP nsXPCComponents_Utils::SetSandboxMetadata(HandleValue sandboxVal, HandleValue metadataVal, JSContext* cx) { if (!sandboxVal.isObject()) return NS_ERROR_INVALID_ARG; RootedObject sandbox(cx, &sandboxVal.toObject()); sandbox = js::CheckedUnwrap(sandbox); if (!sandbox || !xpc::IsSandbox(sandbox)) return NS_ERROR_INVALID_ARG; nsresult rv = xpc::SetSandboxMetadata(cx, sandbox, metadataVal); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::Import(const nsACString& registryLocation, HandleValue targetObj, JSContext* cx, uint8_t optionalArgc, MutableHandleValue retval) { nsCOMPtr<xpcIJSModuleLoader> moduleloader = do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); if (!moduleloader) return NS_ERROR_FAILURE; return moduleloader->Import(registryLocation, targetObj, cx, optionalArgc, retval); } NS_IMETHODIMP nsXPCComponents_Utils::IsModuleLoaded(const nsACString& registryLocation, bool* retval) { nsCOMPtr<xpcIJSModuleLoader> moduleloader = do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); if (!moduleloader) return NS_ERROR_FAILURE; return moduleloader->IsModuleLoaded(registryLocation, retval); } NS_IMETHODIMP nsXPCComponents_Utils::Unload(const nsACString & registryLocation) { nsCOMPtr<xpcIJSModuleLoader> moduleloader = do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); if (!moduleloader) return NS_ERROR_FAILURE; return moduleloader->Unload(registryLocation); } NS_IMETHODIMP nsXPCComponents_Utils::ImportGlobalProperties(HandleValue aPropertyList, JSContext* cx) { RootedObject global(cx, CurrentGlobalOrNull(cx)); MOZ_ASSERT(global); // Don't allow doing this if the global is a Window nsGlobalWindow* win; if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, &global, win))) { return NS_ERROR_NOT_AVAILABLE; } GlobalProperties options; NS_ENSURE_TRUE(aPropertyList.isObject(), NS_ERROR_INVALID_ARG); RootedObject propertyList(cx, &aPropertyList.toObject()); bool isArray; if (NS_WARN_IF(!JS_IsArrayObject(cx, propertyList, &isArray))) { return NS_ERROR_FAILURE; } if (NS_WARN_IF(!isArray)) { return NS_ERROR_INVALID_ARG; } if (!options.Parse(cx, propertyList) || !options.DefineInXPCComponents(cx, global)) { return NS_ERROR_FAILURE; } return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetWeakReference(HandleValue object, JSContext* cx, xpcIJSWeakReference** _retval) { RefPtr<xpcJSWeakReference> ref = new xpcJSWeakReference(); nsresult rv = ref->Init(cx, object); NS_ENSURE_SUCCESS(rv, rv); ref.forget(_retval); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::ForceGC() { JSContext* cx = nsXPConnect::GetContextInstance()->Context(); PrepareForFullGC(cx); GCForReason(cx, GC_NORMAL, gcreason::COMPONENT_UTILS); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::ForceCC(nsICycleCollectorListener* listener) { nsJSContext::CycleCollectNow(listener); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::FinishCC() { nsCycleCollector_finishAnyCurrentCollection(); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::CcSlice(int64_t budget) { nsJSContext::RunCycleCollectorWorkSlice(budget); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetMaxCCSliceTimeSinceClear(int32_t* out) { *out = nsJSContext::GetMaxCCSliceTimeSinceClear(); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::ClearMaxCCTime() { nsJSContext::ClearMaxCCSliceTime(); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::ForceShrinkingGC() { JSContext* cx = dom::danger::GetJSContext(); PrepareForFullGC(cx); GCForReason(cx, GC_SHRINK, gcreason::COMPONENT_UTILS); return NS_OK; } class PreciseGCRunnable : public Runnable { public: PreciseGCRunnable(ScheduledGCCallback* aCallback, bool aShrinking) : mCallback(aCallback), mShrinking(aShrinking) {} NS_IMETHOD Run() override { JSContext* cx = dom::danger::GetJSContext(); if (JS_IsRunning(cx)) return NS_DispatchToMainThread(this); nsJSContext::GarbageCollectNow(gcreason::COMPONENT_UTILS, nsJSContext::NonIncrementalGC, mShrinking ? nsJSContext::ShrinkingGC : nsJSContext::NonShrinkingGC); mCallback->Callback(); return NS_OK; } private: RefPtr<ScheduledGCCallback> mCallback; bool mShrinking; }; NS_IMETHODIMP nsXPCComponents_Utils::SchedulePreciseGC(ScheduledGCCallback* aCallback) { RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, false); return NS_DispatchToMainThread(event); } NS_IMETHODIMP nsXPCComponents_Utils::SchedulePreciseShrinkingGC(ScheduledGCCallback* aCallback) { RefPtr<PreciseGCRunnable> event = new PreciseGCRunnable(aCallback, true); return NS_DispatchToMainThread(event); } NS_IMETHODIMP nsXPCComponents_Utils::UnlinkGhostWindows() { #ifdef DEBUG nsWindowMemoryReporter::UnlinkGhostWindows(); return NS_OK; #else return NS_ERROR_NOT_IMPLEMENTED; #endif } NS_IMETHODIMP nsXPCComponents_Utils::GetJSTestingFunctions(JSContext* cx, MutableHandleValue retval) { JSObject* obj = js::GetTestingFunctions(cx); if (!obj) return NS_ERROR_XPC_JAVASCRIPT_ERROR; retval.setObject(*obj); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::CallFunctionWithAsyncStack(HandleValue function, nsIStackFrame* stack, const nsAString& asyncCause, JSContext* cx, MutableHandleValue retval) { nsresult rv; if (!stack || asyncCause.IsEmpty()) { return NS_ERROR_INVALID_ARG; } JS::Rooted<JS::Value> asyncStack(cx); rv = stack->GetNativeSavedFrame(&asyncStack); if (NS_FAILED(rv)) return rv; if (!asyncStack.isObject()) { JS_ReportErrorASCII(cx, "Must use a native JavaScript stack frame"); return NS_ERROR_INVALID_ARG; } JS::Rooted<JSObject*> asyncStackObj(cx, &asyncStack.toObject()); NS_ConvertUTF16toUTF8 utf8Cause(asyncCause); JS::AutoSetAsyncStackForNewCalls sas(cx, asyncStackObj, utf8Cause.get(), JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT); if (!JS_CallFunctionValue(cx, nullptr, function, JS::HandleValueArray::empty(), retval)) { return NS_ERROR_XPC_JAVASCRIPT_ERROR; } return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetGlobalForObject(HandleValue object, JSContext* cx, MutableHandleValue retval) { // First argument must be an object. if (object.isPrimitive()) return NS_ERROR_XPC_BAD_CONVERT_JS; // Wrappers are parented to their the global in their home compartment. But // when getting the global for a cross-compartment wrapper, we really want // a wrapper for the foreign global. So we need to unwrap before getting the // parent, enter the compartment for the duration of the call, and wrap the // result. Rooted<JSObject*> obj(cx, &object.toObject()); obj = js::UncheckedUnwrap(obj); { JSAutoCompartment ac(cx, obj); obj = JS_GetGlobalForObject(cx, obj); } if (!JS_WrapObject(cx, &obj)) return NS_ERROR_FAILURE; // Get the WindowProxy if necessary. obj = js::ToWindowProxyIfWindow(obj); retval.setObject(*obj); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::IsProxy(HandleValue vobj, JSContext* cx, bool* rval) { if (!vobj.isObject()) { *rval = false; return NS_OK; } RootedObject obj(cx, &vobj.toObject()); obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false); NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE); *rval = js::IsScriptedProxy(obj); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::ExportFunction(HandleValue vfunction, HandleValue vscope, HandleValue voptions, JSContext* cx, MutableHandleValue rval) { if (!xpc::ExportFunction(cx, vfunction, vscope, voptions, rval)) return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::CreateObjectIn(HandleValue vobj, HandleValue voptions, JSContext* cx, MutableHandleValue rval) { RootedObject optionsObject(cx, voptions.isObject() ? &voptions.toObject() : nullptr); CreateObjectInOptions options(cx, optionsObject); if (voptions.isObject() && !options.Parse()) { return NS_ERROR_FAILURE; } if (!xpc::CreateObjectIn(cx, vobj, options, rval)) return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::MakeObjectPropsNormal(HandleValue vobj, JSContext* cx) { if (!cx) return NS_ERROR_FAILURE; // first argument must be an object if (vobj.isPrimitive()) return NS_ERROR_XPC_BAD_CONVERT_JS; RootedObject obj(cx, js::UncheckedUnwrap(&vobj.toObject())); JSAutoCompartment ac(cx, obj); Rooted<IdVector> ida(cx, IdVector(cx)); if (!JS_Enumerate(cx, obj, &ida)) return NS_ERROR_FAILURE; RootedId id(cx); RootedValue v(cx); for (size_t i = 0; i < ida.length(); ++i) { id = ida[i]; if (!JS_GetPropertyById(cx, obj, id, &v)) return NS_ERROR_FAILURE; if (v.isPrimitive()) continue; RootedObject propobj(cx, &v.toObject()); // TODO Deal with non-functions. if (!js::IsWrapper(propobj) || !JS::IsCallable(propobj)) continue; FunctionForwarderOptions forwarderOptions; if (!NewFunctionForwarder(cx, id, propobj, forwarderOptions, &v) || !JS_SetPropertyById(cx, obj, id, v)) return NS_ERROR_FAILURE; } return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::IsDeadWrapper(HandleValue obj, bool* out) { *out = false; if (obj.isPrimitive()) return NS_ERROR_INVALID_ARG; // Make sure to unwrap first. Once a proxy is nuked, it ceases to be a // wrapper, meaning that, if passed to another compartment, we'll generate // a CCW for it. Make sure that IsDeadWrapper sees through the confusion. *out = JS_IsDeadWrapper(js::CheckedUnwrap(&obj.toObject())); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::IsCrossProcessWrapper(HandleValue obj, bool* out) { *out = false; if (obj.isPrimitive()) return NS_ERROR_INVALID_ARG; *out = jsipc::IsWrappedCPOW(&obj.toObject()); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetCrossProcessWrapperTag(HandleValue obj, nsACString& out) { if (obj.isPrimitive() || !jsipc::IsWrappedCPOW(&obj.toObject())) return NS_ERROR_INVALID_ARG; jsipc::GetWrappedCPOWTag(&obj.toObject(), out); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::PermitCPOWsInScope(HandleValue obj) { if (!obj.isObject()) return NS_ERROR_INVALID_ARG; JSObject* scopeObj = js::UncheckedUnwrap(&obj.toObject()); CompartmentPrivate::Get(scopeObj)->allowCPOWs = true; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::RecomputeWrappers(HandleValue vobj, JSContext* cx) { // Determine the compartment of the given object, if any. JSCompartment* c = vobj.isObject() ? js::GetObjectCompartment(js::UncheckedUnwrap(&vobj.toObject())) : nullptr; // If no compartment was given, recompute all. if (!c) js::RecomputeWrappers(cx, js::AllCompartments(), js::AllCompartments()); // Otherwise, recompute wrappers for the given compartment. else js::RecomputeWrappers(cx, js::SingleCompartment(c), js::AllCompartments()) && js::RecomputeWrappers(cx, js::AllCompartments(), js::SingleCompartment(c)); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::SetWantXrays(HandleValue vscope, JSContext* cx) { if (!vscope.isObject()) return NS_ERROR_INVALID_ARG; JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject()); JSCompartment* compartment = js::GetObjectCompartment(scopeObj); CompartmentPrivate::Get(scopeObj)->wantXrays = true; bool ok = js::RecomputeWrappers(cx, js::SingleCompartment(compartment), js::AllCompartments()); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::ForcePermissiveCOWs(JSContext* cx) { CrashIfNotInAutomation(); CompartmentPrivate::Get(CurrentGlobalOrNull(cx))->forcePermissiveCOWs = true; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::ForcePrivilegedComponentsForScope(HandleValue vscope, JSContext* cx) { if (!vscope.isObject()) return NS_ERROR_INVALID_ARG; CrashIfNotInAutomation(); JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject()); XPCWrappedNativeScope* scope = ObjectScope(scopeObj); scope->ForcePrivilegedComponents(); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetComponentsForScope(HandleValue vscope, JSContext* cx, MutableHandleValue rval) { if (!vscope.isObject()) return NS_ERROR_INVALID_ARG; JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject()); XPCWrappedNativeScope* scope = ObjectScope(scopeObj); RootedObject components(cx); if (!scope->GetComponentsJSObject(&components)) return NS_ERROR_FAILURE; if (!JS_WrapObject(cx, &components)) return NS_ERROR_FAILURE; rval.setObject(*components); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::Dispatch(HandleValue runnableArg, HandleValue scope, JSContext* cx) { RootedValue runnable(cx, runnableArg); // Enter the given compartment, if any, and rewrap runnable. Maybe<JSAutoCompartment> ac; if (scope.isObject()) { JSObject* scopeObj = js::UncheckedUnwrap(&scope.toObject()); if (!scopeObj) return NS_ERROR_FAILURE; ac.emplace(cx, scopeObj); if (!JS_WrapValue(cx, &runnable)) return NS_ERROR_FAILURE; } // Get an XPCWrappedJS for |runnable|. if (!runnable.isObject()) return NS_ERROR_INVALID_ARG; nsCOMPtr<nsIRunnable> run; nsresult rv = nsXPConnect::XPConnect()->WrapJS(cx, &runnable.toObject(), NS_GET_IID(nsIRunnable), getter_AddRefs(run)); NS_ENSURE_SUCCESS(rv, rv); MOZ_ASSERT(run); // Dispatch. return NS_DispatchToMainThread(run); } #define GENERATE_JSCONTEXTOPTION_GETTER_SETTER(_attr, _getter, _setter) \ NS_IMETHODIMP \ nsXPCComponents_Utils::Get## _attr(JSContext* cx, bool* aValue) \ { \ *aValue = ContextOptionsRef(cx)._getter(); \ return NS_OK; \ } \ NS_IMETHODIMP \ nsXPCComponents_Utils::Set## _attr(JSContext* cx, bool aValue) \ { \ ContextOptionsRef(cx)._setter(aValue); \ return NS_OK; \ } GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict, extraWarnings, setExtraWarnings) GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Werror, werror, setWerror) GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Strict_mode, strictMode, setStrictMode) GENERATE_JSCONTEXTOPTION_GETTER_SETTER(Ion, ion, setIon) #undef GENERATE_JSCONTEXTOPTION_GETTER_SETTER NS_IMETHODIMP nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx) { PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS); NS_ENSURE_TRUE(obj.isObject(), NS_ERROR_INVALID_ARG); JSObject* wrapper = &obj.toObject(); NS_ENSURE_TRUE(IsWrapper(wrapper), NS_ERROR_INVALID_ARG); JSObject* sb = UncheckedUnwrap(wrapper); NS_ENSURE_TRUE(IsSandbox(sb), NS_ERROR_INVALID_ARG); NukeCrossCompartmentWrappers(cx, AllCompartments(), SingleCompartment(GetObjectCompartment(sb)), NukeWindowReferences); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::BlockScriptForGlobal(HandleValue globalArg, JSContext* cx) { NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), /* stopAtWindowProxy = */ false)); NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) { JS_ReportErrorASCII(cx, "Script may not be disabled for system globals"); return NS_ERROR_FAILURE; } Scriptability::Get(global).Block(); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::UnblockScriptForGlobal(HandleValue globalArg, JSContext* cx) { NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), /* stopAtWindowProxy = */ false)); NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) { JS_ReportErrorASCII(cx, "Script may not be disabled for system globals"); return NS_ERROR_FAILURE; } Scriptability::Get(global).Unblock(); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::IsXrayWrapper(HandleValue obj, bool* aRetval) { *aRetval = obj.isObject() && xpc::WrapperFactory::IsXrayWrapper(&obj.toObject()); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::WaiveXrays(HandleValue aVal, JSContext* aCx, MutableHandleValue aRetval) { RootedValue value(aCx, aVal); if (!xpc::WrapperFactory::WaiveXrayAndWrap(aCx, &value)) return NS_ERROR_FAILURE; aRetval.set(value); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::UnwaiveXrays(HandleValue aVal, JSContext* aCx, MutableHandleValue aRetval) { if (!aVal.isObject()) { aRetval.set(aVal); return NS_OK; } RootedObject obj(aCx, js::UncheckedUnwrap(&aVal.toObject())); if (!JS_WrapObject(aCx, &obj)) return NS_ERROR_FAILURE; aRetval.setObject(*obj); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetClassName(HandleValue aObj, bool aUnwrap, JSContext* aCx, char** aRv) { if (!aObj.isObject()) return NS_ERROR_INVALID_ARG; RootedObject obj(aCx, &aObj.toObject()); if (aUnwrap) obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false); *aRv = NS_strdup(js::GetObjectClass(obj)->name); NS_ENSURE_TRUE(*aRv, NS_ERROR_OUT_OF_MEMORY); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetDOMClassInfo(const nsAString& aClassName, nsIClassInfo** aClassInfo) { *aClassInfo = nullptr; return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP nsXPCComponents_Utils::GetIncumbentGlobal(HandleValue aCallback, JSContext* aCx, MutableHandleValue aOut) { nsCOMPtr<nsIGlobalObject> global = mozilla::dom::GetIncumbentGlobal(); RootedValue globalVal(aCx); if (!global) { globalVal = NullValue(); } else { // Note: We rely on the wrap call for outerization. globalVal = ObjectValue(*global->GetGlobalJSObject()); if (!JS_WrapValue(aCx, &globalVal)) return NS_ERROR_FAILURE; } // Invoke the callback, if passed. if (aCallback.isObject()) { RootedValue ignored(aCx); if (!JS_CallFunctionValue(aCx, nullptr, aCallback, JS::HandleValueArray(globalVal), &ignored)) return NS_ERROR_FAILURE; } aOut.set(globalVal); return NS_OK; } /* * Below is a bunch of awkward junk to allow JS test code to trigger the * creation of an XPCWrappedJS, such that it ends up in the map. We need to * hand the caller some sort of reference to hold onto (to prevent the * refcount from dropping to zero as soon as the function returns), but trying * to return a bonafide XPCWrappedJS to script causes all sorts of trouble. So * we create a benign holder class instead, which acts as an opaque reference * that script can use to keep the XPCWrappedJS alive and in the map. */ class WrappedJSHolder : public nsISupports { NS_DECL_ISUPPORTS WrappedJSHolder() {} RefPtr<nsXPCWrappedJS> mWrappedJS; private: virtual ~WrappedJSHolder() {} }; NS_IMPL_ISUPPORTS0(WrappedJSHolder); NS_IMETHODIMP nsXPCComponents_Utils::GenerateXPCWrappedJS(HandleValue aObj, HandleValue aScope, JSContext* aCx, nsISupports** aOut) { if (!aObj.isObject()) return NS_ERROR_INVALID_ARG; RootedObject obj(aCx, &aObj.toObject()); RootedObject scope(aCx, aScope.isObject() ? js::UncheckedUnwrap(&aScope.toObject()) : CurrentGlobalOrNull(aCx)); JSAutoCompartment ac(aCx, scope); if (!JS_WrapObject(aCx, &obj)) return NS_ERROR_FAILURE; RefPtr<WrappedJSHolder> holder = new WrappedJSHolder(); nsresult rv = nsXPCWrappedJS::GetNewOrUsed(obj, NS_GET_IID(nsISupports), getter_AddRefs(holder->mWrappedJS)); holder.forget(aOut); return rv; } NS_IMETHODIMP nsXPCComponents_Utils::GetWatchdogTimestamp(const nsAString& aCategory, PRTime* aOut) { WatchdogTimestampCategory category; if (aCategory.EqualsLiteral("ContextStateChange")) category = TimestampContextStateChange; else if (aCategory.EqualsLiteral("WatchdogWakeup")) category = TimestampWatchdogWakeup; else if (aCategory.EqualsLiteral("WatchdogHibernateStart")) category = TimestampWatchdogHibernateStart; else if (aCategory.EqualsLiteral("WatchdogHibernateStop")) category = TimestampWatchdogHibernateStop; else return NS_ERROR_INVALID_ARG; *aOut = XPCJSContext::Get()->GetWatchdogTimestamp(category); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetJSEngineTelemetryValue(JSContext* cx, MutableHandleValue rval) { RootedObject obj(cx, JS_NewPlainObject(cx)); if (!obj) return NS_ERROR_OUT_OF_MEMORY; unsigned attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT; size_t i = JS_SetProtoCalled(cx); RootedValue v(cx, DoubleValue(i)); if (!JS_DefineProperty(cx, obj, "setProto", v, attrs)) return NS_ERROR_OUT_OF_MEMORY; i = JS_GetCustomIteratorCount(cx); v.setDouble(i); if (!JS_DefineProperty(cx, obj, "customIter", v, attrs)) return NS_ERROR_OUT_OF_MEMORY; rval.setObject(*obj); return NS_OK; } bool xpc::CloneInto(JSContext* aCx, HandleValue aValue, HandleValue aScope, HandleValue aOptions, MutableHandleValue aCloned) { if (!aScope.isObject()) return false; RootedObject scope(aCx, &aScope.toObject()); scope = js::CheckedUnwrap(scope); if(!scope) { JS_ReportErrorASCII(aCx, "Permission denied to clone object into scope"); return false; } if (!aOptions.isUndefined() && !aOptions.isObject()) { JS_ReportErrorASCII(aCx, "Invalid argument"); return false; } RootedObject optionsObject(aCx, aOptions.isObject() ? &aOptions.toObject() : nullptr); StackScopedCloneOptions options(aCx, optionsObject); if (aOptions.isObject() && !options.Parse()) return false; { JSAutoCompartment ac(aCx, scope); aCloned.set(aValue); if (!StackScopedClone(aCx, options, aCloned)) return false; } return JS_WrapValue(aCx, aCloned); } NS_IMETHODIMP nsXPCComponents_Utils::CloneInto(HandleValue aValue, HandleValue aScope, HandleValue aOptions, JSContext* aCx, MutableHandleValue aCloned) { return xpc::CloneInto(aCx, aValue, aScope, aOptions, aCloned) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP nsXPCComponents_Utils::GetWebIDLCallerPrincipal(nsIPrincipal** aResult) { // This API may only be when the Entry Settings Object corresponds to a // JS-implemented WebIDL call. In all other cases, the value will be null, // and we throw. nsCOMPtr<nsIPrincipal> callerPrin = mozilla::dom::GetWebIDLCallerPrincipal(); if (!callerPrin) return NS_ERROR_NOT_AVAILABLE; callerPrin.forget(aResult); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetObjectPrincipal(HandleValue val, JSContext* cx, nsIPrincipal** result) { if (!val.isObject()) return NS_ERROR_INVALID_ARG; RootedObject obj(cx, &val.toObject()); obj = js::CheckedUnwrap(obj); MOZ_ASSERT(obj); nsCOMPtr<nsIPrincipal> prin = nsContentUtils::ObjectPrincipal(obj); prin.forget(result); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::GetCompartmentLocation(HandleValue val, JSContext* cx, nsACString& result) { if (!val.isObject()) return NS_ERROR_INVALID_ARG; RootedObject obj(cx, &val.toObject()); obj = js::CheckedUnwrap(obj); MOZ_ASSERT(obj); result = xpc::CompartmentPrivate::Get(obj)->GetLocation(); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::SetAddonInterposition(const nsACString& addonIdStr, nsIAddonInterposition* interposition, JSContext* cx) { JSAddonId* addonId = xpc::NewAddonId(cx, addonIdStr); if (!addonId) return NS_ERROR_FAILURE; if (!XPCWrappedNativeScope::SetAddonInterposition(cx, addonId, interposition)) return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::SetAddonCallInterposition(HandleValue target, JSContext* cx) { NS_ENSURE_TRUE(target.isObject(), NS_ERROR_INVALID_ARG); RootedObject targetObj(cx, &target.toObject()); targetObj = js::CheckedUnwrap(targetObj); NS_ENSURE_TRUE(targetObj, NS_ERROR_INVALID_ARG); XPCWrappedNativeScope* xpcScope = ObjectScope(targetObj); NS_ENSURE_TRUE(xpcScope, NS_ERROR_INVALID_ARG); xpcScope->SetAddonCallInterposition(); return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::AllowCPOWsInAddon(const nsACString& addonIdStr, bool allow, JSContext* cx) { JSAddonId* addonId = xpc::NewAddonId(cx, addonIdStr); if (!addonId) return NS_ERROR_FAILURE; if (!XPCWrappedNativeScope::AllowCPOWsInAddon(cx, addonId, allow)) return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsXPCComponents_Utils::Now(double* aRetval) { bool isInconsistent = false; TimeStamp start = TimeStamp::ProcessCreation(isInconsistent); *aRetval = (TimeStamp::Now() - start).ToMilliseconds(); return NS_OK; } /***************************************************************************/ /***************************************************************************/ /***************************************************************************/ nsXPCComponentsBase::nsXPCComponentsBase(XPCWrappedNativeScope* aScope) : mScope(aScope) { MOZ_ASSERT(aScope, "aScope must not be null"); } nsXPCComponents::nsXPCComponents(XPCWrappedNativeScope* aScope) : nsXPCComponentsBase(aScope) { } nsXPCComponentsBase::~nsXPCComponentsBase() { } nsXPCComponents::~nsXPCComponents() { } void nsXPCComponentsBase::ClearMembers() { mInterfaces = nullptr; mInterfacesByID = nullptr; mResults = nullptr; } void nsXPCComponents::ClearMembers() { mClasses = nullptr; mClassesByID = nullptr; mID = nullptr; mException = nullptr; mConstructor = nullptr; mUtils = nullptr; nsXPCComponentsBase::ClearMembers(); } /*******************************************/ #define XPC_IMPL_GET_OBJ_METHOD(_class, _n) \ NS_IMETHODIMP _class::Get##_n(nsIXPCComponents_##_n * *a##_n) { \ NS_ENSURE_ARG_POINTER(a##_n); \ if (!m##_n) \ m##_n = new nsXPCComponents_##_n(); \ RefPtr<nsXPCComponents_##_n> ret = m##_n; \ ret.forget(a##_n); \ return NS_OK; \ } XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase, Interfaces) XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase, InterfacesByID) XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Classes) XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, ClassesByID) XPC_IMPL_GET_OBJ_METHOD(nsXPCComponentsBase, Results) XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, ID) XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Exception) XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Constructor) XPC_IMPL_GET_OBJ_METHOD(nsXPCComponents, Utils) #undef XPC_IMPL_GET_OBJ_METHOD /*******************************************/ NS_IMETHODIMP nsXPCComponentsBase::IsSuccessCode(nsresult result, bool* out) { *out = NS_SUCCEEDED(result); return NS_OK; } NS_IMETHODIMP nsXPCComponents::GetStack(nsIStackFrame * *aStack) { nsresult rv; nsXPConnect* xpc = nsXPConnect::XPConnect(); rv = xpc->GetCurrentJSStack(aStack); return rv; } NS_IMETHODIMP nsXPCComponents::GetManager(nsIComponentManager * *aManager) { MOZ_ASSERT(aManager, "bad param"); return NS_GetComponentManager(aManager); } NS_IMETHODIMP nsXPCComponents::GetReturnCode(JSContext* aCx, MutableHandleValue aOut) { nsresult res = XPCJSContext::Get()->GetPendingResult(); aOut.setNumber(static_cast<uint32_t>(res)); return NS_OK; } NS_IMETHODIMP nsXPCComponents::SetReturnCode(JSContext* aCx, HandleValue aCode) { nsresult rv; if (!ToUint32(aCx, aCode, (uint32_t*)&rv)) return NS_ERROR_FAILURE; XPCJSContext::Get()->SetPendingResult(rv); return NS_OK; } // static NS_IMETHODIMP nsXPCComponents::ReportError(HandleValue error, JSContext* cx) { NS_WARNING("Components.reportError deprecated, use Components.utils.reportError"); nsCOMPtr<nsIXPCComponents_Utils> utils; nsresult rv = GetUtils(getter_AddRefs(utils)); if (NS_FAILED(rv)) return rv; return utils->ReportError(error, cx); } /**********************************************/ class ComponentsSH : public nsIXPCScriptable { public: explicit constexpr ComponentsSH(unsigned dummy) { } // We don't actually inherit any ref counting infrastructure, but we don't // need an nsAutoRefCnt member, so the _INHERITED macro is a hack to avoid // having one. NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIXPCSCRIPTABLE static nsresult Get(nsIXPCScriptable** helper) { *helper = &singleton; return NS_OK; } private: static ComponentsSH singleton; }; ComponentsSH ComponentsSH::singleton(0); // Singleton refcounting. NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::AddRef(void) { return 1; } NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::Release(void) { return 1; } NS_INTERFACE_MAP_BEGIN(ComponentsSH) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END #define NSXPCCOMPONENTSBASE_CID \ { 0xc62998e5, 0x95f1, 0x4058, \ { 0xa5, 0x09, 0xec, 0x21, 0x66, 0x18, 0x92, 0xb9 } } #define NSXPCCOMPONENTS_CID \ { 0x3649f405, 0xf0ec, 0x4c28, \ { 0xae, 0xb0, 0xaf, 0x9a, 0x51, 0xe4, 0x4c, 0x81 } } NS_IMPL_CLASSINFO(nsXPCComponentsBase, &ComponentsSH::Get, nsIClassInfo::DOM_OBJECT, NSXPCCOMPONENTSBASE_CID) NS_IMPL_ISUPPORTS_CI(nsXPCComponentsBase, nsIXPCComponentsBase) NS_IMPL_CLASSINFO(nsXPCComponents, &ComponentsSH::Get, nsIClassInfo::DOM_OBJECT, NSXPCCOMPONENTS_CID) // Below is more or less what NS_IMPL_ISUPPORTS_CI_INHERITED1 would look like // if it existed. NS_IMPL_ADDREF_INHERITED(nsXPCComponents, nsXPCComponentsBase) NS_IMPL_RELEASE_INHERITED(nsXPCComponents, nsXPCComponentsBase) NS_INTERFACE_MAP_BEGIN(nsXPCComponents) NS_INTERFACE_MAP_ENTRY(nsIXPCComponents) NS_IMPL_QUERY_CLASSINFO(nsXPCComponents) NS_INTERFACE_MAP_END_INHERITING(nsXPCComponentsBase) NS_IMPL_CI_INTERFACE_GETTER(nsXPCComponents, nsIXPCComponents) // The nsIXPCScriptable map declaration that will generate stubs for us #define XPC_MAP_CLASSNAME ComponentsSH #define XPC_MAP_QUOTED_CLASSNAME "nsXPCComponents" #define XPC_MAP_WANT_PRECREATE #include "xpc_map_end.h" /* This will #undef the above */ NS_IMETHODIMP ComponentsSH::PreCreate(nsISupports* nativeObj, JSContext* cx, JSObject* globalObj, JSObject** parentObj) { nsXPCComponentsBase* self = static_cast<nsXPCComponentsBase*>(nativeObj); // this should never happen if (!self->GetScope()) { NS_WARNING("mScope must not be null when nsXPCComponents::PreCreate is called"); return NS_ERROR_FAILURE; } *parentObj = self->GetScope()->GetGlobalJSObject(); return NS_OK; }