diff --git a/js/xpconnect/src/XPCWrappedJSClass.cpp b/js/xpconnect/src/XPCWrappedJSClass.cpp index 09dbdcc32e3c..cf45f106a125 100644 --- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -97,7 +97,11 @@ class MOZ_STACK_CLASS AutoSavePendingResult { // static const nsXPTInterfaceInfo* nsXPCWrappedJS::GetInterfaceInfo(REFNSIID aIID) { const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByIID(aIID); - if (!info || info->IsBuiltinClass()) { + if (!info) { + return nullptr; + } + + if (info->IsBuiltinClass() || !nsXPConnect::IsISupportsDescendant(info)) { return nullptr; } diff --git a/js/xpconnect/src/XPCWrappedNativeInfo.cpp b/js/xpconnect/src/XPCWrappedNativeInfo.cpp index 620b4d34be9c..d9aebda71a71 100644 --- a/js/xpconnect/src/XPCWrappedNativeInfo.cpp +++ b/js/xpconnect/src/XPCWrappedNativeInfo.cpp @@ -248,6 +248,16 @@ already_AddRefed XPCNativeInterface::NewInstance( uint16_t methodCount = aInfo->MethodCount(); uint16_t constCount = aInfo->ConstantCount(); + + // If the interface does not have nsISupports in its inheritance chain + // then we know we can't reflect its methods. However, some interfaces that + // are used just to reflect constants are declared this way. We need to + // go ahead and build the thing. But, we'll ignore whatever methods it may + // have. + if (!nsXPConnect::IsISupportsDescendant(aInfo)) { + methodCount = 0; + } + totalCount = methodCount + constCount; if (totalCount > MAX_LOCAL_MEMBER_COUNT) { diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index fc40e8d2d34e..c4c2a2a6c395 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -166,6 +166,11 @@ XPCJSRuntime* nsXPConnect::GetRuntimeInstance() { return gSelf->mRuntime; } +// static +bool nsXPConnect::IsISupportsDescendant(const nsXPTInterfaceInfo* info) { + return info && info->HasAncestor(NS_GET_IID(nsISupports)); +} + void xpc::ErrorBase::Init(JSErrorBase* aReport) { if (!aReport->filename) { mFileName.SetIsVoid(true); diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 91abad7736cd..00d4cf08fb45 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -226,6 +226,8 @@ class nsXPConnect final : public nsIXPConnect { static XPCJSRuntime* GetRuntimeInstance(); XPCJSContext* GetContext() { return mContext; } + static bool IsISupportsDescendant(const nsXPTInterfaceInfo* info); + static nsIScriptSecurityManager* SecurityManager() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(gScriptSecurityManager); diff --git a/xpcom/idl-parser/xpidl/rust.py b/xpcom/idl-parser/xpidl/rust.py index 93d96b124f02..c62853976989 100644 --- a/xpcom/idl-parser/xpidl/rust.py +++ b/xpcom/idl-parser/xpidl/rust.py @@ -479,7 +479,12 @@ def write_interface(iface, fd): if iface.namemap is None: raise Exception("Interface was not resolved.") - assert iface.base or (iface.name == "nsISupports") + # if we see a base class-less type other than nsISupports, we just need + # to discard anything else about it other than its constants. + if iface.base is None and iface.name != "nsISupports": + assert len([m for m in iface.members + if type(m) == xpidl.Attribute or type(m) == xpidl.Method]) == 0 + return # Extract the UUID's information so that it can be written into the struct definition names = uuid_decoder.match(iface.attributes.uuid).groupdict() diff --git a/xpcom/idl-parser/xpidl/rust_macros.py b/xpcom/idl-parser/xpidl/rust_macros.py index 45b37d5f4a27..fec08e02ea8c 100644 --- a/xpcom/idl-parser/xpidl/rust_macros.py +++ b/xpcom/idl-parser/xpidl/rust_macros.py @@ -51,7 +51,12 @@ def write_interface(iface, fd): if iface.namemap is None: raise Exception("Interface was not resolved.") - assert iface.base or (iface.name == "nsISupports") + # if we see a base class-less type other than nsISupports, we just need + # to discard anything else about it other than its constants. + if iface.base is None and iface.name != "nsISupports": + assert len([m for m in iface.members + if type(m) == xpidl.Attribute or type(m) == xpidl.Method]) == 0 + return base = 'Some("%s")' % iface.base if iface.base is not None else 'None' try: diff --git a/xpcom/idl-parser/xpidl/xpidl.py b/xpcom/idl-parser/xpidl/xpidl.py index bcbc29814816..0834b5ab94ce 100755 --- a/xpcom/idl-parser/xpidl/xpidl.py +++ b/xpcom/idl-parser/xpidl/xpidl.py @@ -704,8 +704,6 @@ class Interface(object): raise IDLError("interface '%s' is not builtinclass but derives from " "builtinclass '%s'" % (self.name, self.base), self.location) - elif self.name != 'nsISupports': - raise IDLError("Interface '%s' must inherit from nsISupports" % self.name, self.location) for member in self.members: member.resolve(self)