Bug 1873386 - Interfaces referenced from scriptable members need to be [scriptable] r=necko-reviewers,jschanck,mccr8,valentin

Differential Revision: https://phabricator.services.mozilla.com/D202104
This commit is contained in:
Tomislav Jovanovic 2024-04-09 11:29:22 +00:00
parent 24d759d2a0
commit 392dac6191
9 changed files with 51 additions and 17 deletions

View file

@ -39,12 +39,14 @@ interface nsIWebAuthnService : nsISupports
// IsUserVerifyingPlatformAuthenticatorAvailable
readonly attribute boolean isUVPAA;
[noscript]
void makeCredential(
in uint64_t aTransactionId,
in uint64_t browsingContextId,
in nsIWebAuthnRegisterArgs args,
in nsIWebAuthnRegisterPromise promise);
[noscript]
void getAssertion(
in uint64_t aTransactionId,
in uint64_t browsingContextId,

View file

@ -26,7 +26,7 @@ interface nsIAsyncVerifyRedirectReadyCallback : nsISupports
* Implemented by chrome side of IPC protocols that support redirect responses.
*/
[scriptable, uuid(3ed1d288-5324-46ee-8a98-33ac37d1080b)]
[uuid(3ed1d288-5324-46ee-8a98-33ac37d1080b)]
interface nsIParentRedirectingChannel : nsIParentChannel
{
/**

View file

@ -37,6 +37,7 @@ interface nsIStreamTransportService : nsISupports
nsITransport createInputTransport(in nsIInputStream aStream,
in boolean aCloseWhenDone);
[noscript]
void InputAvailable(in nsIInputStream aStream,
in nsIInputAvailableCallback aCallback);
};

View file

@ -116,7 +116,7 @@ interface nsIUDPSocket : nsISupports
* If it is used off the socket thread there is a risk of triggering a bug
* in OS thatcan cause a crash.
*/
void syncListen(in nsIUDPSocketSyncListener aListener);
[noscript] void syncListen(in nsIUDPSocketSyncListener aListener);
/**
* connect

View file

@ -174,7 +174,7 @@ interface nsICertStorage : nsISupports {
* - STATE_NO_FILTER if there is no (usable) CRLite filter.
* No lookup is performed in the STATE_NOT_ENROLLED and STATE_NOT_COVERED cases.
*/
[must_use]
[must_use, noscript]
short getCRLiteRevocationState(in Array<octet> issuer,
in Array<octet> issuerSPKI,
in Array<octet> serialNumber,
@ -203,7 +203,7 @@ interface nsICertStorage : nsISupports {
* this issuer SPKI and serial number is revoked according to the current set of stashed CRLite
* revocation information.
*/
[must_use]
[must_use, noscript]
boolean isCertRevokedByStash(in Array<octet> issuerSPKI, in Array<octet> serialNumber);
/**

View file

@ -28,7 +28,7 @@ interface nsIClassInfo : nsISupports
* Return an object to assist XPConnect in supplying JavaScript-specific
* behavior to callers of the instance object, or null if not needed.
*/
nsIXPCScriptable getScriptableHelper();
[noscript] nsIXPCScriptable getScriptableHelper();
/**
* A contract ID through which an instance of this class can be created

View file

@ -47,7 +47,7 @@ def flags(*flags):
return [flag for flag, cond in flags if cond]
def get_type(type, calltype, iid_is=None, size_is=None):
def get_type(type, calltype, iid_is=None, size_is=None, needs_scriptable=None):
while isinstance(type, xpidl.Typedef):
type = type.realtype
@ -63,7 +63,7 @@ def get_type(type, calltype, iid_is=None, size_is=None):
# This allows Arrays of InterfaceIs types to work.
return {
"tag": "TD_ARRAY",
"element": get_type(type.type, calltype, iid_is),
"element": get_type(type.type, calltype, iid_is, None, needs_scriptable),
}
if isinstance(type, xpidl.LegacyArray):
@ -72,10 +72,12 @@ def get_type(type, calltype, iid_is=None, size_is=None):
return {
"tag": "TD_LEGACY_ARRAY",
"size_is": size_is,
"element": get_type(type.type, calltype, iid_is),
"element": get_type(type.type, calltype, iid_is, None, needs_scriptable),
}
if isinstance(type, xpidl.Interface) or isinstance(type, xpidl.Forward):
if isinstance(needs_scriptable, set):
needs_scriptable.add(type.name)
return {
"tag": "TD_INTERFACE_TYPE",
"name": type.name,
@ -163,6 +165,9 @@ def build_interface(iface):
consts = []
methods = []
# Interfaces referenced from scriptable members need to be [scriptable].
needs_scriptable = set()
def build_const(c):
consts.append(
{
@ -182,7 +187,7 @@ def build_interface(iface):
}
)
def build_method(m):
def build_method(m, needs_scriptable=None):
params = []
for p in m.params:
params.append(
@ -192,6 +197,7 @@ def build_interface(iface):
p.paramtype,
iid_is=attr_param_idx(p, m, "iid_is"),
size_is=attr_param_idx(p, m, "size_is"),
needs_scriptable=needs_scriptable,
),
in_=p.paramtype.count("in"),
out=p.paramtype.count("out"),
@ -202,33 +208,36 @@ def build_interface(iface):
hasretval = len(m.params) > 0 and m.params[-1].retval
if not m.notxpcom and m.realtype.name != "void":
hasretval = True
params.append(mk_param(get_type(m.realtype, "out"), out=1))
type = get_type(m.realtype, "out", needs_scriptable=needs_scriptable)
params.append(mk_param(type, out=1))
methods.append(
mk_method(m, params, optargc=m.optional_argc, hasretval=hasretval)
)
def build_attr(a):
def build_attr(a, needs_scriptable=None):
assert a.realtype.name != "void"
# Write the getter
getter_params = []
if not a.notxpcom:
getter_params.append(mk_param(get_type(a.realtype, "out"), out=1))
type = get_type(a.realtype, "out", needs_scriptable=needs_scriptable)
getter_params.append(mk_param(type, out=1))
methods.append(mk_method(a, getter_params, getter=1, hasretval=1))
# And maybe the setter
if not a.readonly:
param = mk_param(get_type(a.realtype, "in"), in_=1)
methods.append(mk_method(a, [param], setter=1))
type = get_type(a.realtype, "in", needs_scriptable=needs_scriptable)
methods.append(mk_method(a, [mk_param(type, in_=1)], setter=1))
for member in iface.members:
if isinstance(member, xpidl.ConstMember):
build_const(member)
elif isinstance(member, xpidl.Attribute):
build_attr(member)
build_attr(member, member.isScriptable() and needs_scriptable)
elif isinstance(member, xpidl.Method):
build_method(member)
build_method(member, member.isScriptable() and needs_scriptable)
elif isinstance(member, xpidl.CEnum):
build_cenum(member)
elif isinstance(member, xpidl.CDATA):
@ -236,12 +245,24 @@ def build_interface(iface):
else:
raise Exception("Unexpected interface member: %s" % member)
for ref in set(needs_scriptable):
p = iface.idl.getName(xpidl.TypeId(ref), None)
if isinstance(p, xpidl.Interface):
needs_scriptable.remove(ref)
if not p.attributes.scriptable:
raise Exception(
f"Scriptable member in {iface.name} references non-scriptable {ref}. "
"The interface must be marked as [scriptable], "
"or the referencing member with [noscript]."
)
return {
"name": iface.name,
"uuid": iface.attributes.uuid,
"methods": methods,
"consts": consts,
"parent": iface.base,
"needs_scriptable": sorted(needs_scriptable),
"flags": flags(
("function", iface.attributes.function),
("builtinclass", iface.attributes.builtinclass),

View file

@ -625,6 +625,16 @@ def link_and_write(files, outfile, outheader):
iids.add(interface["uuid"])
names.add(interface["name"])
# All forwards referenced from scriptable members must be known (as scriptable).
for iface in interfaces:
for ref in iface["needs_scriptable"]:
if not ref in names:
raise Exception(
f"Scriptable member in {iface['name']} references unknown {ref}. "
"Forward must be a known and [scriptable] interface, "
"or the referencing member marked with [noscript]."
)
link_to_cpp(interfaces, outfile, outheader)

View file

@ -13,7 +13,7 @@ interface nsIThreadObserver;
* The XPCOM thread object implements this interface, which allows a consumer
* to observe dispatch activity on the thread.
*/
[builtinclass, scriptable, rust_sync, uuid(a3a72e5f-71d9-4add-8f30-59a78fb6d5eb)]
[rust_sync, uuid(a3a72e5f-71d9-4add-8f30-59a78fb6d5eb)]
interface nsIThreadInternal : nsIThread
{
/**