[PATCH 4/5] xdrgen: Enforce RFC 5531 name and number scoping for RPC programs
Chuck Lever <[email protected]>
| Newsgroups | gmane.linux.nfs |
|---|---|
| Message-ID | <[email protected]> |
The duplicate-identifier check enforces the RFC 4506 name space for XDR type and constant identifiers but ignores what an RPC program definition adds. RFC 5531 Section 12.3 completes the model: a program identifier shares the specification-wide name space with constant and type identifiers, a version name and number are unique within their program, and a procedure name and number are unique within their version. xdrgen currently accepts a specification that breaks any of these rules, and the symptom depends on which rule. A duplicate procedure name reaches the generated header as a redeclared enumerator, which the C compiler rejects. A duplicate procedure number is more dangerous because it is silent: the two procedures emit enumerators of equal value -- valid C that compiles cleanly -- leaving a dispatch collision to surface only at run time. A duplicate program name shares the specification-wide name space with constants and types and is caught alongside them. Extend the check to enforce RFC 5531 scoping in full. Signed-off-by: Chuck Lever <[email protected]> --- tools/net/sunrpc/xdrgen/xdr_ast.py | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tools/net/sunrpc/xdrgen/xdr_ast.py b/tools/net/sunrpc/xdrgen/xdr_ast.py index cf68ff5dfe17..ec48506b239a 100644 --- a/tools/net/sunrpc/xdrgen/xdr_ast.py +++ b/tools/net/sunrpc/xdrgen/xdr_ast.py @@ -862,6 +862,50 @@ def _introduced_names(value): yield value.declaration.name, value.declaration elif isinstance(value, _XdrConstant): yield value.name, value + elif isinstance(value, _RpcProgram): + yield value.name, value + + +def _check_rpc_scope_names(program: "_RpcProgram") -> None: + """Enforce RFC 5531 Section 12.3 scoping within an RPC program. + + A version name and number are unique within the program and a + procedure name and number are unique within its version. + """ + version_names = set() + version_numbers = set() + for version in program.versions: + if version.name in version_names: + raise XdrSemanticError( + f"duplicate version name '{version.name}'" + f" in program '{program.name}'", + version, + ) + version_names.add(version.name) + if version.number in version_numbers: + raise XdrSemanticError( + f"duplicate version number {version.number}" + f" in program '{program.name}'", + version, + ) + version_numbers.add(version.number) + procedure_names = set() + procedure_numbers = set() + for procedure in version.procedures: + if procedure.name in procedure_names: + raise XdrSemanticError( + f"duplicate procedure name '{procedure.name}'" + f" in version '{version.name}'", + procedure, + ) + procedure_names.add(procedure.name) + if procedure.number in procedure_numbers: + raise XdrSemanticError( + f"duplicate procedure number {procedure.number}" + f" in version '{version.name}'", + procedure, + ) + procedure_numbers.add(procedure.number) def check_duplicate_definitions(root: "Specification") -> None: @@ -869,6 +913,9 @@ def check_duplicate_definitions(root: "Specification") -> None: RFC 4506 Section 6.4 places constant and type identifiers in a single name space that must be unique within a specification. + RFC 5531 Section 12.3 adds RPC program names to that name space + and scopes version names and numbers to their program and + procedure names and numbers to their version. """ seen = {} for definition in root.definitions: @@ -882,6 +929,8 @@ def check_duplicate_definitions(root: "Specification") -> None: where, ) seen[name] = where + if isinstance(definition.value, _RpcProgram): + _check_rpc_scope_names(definition.value) def transform_parse_tree(parse_tree): -- 2.54.0