Skip to content

AVRO-4312: [csharp] Validate names against the Avro name grammar#3890

Open
iemejia wants to merge 3 commits into
apache:mainfrom
iemejia:AVRO-4312-csharp-name-validation
Open

AVRO-4312: [csharp] Validate names against the Avro name grammar#3890
iemejia wants to merge 3 commits into
apache:mainfrom
iemejia:AVRO-4312-csharp-name-validation

Conversation

@iemejia

@iemejia iemejia commented Jul 20, 2026

Copy link
Copy Markdown
Member

What is the purpose of the change

Record/fixed/enum names, record field names and protocol message names were
accepted verbatim when parsing, unlike enum symbols which were already
validated. Because the code generator splices some of these values directly
into generated C# source (for example protocol message names into a case
label and field names into Get/Put switch bodies), an out-of-spec name
produced malformed or unexpected generated code.

This change adds a shared, Unicode-aware name validator (first character a
letter or _, remaining characters letters, digits or _) and applies it to
schema names, field names and message names during parsing.

Notes:

  • The rule is Unicode-aware to preserve the existing support for non-ASCII
    names (e.g. the TestRecordFieldNames case).
  • Namespaces are intentionally not validated, because the code generator's
    namespace-mapping feature rewrites them to C#-specific values (such as
    @return for reserved words) and re-parses the schema.

Part of AVRO-4312.

Verifying this change

This change added tests and can be verified as follows:

  • Added negative cases to Schema/SchemaTests.cs (invalid record name, invalid
    field name, and a field name attempting identifier injection) and
    Protocol/ProtocolTest.cs (TestInvalidMessageName).
  • Verified locally: the full Avro.test suite (1526 tests) passes, including
    the AvroGen code-generation tests.

Documentation

  • Does this pull request introduce a new feature? no
  • If yes, how is the feature documented? not applicable

Record/fixed/enum names, record field names and protocol message names
were accepted verbatim when parsing, unlike enum symbols which were
already validated. Because the code generator splices some of these
values directly into generated C# source (for example protocol message
names into a case label and field names into Get/Put switch bodies), an
out-of-spec name produced malformed or unexpected generated code.

Add a shared, Unicode-aware name validator (first character a letter or
'_', remaining characters letters, digits or '_') and apply it to
schema names, field names and message names during parsing. The rule is
Unicode-aware to preserve the existing support for non-ASCII names, and
namespaces are intentionally not validated because the code generator's
namespace-mapping feature rewrites them to C#-specific values (such as
"@return") and re-parses the schema. Add negative tests for invalid
field, record and message names.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Avro name-grammar validation to the C# implementation to prevent invalid schema/field/message names from being accepted during parsing (protecting AvroGen/codegen from malformed identifiers and identifier-injection style inputs).

Changes:

  • Introduces a shared SchemaName.ValidateName helper and enforces it for schema names, record field names, and protocol message names.
  • Adds negative tests covering invalid record names, invalid field names, and invalid protocol message names.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
lang/csharp/src/apache/test/Schema/SchemaTests.cs Adds negative schema-parse cases for invalid record/field names.
lang/csharp/src/apache/test/Protocol/ProtocolTest.cs Adds negative protocol-parse cases for invalid message names.
lang/csharp/src/apache/main/Schema/SchemaName.cs Introduces centralized name validation and applies it to schema simple names.
lang/csharp/src/apache/main/Schema/Field.cs Enforces name validation for record field names.
lang/csharp/src/apache/main/Protocol/Message.cs Enforces name validation for protocol message names.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

throw new ArgumentNullException(nameof(name), "name cannot be null.");
}

SchemaName.ValidateName(name, "field");
Comment on lines +41 to +55
if (string.IsNullOrEmpty(name)
|| !(char.IsLetter(name[0]) || name[0] == '_'))
{
throw new SchemaParseException($"Invalid {what} name: {name}");
}

for (int i = 1; i < name.Length; i++)
{
char c = name[i];
if (!(char.IsLetterOrDigit(c) || c == '_'))
{
throw new SchemaParseException($"Invalid {what} name: {name}");
}
}
}
Address review feedback:
- Validate record field aliases with the same rule as field names, since
  aliases participate in schema resolution and are names per the Avro
  grammar. Previously they were accepted verbatim.
- Escape control characters (and quote the value) when embedding an
  invalid name in the SchemaParseException message, so a crafted name
  containing newlines or other control characters cannot produce
  multi-line or ambiguous error output.

Add a negative test for an invalid field alias.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment on lines +41 to +57
internal static void ValidateName(string name, string what)
{
if (string.IsNullOrEmpty(name)
|| !(char.IsLetter(name[0]) || name[0] == '_'))
{
throw new SchemaParseException($"Invalid {what} name: {Quote(name)}");
}

for (int i = 1; i < name.Length; i++)
{
char c = name[i];
if (!(char.IsLetterOrDigit(c) || c == '_'))
{
throw new SchemaParseException($"Invalid {what} name: {Quote(name)}");
}
}
}
Address review feedback: ValidateName inspected individual UTF-16 code
units, which rejected valid supplementary-plane letters and digits that
are encoded as surrogate pairs. Iterate by Unicode scalar value using
the char.IsLetter(string, int) / char.IsLetterOrDigit(string, int)
overloads and advance past surrogate pairs. Add a test that a name
containing a supplementary-plane letter (U+20000) is accepted.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants