From b3f3e9a04a8b59909954c36558ee0a0aa54f255d Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Mon, 22 Apr 2024 18:19:58 +0000 Subject: [PATCH] Bug 1892481 - More consistently enforce noscript and builtinclass in xpidl, r=xpcom-reviewers,necko-reviewers,valentin,media-playback-reviewers,mccr8,padenot These properties were previously being checked much later, during xptcodegen, and causing methods to be treated as noscript implicitly. This change enforces the noscript requirements earlier when possible in xpidl.py, to produce better errors, and adds addiitonal checks to ensure that types which need to be builtinclass are marked as such. This required some changes to interfaces in order to satisfy the new checks. Differential Revision: https://phabricator.services.mozilla.com/D207804 --- caps/nsIPrincipal.idl | 2 +- docshell/base/nsIDocumentViewer.idl | 5 +- dom/media/gmp/mozIGeckoMediaPluginService.idl | 2 +- .../interfaces/nsITCPSocketCallback.idl | 8 +- js/xpconnect/tests/idl/xpctest_utils.idl | 4 +- modules/libjar/nsIZipReader.idl | 4 +- netwerk/base/nsIClassOfService.idl | 4 +- netwerk/base/nsINetAddr.idl | 2 +- .../base/nsINetworkInterceptController.idl | 2 +- netwerk/base/nsIServerSocket.idl | 2 +- netwerk/base/nsITLSServerSocket.idl | 2 +- netwerk/base/nsITimedChannel.idl | 4 +- netwerk/base/nsIUDPSocket.idl | 8 +- netwerk/dns/nsIDNSByTypeRecord.idl | 6 +- netwerk/dns/nsIDNSRecord.idl | 4 +- .../protocol/http/nsIHttpChannelInternal.idl | 2 +- .../websocket/nsIWebSocketChannel.idl | 2 +- .../protocol/webtransport/nsIWebTransport.idl | 1 + netwerk/socket/nsINamedPipeService.idl | 4 +- .../browser/nsIWebBrowserChrome.idl | 6 +- .../windowcreator/nsIWindowProvider.idl | 2 +- widget/nsIBaseWindow.idl | 6 +- widget/nsIDragService.idl | 2 +- widget/nsIScreen.idl | 2 +- xpcom/idl-parser/xpidl/xpidl.py | 95 ++++++++++++++++++- xpcom/io/nsIConverterInputStream.idl | 2 +- xpcom/io/nsIUnicharInputStream.idl | 2 +- xpcom/reflect/xptinfo/xptcodegen.py | 21 +--- xpcom/threads/nsIThreadManager.idl | 2 +- 29 files changed, 135 insertions(+), 73 deletions(-) diff --git a/caps/nsIPrincipal.idl b/caps/nsIPrincipal.idl index cf6ccd4dea99..e8698e35eeaf 100644 --- a/caps/nsIPrincipal.idl +++ b/caps/nsIPrincipal.idl @@ -498,7 +498,7 @@ interface nsIPrincipal : nsISupports * * May be called from any thread. */ - nsIReferrerInfo createReferrerInfo(in ReferrerPolicy aReferrerPolicy); + [noscript] nsIReferrerInfo createReferrerInfo(in ReferrerPolicy aReferrerPolicy); /** * The base part of |origin| without the concatenation with |originSuffix|. diff --git a/docshell/base/nsIDocumentViewer.idl b/docshell/base/nsIDocumentViewer.idl index afbbdfc464c0..27510dc87905 100644 --- a/docshell/base/nsIDocumentViewer.idl +++ b/docshell/base/nsIDocumentViewer.idl @@ -211,8 +211,9 @@ interface nsIDocumentViewer : nsISupports /** * Sets the print settings for print / print-previewing a subdocument. */ - [can_run_script] void setPrintSettingsForSubdocument(in nsIPrintSettings aPrintSettings, - in RemotePrintJobChildPtr aRemotePrintJob); + [can_run_script, noscript] + void setPrintSettingsForSubdocument(in nsIPrintSettings aPrintSettings, + in RemotePrintJobChildPtr aRemotePrintJob); /** * Get the history entry that this viewer will save itself into when diff --git a/dom/media/gmp/mozIGeckoMediaPluginService.idl b/dom/media/gmp/mozIGeckoMediaPluginService.idl index 000cfef2f53b..a4e3253cbae9 100644 --- a/dom/media/gmp/mozIGeckoMediaPluginService.idl +++ b/dom/media/gmp/mozIGeckoMediaPluginService.idl @@ -57,7 +57,7 @@ native GetGMPVideoEncoderCallback(mozilla::UniquePtr native GetNodeIdCallback(mozilla::UniquePtr&&); native GMPCrashHelperPtr(mozilla::GMPCrashHelper*); -[scriptable, uuid(44d362ae-937a-4803-bee6-f2512a0149d1)] +[scriptable, builtinclass, uuid(44d362ae-937a-4803-bee6-f2512a0149d1)] interface mozIGeckoMediaPluginService : nsISupports { diff --git a/dom/network/interfaces/nsITCPSocketCallback.idl b/dom/network/interfaces/nsITCPSocketCallback.idl index 4a2b7a9ef2ba..181b84abeb06 100644 --- a/dom/network/interfaces/nsITCPSocketCallback.idl +++ b/dom/network/interfaces/nsITCPSocketCallback.idl @@ -11,12 +11,6 @@ #include "domstubs.idl" -%{C++ -#include "nsTArrayForwardDeclare.h" -%} -[ref] native nsUint8TArrayRef(nsTArray); -[ptr] native JSContextPtr(JSContext); - /* * This interface is implemented in TCPSocket.cpp as an internal interface @@ -36,7 +30,7 @@ interface nsITCPSocketCallback : nsISupports { void fireDataStringEvent(in AString type, in ACString data); // Dispatch a "data" event at this object with an Array - void fireDataArrayEvent(in AString type, [const] in nsUint8TArrayRef data); + void fireDataArrayEvent(in AString type, in Array data); // Dispatch an event of the given type at this object. void fireEvent(in AString type); diff --git a/js/xpconnect/tests/idl/xpctest_utils.idl b/js/xpconnect/tests/idl/xpctest_utils.idl index bfc02c45618e..3379a5253cfe 100644 --- a/js/xpconnect/tests/idl/xpctest_utils.idl +++ b/js/xpconnect/tests/idl/xpctest_utils.idl @@ -37,8 +37,8 @@ interface nsIXPCTestTypeScript : nsISupports { void exposedMethod(in long arg); // Members referencing TSNoncompat typedefs are not exposed. - attribute Noncompat noncompatProp; - void noncompatMethod(in Noncompat arg); + [noscript] attribute Noncompat noncompatProp; + [noscript] void noncompatMethod(in Noncompat arg); // [noscript] attributes and methods are not exposed. [noscript] attribute long noscriptProp; diff --git a/modules/libjar/nsIZipReader.idl b/modules/libjar/nsIZipReader.idl index abead2841aff..d191571957d3 100644 --- a/modules/libjar/nsIZipReader.idl +++ b/modules/libjar/nsIZipReader.idl @@ -85,7 +85,7 @@ interface nsIZipReader : nsISupports * ZipReader is closed or destroyed, and must free the memory as * appropriate afterwards. */ - void openMemory(in voidPtr aData, in unsigned long aLength); + [noscript] void openMemory(in voidPtr aData, in unsigned long aLength); /** * The file that represents the zip with which this zip reader was @@ -238,7 +238,7 @@ interface nsIZipReaderCache : nsISupports * Returns the cached NSPR file descriptor of the file. * Note: currently not supported on Windows platform. */ - PRFileDescStar getFd(in nsIFile zipFile); + [noscript] PRFileDescStar getFd(in nsIFile zipFile); }; //////////////////////////////////////////////////////////////////////////////// diff --git a/netwerk/base/nsIClassOfService.idl b/netwerk/base/nsIClassOfService.idl index 7b133107de4b..2d5fa03dc1a1 100644 --- a/netwerk/base/nsIClassOfService.idl +++ b/netwerk/base/nsIClassOfService.idl @@ -22,7 +22,7 @@ class ClassOfService; %} native ClassOfService(mozilla::net::ClassOfService); -[scriptable, uuid(1ccb58ec-5e07-4cf9-a30d-ac5490d23b41)] +[scriptable, builtinclass, uuid(1ccb58ec-5e07-4cf9-a30d-ac5490d23b41)] interface nsIClassOfService : nsISupports { attribute unsigned long classFlags; @@ -30,7 +30,7 @@ interface nsIClassOfService : nsISupports void clearClassFlags(in unsigned long flags); void addClassFlags(in unsigned long flags); - void setClassOfService(in ClassOfService s); + [noscript] void setClassOfService(in ClassOfService s); // All these flags have a (de)prioritization effect. diff --git a/netwerk/base/nsINetAddr.idl b/netwerk/base/nsINetAddr.idl index bbbcd28c0e52..3e8644241582 100644 --- a/netwerk/base/nsINetAddr.idl +++ b/netwerk/base/nsINetAddr.idl @@ -21,7 +21,7 @@ native NetAddr(mozilla::net::NetAddr); * This interface represents a native NetAddr struct in a readonly * interface. */ -[scriptable, uuid(652B9EC5-D159-45D7-9127-50BB559486CD)] +[scriptable, builtinclass, uuid(652B9EC5-D159-45D7-9127-50BB559486CD)] interface nsINetAddr : nsISupports { /** diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl index 946cc95a8806..7f91d2df6f8b 100644 --- a/netwerk/base/nsINetworkInterceptController.idl +++ b/netwerk/base/nsINetworkInterceptController.idl @@ -48,7 +48,7 @@ interface nsIInterceptedBodyCallback : nsISupports * which do not implement nsIChannel. */ -[scriptable, uuid(f4b82975-6a86-4cc4-87fe-9a1fd430c86d)] +[scriptable, builtinclass, uuid(f4b82975-6a86-4cc4-87fe-9a1fd430c86d)] interface nsIInterceptedChannel : nsISupports { /** diff --git a/netwerk/base/nsIServerSocket.idl b/netwerk/base/nsIServerSocket.idl index d6fd34877825..3c21bdb7074a 100644 --- a/netwerk/base/nsIServerSocket.idl +++ b/netwerk/base/nsIServerSocket.idl @@ -19,7 +19,7 @@ typedef unsigned long nsServerSocketFlag; * * An interface to a server socket that can accept incoming connections. */ -[scriptable, uuid(7a9c39cb-a13f-4eef-9bdf-a74301628742)] +[scriptable, builtinclass, uuid(7a9c39cb-a13f-4eef-9bdf-a74301628742)] interface nsIServerSocket : nsISupports { /** diff --git a/netwerk/base/nsITLSServerSocket.idl b/netwerk/base/nsITLSServerSocket.idl index e944f23af72c..a3588ddce297 100644 --- a/netwerk/base/nsITLSServerSocket.idl +++ b/netwerk/base/nsITLSServerSocket.idl @@ -8,7 +8,7 @@ interface nsIX509Cert; interface nsITLSServerSecurityObserver; interface nsISocketTransport; -[scriptable, uuid(cc2c30f9-cfaa-4b8a-bd44-c24881981b74)] +[scriptable, builtinclass, uuid(cc2c30f9-cfaa-4b8a-bd44-c24881981b74)] interface nsITLSServerSocket : nsIServerSocket { /** diff --git a/netwerk/base/nsITimedChannel.idl b/netwerk/base/nsITimedChannel.idl index 4707bf1b7ab2..f6d85cf945c4 100644 --- a/netwerk/base/nsITimedChannel.idl +++ b/netwerk/base/nsITimedChannel.idl @@ -25,7 +25,7 @@ interface nsIServerTiming : nsISupports { [ref] native nsServerTimingArrayRef(nsTArray>); // All properties return zero if the value is not available -[scriptable, uuid(ca63784d-959c-4c3a-9a59-234a2a520de0)] +[scriptable, builtinclass, uuid(ca63784d-959c-4c3a-9a59-234a2a520de0)] interface nsITimedChannel : nsISupports { // Set this attribute to true to enable collection of timing data. // channelCreationTime will be available even with this attribute set to @@ -124,5 +124,5 @@ interface nsITimedChannel : nsISupports { [noscript] attribute boolean reportResourceTiming; readonly attribute nsIArray serverTiming; - nsServerTimingArrayRef getNativeServerTiming(); + [noscript] nsServerTimingArrayRef getNativeServerTiming(); }; diff --git a/netwerk/base/nsIUDPSocket.idl b/netwerk/base/nsIUDPSocket.idl index 5c23c1bb6fc6..d07be55349ce 100644 --- a/netwerk/base/nsIUDPSocket.idl +++ b/netwerk/base/nsIUDPSocket.idl @@ -31,7 +31,7 @@ native NetAddr(mozilla::net::NetAddr); * * An interface to a UDP socket that can accept incoming connections. */ -[scriptable, uuid(d423bf4e-4499-40cf-bc03-153e2bf206d1)] +[scriptable, builtinclass, uuid(d423bf4e-4499-40cf-bc03-153e2bf206d1)] interface nsIUDPSocket : nsISupports { /** @@ -126,7 +126,7 @@ interface nsIUDPSocket : nsISupports * @param aRemoteAddr * The remote address to connect to */ - void connect([const] in NetAddrPtr aAddr); + [noscript] void connect([const] in NetAddrPtr aAddr); /** * Returns the local address of this UDP socket @@ -217,8 +217,8 @@ interface nsIUDPSocket : nsISupports * @param addr The remote host address. * @param stream The input stream to be sent. This must be a buffered stream implementation. */ - void sendBinaryStreamWithAddress([const] in NetAddrPtr addr, - in nsIInputStream stream); + [noscript] void sendBinaryStreamWithAddress([const] in NetAddrPtr addr, + in nsIInputStream stream); /** * joinMulticast diff --git a/netwerk/dns/nsIDNSByTypeRecord.idl b/netwerk/dns/nsIDNSByTypeRecord.idl index 13290e260e27..89829c5c2ad0 100644 --- a/netwerk/dns/nsIDNSByTypeRecord.idl +++ b/netwerk/dns/nsIDNSByTypeRecord.idl @@ -32,7 +32,7 @@ native TypeResult(mozilla::net::TypeRecordResultType); native MaybePort(mozilla::Maybe); native MaybeAlpnTuple(mozilla::Maybe>); -[scriptable, uuid(5d13241b-9d46-448a-90d8-77c418491026)] +[scriptable, builtinclass, uuid(5d13241b-9d46-448a-90d8-77c418491026)] interface nsIDNSByTypeRecord : nsIDNSRecord { /** @@ -43,10 +43,10 @@ interface nsIDNSByTypeRecord : nsIDNSRecord [noscript] readonly attribute TypeResult results; }; -[scriptable, uuid(2a71750d-cb21-45f1-9e1c-666d18dd7645)] +[scriptable, builtinclass, uuid(2a71750d-cb21-45f1-9e1c-666d18dd7645)] interface nsIDNSTXTRecord : nsISupports { - CStringArrayRef getRecords(); + [noscript] CStringArrayRef getRecords(); /* * Return concatenated strings. diff --git a/netwerk/dns/nsIDNSRecord.idl b/netwerk/dns/nsIDNSRecord.idl index 27df2e28be2d..ebe8869c60db 100644 --- a/netwerk/dns/nsIDNSRecord.idl +++ b/netwerk/dns/nsIDNSRecord.idl @@ -26,12 +26,12 @@ interface nsINetAddr; * like an enumerator, allowing the caller to easily step through the * list of IP addresses. */ -[scriptable, uuid(f92228ae-c417-4188-a604-0830a95e7eb9)] +[scriptable, builtinclass, uuid(f92228ae-c417-4188-a604-0830a95e7eb9)] interface nsIDNSRecord : nsISupports { }; -[scriptable, uuid(cb260e20-943f-4309-953b-78c90d3a7638)] +[scriptable, builtinclass, uuid(cb260e20-943f-4309-953b-78c90d3a7638)] interface nsIDNSAddrRecord : nsIDNSRecord { /** diff --git a/netwerk/protocol/http/nsIHttpChannelInternal.idl b/netwerk/protocol/http/nsIHttpChannelInternal.idl index 64f41be28be0..620718f4bbe0 100644 --- a/netwerk/protocol/http/nsIHttpChannelInternal.idl +++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl @@ -56,7 +56,7 @@ interface nsIHttpUpgradeListener : nsISupports [must_use] void onUpgradeFailed(in nsresult aErrorCode); - void onWebSocketConnectionAvailable(in WebSocketConnectionBase aConnection); + [noscript] void onWebSocketConnectionAvailable(in WebSocketConnectionBase aConnection); }; /** diff --git a/netwerk/protocol/websocket/nsIWebSocketChannel.idl b/netwerk/protocol/websocket/nsIWebSocketChannel.idl index 7092c3c6b114..555d6d8168ea 100644 --- a/netwerk/protocol/websocket/nsIWebSocketChannel.idl +++ b/netwerk/protocol/websocket/nsIWebSocketChannel.idl @@ -146,7 +146,7 @@ interface nsIWebSocketChannel : nsISupports in nsIWebSocketListener aListener, in nsISupports aContext); - [must_use] + [must_use, noscript] void asyncOpenNative(in nsIURI aURI, in ACString aOrigin, in OriginAttributes aOriginAttributes, diff --git a/netwerk/protocol/webtransport/nsIWebTransport.idl b/netwerk/protocol/webtransport/nsIWebTransport.idl index 8055a4c1b4bf..3afe9979bae9 100644 --- a/netwerk/protocol/webtransport/nsIWebTransport.idl +++ b/netwerk/protocol/webtransport/nsIWebTransport.idl @@ -44,6 +44,7 @@ interface nsIWebTransport : nsISupports { in unsigned long aSecurityFlags, in WebTransportSessionEventListener aListener); + [noscript] void asyncConnectWithClient(in nsIURI aURI, in boolean aDedicated, in Array aServerCertHashes, diff --git a/netwerk/socket/nsINamedPipeService.idl b/netwerk/socket/nsINamedPipeService.idl index 9db557577d1a..ce189ae9d39b 100644 --- a/netwerk/socket/nsINamedPipeService.idl +++ b/netwerk/socket/nsINamedPipeService.idl @@ -12,7 +12,7 @@ * This is the callback interface for nsINamedPipeService. * The functions are called by the internal thread in the nsINamedPipeService. */ -[scriptable, uuid(de4f460b-94fd-442c-9002-1637beb2185a)] +[uuid(de4f460b-94fd-442c-9002-1637beb2185a)] interface nsINamedPipeDataObserver : nsISupports { /** @@ -41,7 +41,7 @@ interface nsINamedPipeDataObserver : nsISupports /** * nsINamedPipeService */ -[scriptable, uuid(1bf19133-5625-4ac8-836a-80b1c215f72b)] +[uuid(1bf19133-5625-4ac8-836a-80b1c215f72b)] interface nsINamedPipeService : nsISupports { /** diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl index 517c87a285dd..217beda78edf 100644 --- a/toolkit/components/browser/nsIWebBrowserChrome.idl +++ b/toolkit/components/browser/nsIWebBrowserChrome.idl @@ -15,7 +15,7 @@ interface nsIDocShellTreeItem; * containing an embedded Gecko web browser. */ -[scriptable, uuid(E8C414C4-DC38-4BA3-AB4E-EC4CBBE22907)] +[scriptable, builtinclass, uuid(E8C414C4-DC38-4BA3-AB4E-EC4CBBE22907)] interface nsIWebBrowserChrome : nsISupports { /** @@ -124,7 +124,7 @@ interface nsIWebBrowserChrome : nsISupports * * @see nsIBaseWindow */ - void setDimensions(in DimensionRequest aRequest); + [noscript] void setDimensions(in DimensionRequest aRequest); /** * Gets the dimensions of the window. The caller may pass @@ -134,7 +134,7 @@ interface nsIWebBrowserChrome : nsISupports * * @see nsIBaseWindow */ - void getDimensions(in DimensionKind aDimensionKind, out long aX, out long aY, out long aCX, out long aCY); + [noscript] void getDimensions(in DimensionKind aDimensionKind, out long aX, out long aY, out long aCX, out long aCY); /** * Blur the window. This should unfocus the window and send an onblur event. diff --git a/toolkit/components/windowcreator/nsIWindowProvider.idl b/toolkit/components/windowcreator/nsIWindowProvider.idl index d16927a94936..467d45246a18 100644 --- a/toolkit/components/windowcreator/nsIWindowProvider.idl +++ b/toolkit/components/windowcreator/nsIWindowProvider.idl @@ -33,7 +33,7 @@ native nsDocShellLoadStatePtr(nsDocShellLoadState*); * or the provider does not provide a window, the window watcher will proceed * to actually open a new window. */ -[scriptable, uuid(e97a3830-15ef-499b-8372-c22d128091c1)] +[scriptable, builtinclass, uuid(e97a3830-15ef-499b-8372-c22d128091c1)] interface nsIWindowProvider : nsISupports { /** diff --git a/widget/nsIBaseWindow.idl b/widget/nsIBaseWindow.idl index 3cf71937881a..3e0dadbdd56f 100644 --- a/widget/nsIBaseWindow.idl +++ b/widget/nsIBaseWindow.idl @@ -161,7 +161,7 @@ interface nsIBaseWindow : nsISupports * * @see DimensionRequest */ - void setDimensions(in DimensionRequest aRequest); + [noscript] void setDimensions(in DimensionRequest aRequest); /** * Gets the dimensions of the window. The caller may pass nullptr for any @@ -178,7 +178,7 @@ interface nsIBaseWindow : nsISupports * * @see DimensionRequest */ - void getDimensions(in DimensionKind aDimensionKind, out long aX, out long aY, out long aCX, out long aCY); + [noscript] void getDimensions(in DimensionKind aDimensionKind, out long aX, out long aY, out long aCX, out long aCY); /** * Tell the window to repaint itself @@ -210,7 +210,7 @@ interface nsIBaseWindow : nsISupports On controls that don't support setting nativeWindow parents, setting this will return a NS_ERROR_NOT_IMPLEMENTED error. */ - attribute nativeWindow parentNativeWindow; + [noscript] attribute nativeWindow parentNativeWindow; /* This is the handle (HWND, GdkWindow*, ...) to the native window of the diff --git a/widget/nsIDragService.idl b/widget/nsIDragService.idl index a35d3128a842..619c8f8a8232 100644 --- a/widget/nsIDragService.idl +++ b/widget/nsIDragService.idl @@ -126,7 +126,7 @@ interface nsIDragService : nsISupports * * Note: This method is deprecated for non-native code. */ - [can_run_script] + [noscript, can_run_script] void invokeDragSessionWithSelection(in Selection aSelection, in nsIPrincipal aPrincipal, in nsIContentSecurityPolicy aCsp, diff --git a/widget/nsIScreen.idl b/widget/nsIScreen.idl index af8371edb35b..619b8bc284ab 100644 --- a/widget/nsIScreen.idl +++ b/widget/nsIScreen.idl @@ -75,7 +75,7 @@ interface nsIScreen : nsISupports /** * ScreenColorGamut is native type, which cannot be declared [infallible]. */ - readonly attribute ScreenColorGamut colorGamut; + [noscript] readonly attribute ScreenColorGamut colorGamut; /** * The number of device pixels per desktop pixel for this screen (for diff --git a/xpcom/idl-parser/xpidl/xpidl.py b/xpcom/idl-parser/xpidl/xpidl.py index 901bf09a766b..59e4e355dec6 100755 --- a/xpcom/idl-parser/xpidl/xpidl.py +++ b/xpcom/idl-parser/xpidl/xpidl.py @@ -1216,19 +1216,24 @@ def ensureInfallibleIsSound(methodOrAttribute): if methodOrAttribute.notxpcom: raise IDLError( - "[infallible] does not make sense for a [notxpcom] " "method or attribute", + "[infallible] does not make sense for a [notxpcom] method or attribute", methodOrAttribute.location, ) # An interface cannot be implemented by JS if it has a notxpcom or nostdcall -# method or attribute, so it must be marked as builtinclass. +# method or attribute, or uses a by-value native type, so it must be marked as +# builtinclass. def ensureBuiltinClassIfNeeded(methodOrAttribute): iface = methodOrAttribute.iface if not iface.attributes.scriptable or iface.attributes.builtinclass: return if iface.name == "nsISupports": return + + # notxpcom and nostdcall types change calling conventions, which breaks + # xptcall wrappers. We cannot allow XPCWrappedJS to be created for + # interfaces with these methods. if methodOrAttribute.notxpcom: raise IDLError( ( @@ -1248,6 +1253,84 @@ def ensureBuiltinClassIfNeeded(methodOrAttribute): methodOrAttribute.location, ) + # Methods with custom native parameters passed without indirection cannot be + # safely handled by xptcall (as it cannot know the calling stack/register + # layout), so require the interface to be builtinclass. + # + # Only "in" parameters and writable attributes are checked, as other + # parameters are always passed indirectly, so do not impact calling + # conventions. + def typeNeedsBuiltinclass(type): + inner = type + while inner.kind == "typedef": + inner = inner.realtype + return ( + inner.kind == "native" + and inner.specialtype is None + and inner.modifier is None + ) + + if methodOrAttribute.kind == "method": + for p in methodOrAttribute.params: + if p.paramtype == "in" and typeNeedsBuiltinclass(p.realtype): + raise IDLError( + ( + "scriptable interface '%s' must be marked [builtinclass] " + "because it contains method '%s' with a by-value custom native " + "parameter '%s'" + ) + % (iface.name, methodOrAttribute.name, p.name), + methodOrAttribute.location, + ) + elif methodOrAttribute.kind == "attribute" and not methodOrAttribute.readonly: + if typeNeedsBuiltinclass(methodOrAttribute.realtype): + raise IDLError( + ( + "scriptable interface '%s' must be marked [builtinclass] because it " + "contains writable attribute '%s' with a by-value custom native type" + ) + % (iface.name, methodOrAttribute.name), + methodOrAttribute.location, + ) + + +def ensureNoscriptIfNeeded(methodOrAttribute): + if not methodOrAttribute.isScriptable(): + return + + # NOTE: We can't check forward-declared interfaces to see if they're + # scriptable, as the information about whether they're scriptable is not + # known here. + def typeNeedsNoscript(type): + if type.kind in ["array", "legacyarray"]: + return typeNeedsNoscript(type.type) + if type.kind == "typedef": + return typeNeedsNoscript(type.realtype) + if type.kind == "native": + return type.specialtype is None + if type.kind == "interface": + return not type.attributes.scriptable + return False + + if typeNeedsNoscript(methodOrAttribute.realtype): + raise IDLError( + "%s '%s' must be marked [noscript] because it has a non-scriptable type" + % (methodOrAttribute.kind, methodOrAttribute.name), + methodOrAttribute.location, + ) + if methodOrAttribute.kind == "method": + for p in methodOrAttribute.params: + # iid_is arguments have their type ignored, so shouldn't be checked. + if not p.iid_is and typeNeedsNoscript(p.realtype): + raise IDLError( + ( + "method '%s' must be marked [noscript] because it has a " + "non-scriptable parameter '%s'" + ) + % (methodOrAttribute.name, p.name), + methodOrAttribute.location, + ) + class Attribute(object): kind = "attribute" @@ -1336,6 +1419,7 @@ class Attribute(object): ensureInfallibleIsSound(self) ensureBuiltinClassIfNeeded(self) + ensureNoscriptIfNeeded(self) def toIDL(self): attribs = attlistToIDL(self.attlist) @@ -1422,9 +1506,6 @@ class Method(object): self.iface = iface self.realtype = self.iface.idl.getName(self.type, self.location) - ensureInfallibleIsSound(self) - ensureBuiltinClassIfNeeded(self) - for p in self.params: p.resolve(self) for p in self.params: @@ -1464,6 +1545,10 @@ class Method(object): self.location, ) + ensureInfallibleIsSound(self) + ensureBuiltinClassIfNeeded(self) + ensureNoscriptIfNeeded(self) + def isScriptable(self): if not self.iface.attributes.scriptable: return False diff --git a/xpcom/io/nsIConverterInputStream.idl b/xpcom/io/nsIConverterInputStream.idl index ad1f9bfbc41f..1474564a3702 100644 --- a/xpcom/io/nsIConverterInputStream.idl +++ b/xpcom/io/nsIConverterInputStream.idl @@ -12,7 +12,7 @@ interface nsIInputStream; * This allows reading unicode strings from a stream, automatically converting * the bytes from a selected character encoding. */ -[scriptable, uuid(FC66FFB6-5404-4908-A4A3-27F92FA0579D)] +[scriptable, builtinclass, uuid(FC66FFB6-5404-4908-A4A3-27F92FA0579D)] interface nsIConverterInputStream : nsIUnicharInputStream { /** * Default replacement char value, U+FFFD REPLACEMENT CHARACTER. diff --git a/xpcom/io/nsIUnicharInputStream.idl b/xpcom/io/nsIUnicharInputStream.idl index 3ae467cc8334..5f1b4a6d8e6c 100644 --- a/xpcom/io/nsIUnicharInputStream.idl +++ b/xpcom/io/nsIUnicharInputStream.idl @@ -42,7 +42,7 @@ native nsWriteUnicharSegmentFun(nsWriteUnicharSegmentFun); * Abstract UTF-16 input stream * @see nsIInputStream */ -[scriptable, uuid(d5e3bd80-6723-4b92-b0c9-22f6162fd94f)] +[scriptable, builtinclass, uuid(d5e3bd80-6723-4b92-b0c9-22f6162fd94f)] interface nsIUnicharInputStream : nsISupports { /** * Reads into a caller-provided array. diff --git a/xpcom/reflect/xptinfo/xptcodegen.py b/xpcom/reflect/xptinfo/xptcodegen.py index 9dd54a6f0785..67860ca1f2d8 100644 --- a/xpcom/reflect/xptinfo/xptcodegen.py +++ b/xpcom/reflect/xptinfo/xptcodegen.py @@ -330,30 +330,11 @@ def link_to_cpp(interfaces, fd, header_fd): ) ) - def is_type_reflectable(type): - # All native types end up getting tagged as void*, or as wrapper types around void* - if type["tag"] == "TD_VOID": - return False - if type["tag"] in ("TD_ARRAY", "TD_LEGACY_ARRAY"): - return is_type_reflectable(type["element"]) - return True - - def is_method_reflectable(method): - if "hidden" in method["flags"]: - return False - - for param in method["params"]: - # Reflected methods can't use non-reflectable types. - if not is_type_reflectable(param["type"]): - return False - - return True - def lower_method(method, ifacename, builtinclass): methodname = "%s::%s" % (ifacename, method["name"]) isSymbol = "symbol" in method["flags"] - reflectable = is_method_reflectable(method) + reflectable = "hidden" not in method["flags"] if not reflectable and builtinclass: # Hide the parameters of methods that can't be called from JS and diff --git a/xpcom/threads/nsIThreadManager.idl b/xpcom/threads/nsIThreadManager.idl index 9629cb630aa5..2c5de409fe44 100644 --- a/xpcom/threads/nsIThreadManager.idl +++ b/xpcom/threads/nsIThreadManager.idl @@ -29,7 +29,7 @@ interface nsINestedEventLoopCondition : nsISupports /** * An interface for creating and locating nsIThread instances. */ -[scriptable, uuid(1be89eca-e2f7-453b-8d38-c11ba247f6f3)] +[scriptable, builtinclass, uuid(1be89eca-e2f7-453b-8d38-c11ba247f6f3)] interface nsIThreadManager : nsISupports { /**