Repository navigation
Description
Do not fix or assign to copilot this year, this code is getting unified with native AOT and you'd introduce unnecessary merge conflicts.
Description
Reading ParameterInfo.RawDefaultValue can cause an available default value to disappear from subsequent DefaultValue and HasDefaultValue queries.
This occurs with a custom CustomConstantAttribute whose Value is supplied through its constructor rather than a named attribute argument.
The raw lookup cannot recover that value, but its failure incorrectly suppresses subsequent non-raw lookups.
Reproduction
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
ParameterInfo parameter = typeof(Example)
.GetMethod(nameof(Example.Method))!
.GetParameters()[0];
Console.WriteLine(parameter.DefaultValue);
Console.WriteLine(parameter.HasDefaultValue);
Console.WriteLine(parameter.RawDefaultValue is DBNull);
Console.WriteLine(parameter.DefaultValue is DBNull);
Console.WriteLine(parameter.HasDefaultValue);
public static class Example
{
public static void Method([AnswerConstant(42)] int value) { }
}
public sealed class AnswerConstantAttribute : CustomConstantAttribute
{
private readonly int _value;
public AnswerConstantAttribute(int value) => _value = value;
public override object Value => _value;
}Expected behavior
Reading RawDefaultValue should not affect the other properties.
DefaultValueremains42.HasDefaultValueremainstrue.RawDefaultValuemay returnDBNull.Valuebecause there is no named argument supplying the raw value.
Expected output:
42
True
True
False
True
Actual behavior
After reading RawDefaultValue, DefaultValue returns DBNull.Value and HasDefaultValue returns false.
42
True
True
True
False
The result therefore depends on property-access order, despite no metadata changing.
Suspected cause
In RuntimeParameterInfo.cs, TryGetDefaultValueInternal uses the same m_noDefaultValue flag for raw and non-raw lookups.
For custom constants:
- The non-raw path instantiates the attribute and reads
CustomConstantAttribute.Value. - The raw path's
GetRawConstantexamines only named arguments. - When the raw path finds no value, it sets
m_noDefaultValue. - Subsequent non-raw lookups return early, even though instantiating the attribute would still produce
42.
An unsuccessful raw lookup should not be treated as proof that no non-raw default exists.
Verification and scope
The behavior was reproduced in a local NativeAOT build sharing CoreCLR's RuntimeParameterInfo implementation, and the corresponding CoreCLR control flow was inspected at the revision linked above.
The standalone repro above has not yet been run on an unmodified CoreCLR build. Affected released versions have not been established.
This should be investigated separately from the NativeAOT implementation-sharing refactor.
Note
This issue draft was generated with GitHub Copilot.
Activity
dotnet-policy-service commentedon Sep 16, 2026
Tagging subscribers to this area: @steveisok, @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.
Share CoreCLR RuntimeParameterInfo with NativeAOT (#134027)