Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Fix KeyValuePair nullability detection on Mono - #120910

#120910
Merged
BrzVlad merged 2 commits into
dotnet:maindotnet/runtime:mainfrom
medhatiwari:nullabilitymedhatiwari/runtime:nullabilityCopy head branch name to clipboard
Jan 13, 2026
Merged

Fix KeyValuePair nullability detection on Mono#120910
BrzVlad merged 2 commits into
dotnet:maindotnet/runtime:mainfrom
medhatiwari:nullabilitymedhatiwari/runtime:nullabilityCopy head branch name to clipboard

Conversation

@medhatiwari

@medhatiwari medhatiwari commented Oct 20, 2025

Copy link
Copy Markdown
Contributor

Fix KeyValuePair nullability detection on Mono

Summary

Fixed a bug in the Mono runtime where NullableAttribute metadata was being lost for generic parameters. This was specifically causing KeyValuePair<TKey, TValue> to incorrectly report NotNull nullability in ASP.NET Core DataAnnotations tests.

Problem

On Mono, the reflection API failed to detect nullability attributes on generic parameters (like TKey and TValue). While CoreCLR correctly identified these as Nullable, Mono defaulted to NotNull

Failing Tests

  • Microsoft.AspNetCore.Mvc.DataAnnotations.DataAnnotationsMetadataProviderTest.IsNullableReferenceType_ReturnsFalse_ForKeyValuePairWithoutNullableConstraints
  • Microsoft.AspNetCore.Mvc.DataAnnotations.DataAnnotationsMetadataProviderTest.IsNullableReferenceType_ReturnsTrue_ForKeyValuePairWithNullableConstraints

Root Cause

The issue was located in the Mono native metadata initialization (src/mono/mono/metadata/class-init.c). In the MonoClass structure, MonoClassSizes is a union where class_size and generic_param_token share the same memory location.

During the execution of mono_class_layout_fields(), the runtime was explicitly assigning class_size = 0. Because of the union, this assignment was overwriting and zeroing out the generic_param_token that had been correctly initialized earlier. When the reflection system later tried to look up custom attributes using that token, it failed because the token was now 0x0.

Solution

The fix modifies mono_class_layout_fields to skip the class_size assignment for types that are generic parameters (MONO_TYPE_VAR and MONO_TYPE_MVAR). This preserves the metadata token, allowing mono_custom_attrs_from_class_checked() to correctly retrieve the NullableAttribute.

Reproduction Case

using System;
using System.Collections.Generic;
using System.Reflection;

var kvpType = typeof(KeyValuePair<string, object>);
var keyProperty = kvpType.GetProperty("Key");
var nullabilityContext = new NullabilityInfoContext();
var result = nullabilityContext.Create(keyProperty);

Console.WriteLine($"ReadState: {result.ReadState}");
// Expected: Nullable
// Mono (before fix): NotNull  
// Mono (after fix): Nullable 

Test Results

  • Before fix: 361 pass, 3 fail (including 2 KeyValuePair tests)
  • After fix: 363 pass, 1 fail (KeyValuePair tests now pass)
  • Net improvement: +2 tests fixed, 0 regressions

Files Changed

  • src/mono/mono/metadata/class-init.c

cc: @giritrivedi

@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Oct 20, 2025
@github-actions github-actions Bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Oct 20, 2025
@jkotas jkotas added area-System.Reflection and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Oct 20, 2025
@jkotas

jkotas commented Oct 20, 2025

Copy link
Copy Markdown
Member

Mono's KeyValuePair<TKey, TValue> generic parameters are missing the NullableAttribute(2) that CoreCLR has

This sounds like a bug in Mono-specific reflection implementation. Instead of adding workaround for this to shared NullabilityInfoContext.cs, could you please fix the Mono reflection implementation instead?

@medhatiwari

Copy link
Copy Markdown
Contributor Author

This sounds like a bug in Mono-specific reflection implementation. Instead of adding workaround for this to shared NullabilityInfoContext.cs, could you please fix the Mono reflection implementation instead?

You're absolutely right - I've fixed this at the Mono native level instead. The reflection APIs are actually working correctly; the issue was metadata token corruption in mono_class_layout_fields().
When debugging, I found that mono_custom_attrs_from_class_checked() was receiving generic_param_token = 0x00000000, even though the PE file contains the correct NullableAttribute metadata with valid tokens. The problem is that MonoClassSizes is a union where class_size and generic_param_token share memory - assigning class_size = 0 was overwriting the token that was correctly set during class creation.
The fix (in src/mono/mono/metadata/class-init.c) skips the class_size assignment for generic parameter types (MONO_TYPE_VAR/MONO_TYPE_MVAR), preserving the token. I've removed the managed workaround and pushed the native fix.

@BrzVlad

BrzVlad commented Jan 12, 2026

Copy link
Copy Markdown
Member

/azp run runtime

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@BrzVlad
BrzVlad merged commit d8182b2 into dotnet:main Jan 13, 2026
79 checks passed
@vitek-karas

Copy link
Copy Markdown
Member

Could we please update the PR description to match the actual fix? Ideally we would also fix the commit message - both describe the fix in a way which doesn't match the code change at all.

@medhatiwari

Copy link
Copy Markdown
Contributor Author

Could we please update the PR description to match the actual fix? Ideally we would also fix the commit message - both describe the fix in a way which doesn't match the code change at all.

I’ve updated the PR description to reflect the native fix in Mono's metadata initialization, Please let me know if it looks good now

@vitek-karas

Copy link
Copy Markdown
Member

Thanks a lot!

@github-actions github-actions Bot locked and limited conversation to collaborators Feb 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-VM-meta-mono community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.