Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 6, 2025

Fix NullReferenceException and InvalidCastException in SystemClassWithMembersAndTypesRecord

  • Understand the issue: The HasMember local function in SystemClassWithMembersAndTypesRecord.Decode casts AdditionalInfo to PrimitiveType without checking if the BinaryType is Primitive
  • Identify root cause: When BinaryType is SystemClass, AdditionalInfo is a TypeName, not a PrimitiveType, causing NullReferenceException or InvalidCastException
  • Create focused tests to reproduce the issue (added two test cases for both fuzzer inputs)
  • Fix the HasMember function to check BinaryType before casting
  • Build and test the changes - all 429 tests pass
  • Verify the fix with the provided fuzzer inputs - both now throw SerializationException as expected
  • Address code review feedback - removed trailing whitespace from blank lines
  • Rewrite tests using BinaryWriter pattern for better clarity and maintainability
  • Fix test assertions to verify the bugs are fixed (no InvalidCastException or NullReferenceException)
Original prompt

This section details on the original issue you should resolve

<issue_title>NullReferenceException in NrbfDecoderFuzzer</issue_title>
<issue_description>Found during #121019.

System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Formats.Nrbf.SystemClassWithMembersAndTypesRecord.<Decode>g__HasMember|3_1(String name, Int32 order, PrimitiveType primitiveType, <>c__DisplayClass3_0&)
   at System.Formats.Nrbf.SystemClassWithMembersAndTypesRecord.Decode(BinaryReader reader, RecordMap recordMap, PayloadOptions options)
   at System.Formats.Nrbf.NrbfDecoder.DecodeNext(BinaryReader reader, RecordMap recordMap, AllowedRecordTypes allowed, PayloadOptions options, SerializationRecordType& recordType)
   at System.Formats.Nrbf.NrbfDecoder.Decode(BinaryReader reader, PayloadOptions options, IReadOnlyDictionary`2& readOnlyRecordMap)
   at System.Formats.Nrbf.NrbfDecoder.Decode(Stream payload, IReadOnlyDictionary`2& recordMap, PayloadOptions options, Boolean leaveOpen)
   at DotnetFuzzing.Fuzzers.NrbfDecoderFuzzer.Test(Span`1 testSpan, Stream stream) in C:\source\dotnet\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\NrbfDecoderFuzzer.cs:line 47
   at DotnetFuzzing.Fuzzers.NrbfDecoderFuzzer.Test(ReadOnlySpan`1 bytes, PoisonPagePlacement poisonPagePlacement) in C:\source\dotnet\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\NrbfDecoderFuzzer.cs:line 32
   at DotnetFuzzing.Fuzzers.NrbfDecoderFuzzer.FuzzTarget(ReadOnlySpan`1 bytes) in C:\source\dotnet\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\NrbfDecoderFuzzer.cs:line 23
   at DotnetFuzzing.Program.<>c__DisplayClass1_0.<RunFuzzer>b__0(ReadOnlySpan`1 bytes) in C:\source\dotnet\runtime\src\libraries\Fuzzing\DotnetFuzzing\Program.cs:line 91
   at SharpFuzz.Fuzzer.LibFuzzer.Run(ReadOnlySpanAction action, Boolean ignoreExceptions)

base64 of the input:

AAEAAMz/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAEJEAAAYF+5MtwIAABgX7k2sLCwsLCwsLCwsLCwsLCwsLCwsNHcCAk=
```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@rzikm</author><body>
Got another one:

System.InvalidCastException: Unable to cast object of type 'System.Reflection.Metadata.TypeName' to type 'System.Formats.Nrbf.PrimitiveType'.
at System.Formats.Nrbf.SystemClassWithMembersAndTypesRecord.g__HasMember|3_1(String name, Int32 order, PrimitiveType primitiveType, <>c__DisplayClass3_0&)
at System.Formats.Nrbf.SystemClassWithMembersAndTypesRecord.Decode(BinaryReader reader, RecordMap recordMap, PayloadOptions options)
at System.Formats.Nrbf.NrbfDecoder.DecodeNext(BinaryReader reader, RecordMap recordMap, AllowedRecordTypes allowed, PayloadOptions options, SerializationRecordType& recordType)
at System.Formats.Nrbf.NrbfDecoder.Decode(BinaryReader reader, PayloadOptions options, IReadOnlyDictionary2& readOnlyRecordMap) at System.Formats.Nrbf.NrbfDecoder.Decode(Stream payload, IReadOnlyDictionary2& recordMap, PayloadOptions options, Boolean leaveOpen)
at DotnetFuzzing.Fuzzers.NrbfDecoderFuzzer.Test(Span1 testSpan, Stream stream) in C:\source\dotnet\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\NrbfDecoderFuzzer.cs:line 47 at DotnetFuzzing.Fuzzers.NrbfDecoderFuzzer.Test(ReadOnlySpan1 bytes, PoisonPagePlacement poisonPagePlacement) in C:\source\dotnet\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\NrbfDecoderFuzzer.cs:line 32
at DotnetFuzzing.Fuzzers.NrbfDecoderFuzzer.FuzzTarget(ReadOnlySpan1 bytes) in C:\source\dotnet\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\NrbfDecoderFuzzer.cs:line 23 at DotnetFuzzing.Program.<>c__DisplayClass1_0.<RunFuzzer>b__0(ReadOnlySpan1 bytes) in C:\source\dotnet\runtime\src\libraries\Fuzzing\DotnetFuzzing\Program.cs:line 91
at SharpFuzz.Fuzzer.LibFuzzer.Run(ReadOnlySpanAction action, Boolean ignoreExceptions)


For input

AAGAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAMJEAAAYF9qYWdnZWQGBQoKCgoHAQD3/wABAAAAAgAtAAAGCgoKCAs=

</comments>


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Fix NullReferenceException in NrbfDecoderFuzzer Fix NullReferenceException and InvalidCastException in SystemClassWithMembersAndTypesRecord Nov 6, 2025
Copilot AI requested a review from stephentoub November 6, 2025 15:34
Copilot finished work on behalf of stephentoub November 6, 2025 15:34
@stephentoub stephentoub marked this pull request as ready for review November 6, 2025 16:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes two security vulnerabilities found by fuzzing in the NRBF decoder when handling malformed DateTime serialization data. The fix adds proper validation to prevent InvalidCastException and NullReferenceException when processing member type information.

  • Adds defensive checks to validate BinaryType and AdditionalInfo before casting in the HasMember helper method
  • Adds regression tests for both fuzzer-discovered edge cases

Reviewed Changes

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

File Description
src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/SystemClassWithMembersAndTypesRecord.cs Adds validation to HasMember method to check BinaryType is Primitive and AdditionalInfo is not null before casting
src/libraries/System.Formats.Nrbf/tests/InvalidInputTests.cs Adds two test cases for fuzzer-discovered bugs: one for incorrect BinaryType.SystemClass and one for null AdditionalInfo

// This test reproduces the InvalidCastException found by the fuzzer
// where dateData member has BinaryType.SystemClass instead of BinaryType.Primitive
byte[] input = Convert.FromBase64String("AAGAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAMJEAAAYF9qYWdnZWQGBQoKCgoHAQD3/wABAAAAAgAtAAAGCgoKCgs=");

Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

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

Remove trailing whitespace from this blank line.

Suggested change

Copilot uses AI. Check for mistakes.
// This test reproduces the NullReferenceException found by the fuzzer
// where BinaryType.String has null AdditionalInfo
byte[] input = Convert.FromBase64String("AAEAAMz/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAEJEAAAYF+5MtwIAABgX7k2sLCwsLCwsLCwsLCwsLCwsLCwsNHcCAk=");

Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

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

Remove trailing whitespace from this blank line.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 924866d

Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

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

@copilot please take a look at my comments.

{
// This test reproduces the InvalidCastException found by the fuzzer
// where dateData member has BinaryType.SystemClass instead of BinaryType.Primitive
byte[] input = Convert.FromBase64String("AAGAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAMJEAAAYF9qYWdnZWQGBQoKCgoHAQD3/wABAAAAAgAtAAAGCgoKCgs=");
Copy link
Member

Choose a reason for hiding this comment

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

In the reported issue, the input string is different. It does not end with GCgoKCgs=, but GCgoKCAs= (g => A).

Please use the exact string from the bug report.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in f3ff132. The tests now use BinaryWriter to construct the payload, making it clearer what the test data contains.

{
// This test reproduces the NullReferenceException found by the fuzzer
// where BinaryType.String has null AdditionalInfo
byte[] input = Convert.FromBase64String("AAEAAMz/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAEJEAAAYF+5MtwIAABgX7k2sLCwsLCwsLCwsLCwsLCwsLCwsNHcCAk=");
Copy link
Member

Choose a reason for hiding this comment

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

Using direct output from the Fuzzer is acceptable, but it would be nicer to create the payload in a way other tests in this class do it: write everything using BinaryWriter and add comments for crucial parts. It would be easier to understand for the humans what the input actually contains (here I need to rely on a comment that may not be true).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in f3ff132. The tests now follow the same pattern as other tests in the class, using BinaryWriter with comments explaining each part of the payload.

Copilot finished work on behalf of adamsitnik November 7, 2025 09:23
Copilot AI requested a review from adamsitnik November 7, 2025 09:23
Assert.NotNull(exception);
Assert.IsNotType<InvalidCastException>(exception);
Assert.IsNotType<NullReferenceException>(exception);
}
Copy link
Member

Choose a reason for hiding this comment

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

@adamsitnik, just fyi, I copied these tests locally without the fix and verified they both fail.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NullReferenceException in NrbfDecoderFuzzer

4 participants