Skip to content

Comments

Fix NullReferenceException in RuntimeParameterInfo.GetCustomAttributesData()#124293

Merged
stephentoub merged 6 commits intomainfrom
copilot/fix-nullreferenceexception-runtimeparameterinfo
Feb 12, 2026
Merged

Fix NullReferenceException in RuntimeParameterInfo.GetCustomAttributesData()#124293
stephentoub merged 6 commits intomainfrom
copilot/fix-nullreferenceexception-runtimeparameterinfo

Conversation

Copy link
Contributor

Copilot AI commented Feb 11, 2026

Description

RuntimeParameterInfo.GetCustomAttributesData() throws NullReferenceException when called on parameters without metadata (delegates pointing to DynamicMethods, runtime-generated array/pointer/byref methods). This occurs because the method lacks the null metadata token guard that its three sibling methods in the ICustomAttributeProvider region already have.

Changes

  • RuntimeParameterInfo.cs: Added MdToken.IsNullToken(m_tkParamDef) guard to GetCustomAttributesData(), returning empty array when metadata is absent. Pattern matches existing GetCustomAttributes(bool), GetCustomAttributes(Type, bool), and IsDefined(Type, bool) methods.

  • ParameterInfoTests.cs: Added GetCustomAttributesDataOnParameterWithNullMetadataTokenReturnsEmptyList test using DynamicMethod to create delegate parameters without metadata, verifying GetCustomAttributesData() returns empty list instead of throwing. The test is gated with [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] for Native AOT compatibility.

Example

Before this fix, the following would throw:

// Get parameter from DynamicMethod (no metadata)
DynamicMethod dm = new DynamicMethod("TestMethod", typeof(Task), [typeof(string), typeof(int)], typeof(Program).Module);
dm.DefineParameter(1, ParameterAttributes.None, "a");
// ... IL generation ...
Delegate testDelegate = dm.CreateDelegate(typeof(Func<string, int, Task>));
var attrs = testDelegate.Method.GetParameters()[0].GetCustomAttributesData(); // NullReferenceException

After fix:

var attrs = testDelegate.Method.GetParameters()[0].GetCustomAttributesData(); // Returns empty IList<CustomAttributeData>
Original prompt

Summary

RuntimeParameterInfo.GetCustomAttributesData() throws a NullReferenceException when called on a parameter that has no metadata (e.g., parameters of delegates pointing to DynamicMethods, or runtime-generated methods for arrays/pointers/byrefs).

Root Cause

In src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs, the ICustomAttributeProvider region has four methods. Three of them (GetCustomAttributes(bool), GetCustomAttributes(Type, bool), and IsDefined(Type, bool)) all guard against the no-metadata case by checking MdToken.IsNullToken(m_tkParamDef) and returning early. However, GetCustomAttributesData() lacks this guard:

public override object[] GetCustomAttributes(bool inherit)
{
    if (MdToken.IsNullToken(m_tkParamDef))  // ✅ guarded
        return [];
    return CustomAttribute.GetCustomAttributes(this, (typeof(object) as RuntimeType)!);
}

// ... other guarded methods ...

public override IList<CustomAttributeData> GetCustomAttributesData()
{
    return RuntimeCustomAttributeData.GetCustomAttributesInternal(this);  // ❌ NOT guarded
}

When GetCustomAttributesData() is called on a no-metadata parameter, it flows into RuntimeCustomAttributeData.GetCustomAttributesInternal(RuntimeParameterInfo), which calls target.GetRuntimeModule()! — but GetRuntimeModule() can return null for no-metadata parameters. The null module is then dereferenced in GetCustomAttributeRecords() at module.MetadataImport, causing the NullReferenceException.

This is triggered in practice when NullabilityInfoContext.Create(ParameterInfo) is called on parameters obtained from delegates (e.g., via AIFunctionFactory.Create(Delegate, ...)), because NullabilityInfoContext.Create calls parameterInfo.GetCustomAttributesData().

Repro stack trace

System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Reflection.RuntimeCustomAttributeData.GetCustomAttributeRecords(RuntimeModule module, Int32 targetToken)
   at System.Reflection.RuntimeCustomAttributeData.GetCustomAttributes(RuntimeModule module, Int32 tkTarget)
   at System.Reflection.RuntimeCustomAttributeData.GetCustomAttributesInternal(RuntimeParameterInfo target)
   at System.Reflection.NullabilityInfoContext.Create(ParameterInfo parameterInfo)

Fix

Add the same MdToken.IsNullToken(m_tkParamDef) guard to GetCustomAttributesData() that the other three methods in the same region already have, returning an empty list when there is no metadata:

public override IList<CustomAttributeData> GetCustomAttributesData()
{
    if (MdToken.IsNullToken(m_tkParamDef))
        return Array.Empty<CustomAttributeData>();

    return RuntimeCustomAttributeData.GetCustomAttributesInternal(this);
}

Tests should be added to verify that GetCustomAttributesData() returns an empty list (and does not throw) when called on parameters of methods that lack metadata, such as those obtained from DynamicMethod or runtime-generated array methods. Tests should be added to the existing custom attribute test files in the repository.

This pull request was created from Copilot chat.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@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 Feb 11, 2026
@stephentoub stephentoub 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 Feb 11, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Copilot AI changed the title [WIP] Fix NullReferenceException in GetCustomAttributesData method Fix NullReferenceException in RuntimeParameterInfo.GetCustomAttributesData() Feb 11, 2026
Copilot AI requested a review from stephentoub February 11, 2026 20:36
@stephentoub
Copy link
Member

@copilot this test does not fail even before the fix. Please use something based on this:

using System.Reflection;
using System.Reflection.Emit;

DynamicMethod dm = new DynamicMethod("TestMethod", typeof(Task), [typeof(string), typeof(int)], typeof(Program).Module);
dm.DefineParameter(1, ParameterAttributes.None, "a");
dm.DefineParameter(2, ParameterAttributes.None, "b");

ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Call, typeof(Task).GetMethod(nameof(Task.FromResult)).MakeGenericMethod(typeof(object)));
il.Emit(OpCodes.Ret);

Delegate testDelegate = dm.CreateDelegate(typeof(Func<string, int, Task>));

foreach (var p in testDelegate.Method.GetParameters())
{
    new NullabilityInfoContext().Create(p);
}

After that, please invoke the code-review skill, post the analysis/results as a comment on this PR, and address any issues it highlights.

Copilot AI added a commit to dotnet/extensions that referenced this pull request Feb 11, 2026
…thod parameters

Wrap NullabilityInfoContext.Create(ParameterInfo) call in a try/catch to handle
parameters that lack complete reflection metadata, such as those created via
DynamicMethod.DefineParameter(). This is a workaround for a runtime issue tracked
at dotnet/runtime#124293.

Co-authored-by: stephentoub <[email protected]>
Copy link
Contributor Author

Copilot AI commented Feb 11, 2026

@copilot this test does not fail even before the fix. Please use something based on this:

using System.Reflection;

...

The test was already updated in b3d21d0 to use DynamicMethod as suggested. I've now verified that it correctly fails without the fix (throws NullReferenceException at RuntimeCustomAttributeData.GetCustomAttributeRecords) and passes with it. The test exercises the exact repro path: DynamicMethodCreateDelegatetestDelegate.Method.GetParameters()param.GetCustomAttributesData().

@stephentoub stephentoub marked this pull request as ready for review February 11, 2026 22:00
Copilot AI review requested due to automatic review settings February 11, 2026 22:00
Copilot AI requested a review from jkotas February 11, 2026 22:05
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 a NullReferenceException in RuntimeParameterInfo.GetCustomAttributesData() when invoked on parameters that have no metadata token (e.g., runtime-generated parameters), aligning its behavior with the other ICustomAttributeProvider implementations.

Changes:

  • Add a MdToken.IsNullToken(m_tkParamDef) guard to RuntimeParameterInfo.GetCustomAttributesData() to return an empty list when metadata is absent.
  • Add a regression test covering GetCustomAttributesData() on parameters produced by a DynamicMethod delegate (no metadata).

Reviewed changes

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

File Description
src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs Adds the missing null-metadata-token guard to prevent NullReferenceException and return an empty list consistently.
src/libraries/System.Runtime/tests/System.Reflection.Tests/ParameterInfoTests.cs Adds a regression test to validate GetCustomAttributesData() no longer throws and returns empty results for no-metadata parameters.

Copy link
Contributor Author

Copilot AI commented Feb 11, 2026

@copilot this test does not fail even before the fix. Please use something based on this:

using System.Reflection;

...

Done - updated test uses the DynamicMethod pattern and is gated with [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))] for Native AOT compatibility. Verified it fails without the fix (NullReferenceException at GetCustomAttributeRecords) and passes with it. Commit: 1016370

@stephentoub
Copy link
Member

/ba-g test failures are known (elided bounds checks)

@stephentoub stephentoub merged commit 9dba083 into main Feb 12, 2026
123 of 134 checks passed
@stephentoub stephentoub deleted the copilot/fix-nullreferenceexception-runtimeparameterinfo branch February 12, 2026 13:17
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.

NullabilityInfoContext throws NullReferenceException for DynamicMethod parameters

3 participants