Skip to content

[cDAC] Fix NonVirtualEntry2MethodDesc to handle invalid precode addresses#124986

Open
max-charlamb wants to merge 1 commit intodotnet:mainfrom
max-charlamb:cdac-nonvirtualentry2methoddesc-fix
Open

[cDAC] Fix NonVirtualEntry2MethodDesc to handle invalid precode addresses#124986
max-charlamb wants to merge 1 commit intodotnet:mainfrom
max-charlamb:cdac-nonvirtualentry2methoddesc-fix

Conversation

@max-charlamb
Copy link
Member

@max-charlamb max-charlamb commented Feb 27, 2026

Summary

NonVirtualEntry2MethodDesc throws InvalidOperationException when an address falls in a precode RangeSection but doesn't match any known precode type (e.g., a MethodDesc address that coincidentally shares the same memory range). The DAC's C++ implementation returns NULL in this case.

This mismatch caused a DEBUG assertion crash in GetCodeHeaderData — the cDAC returned 0x80131509 (COR_E_INVALIDOPERATION) while the DAC returned 0x80070057 (E_INVALIDARG), triggering Debug.Assert(hrLocal == hr) and crashing the process. This broke !clru on IL stubs in the cDAC_windows_x64_release CI job (build 1313397).

Fix

Catch InvalidOperationException from GetMethodDescFromStubAddress in ExecutionManagerCore.NonVirtualEntry2MethodDesc and return TargetPointer.Null, matching the DAC's C++ behavior where NonVirtualEntry2MethodDesc returns NULL for unrecognized addresses.

Test

Adds VarargPInvoke_GetCodeHeaderDataWithInvalidPrecodeAddress dump test that:

  • Gets a method's precode entry point from the VarargPInvoke dump
  • Offsets it by 1 byte to create an address in the RangeList range that isn't a valid precode
  • Calls GetCodeHeaderData (SOS-level API) and asserts it returns E_INVALIDARG

Verified the test fails without the fix (returns COR_E_INVALIDOPERATION) and passes with the fix (returns E_INVALIDARG).

…sses

NonVirtualEntry2MethodDesc throws InvalidOperationException when an
address falls in a precode RangeSection but doesn't match any known
precode type. The DAC's C++ implementation returns NULL in this case.

This mismatch caused a DEBUG assertion crash in GetCodeHeaderData
(cDAC returned 0x80131509, DAC returned 0x80070057), breaking SOS
!clru on IL stubs in the cDAC_windows_x64_release CI job.

The fix catches InvalidOperationException from GetMethodDescFromStubAddress
and returns TargetPointer.Null, matching the DAC behavior.

Adds a dump test that exercises GetCodeHeaderData with an invalid precode
address derived from the VarargPInvoke debuggee's entry point.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 27, 2026 19:55
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

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

Aligns cDAC behavior with the native DAC when given an address that falls within a precode RangeSection but does not correspond to a valid precode, preventing exceptions and downstream assertion failures.

Changes:

  • Added a regression dump test that calls GetCodeHeaderData with an intentionally invalid precode address and asserts E_INVALIDARG.
  • Updated NonVirtualEntry2MethodDesc to return TargetPointer.Null (instead of throwing) when precode bytes are invalid.

Reviewed changes

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

File Description
src/native/managed/cdac/tests/DumpTests/VarargPInvokeDumpTests.cs Adds a regression test for invalid precode addresses passed to GetCodeHeaderData.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs Matches native DAC behavior by catching invalid-precode exceptions and returning Null.

Comment on lines +173 to +180
// Offset by 1 byte to create an address that is still in the same
// RangeList range but is not a valid precode. This is the same
// scenario that caused the original CI failure: GetCodeHeaderData
// calls NonVirtualEntry2MethodDesc, which calls GetMethodDescFromStubAddress,
// which throws InvalidOperationException for invalid precode bytes.
// The fix catches this and returns E_INVALIDARG (matching the DAC).
DacpCodeHeaderData codeHeaderData;
int hr = sosDac.GetCodeHeaderData(new ClrDataAddress(entryPoint.Value + 1), &codeHeaderData);
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

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

This test assumes entryPoint is a precode located in a precode RangeList section, but it doesn’t verify that precondition. If GetMethodEntryPointIfExists returns a non-precode entrypoint (e.g., a real code address), entryPoint.Value + 1 may still be valid and GetCodeHeaderData may succeed, making the test flaky or invalid. Consider adding a precondition check (and continue if it doesn’t hold), such as validating that GetCodeHeaderData(entryPoint) succeeds first, or that resolving the valid entryPoint maps back to the same MethodDesc before offsetting by 1.

Suggested change
// Offset by 1 byte to create an address that is still in the same
// RangeList range but is not a valid precode. This is the same
// scenario that caused the original CI failure: GetCodeHeaderData
// calls NonVirtualEntry2MethodDesc, which calls GetMethodDescFromStubAddress,
// which throws InvalidOperationException for invalid precode bytes.
// The fix catches this and returns E_INVALIDARG (matching the DAC).
DacpCodeHeaderData codeHeaderData;
int hr = sosDac.GetCodeHeaderData(new ClrDataAddress(entryPoint.Value + 1), &codeHeaderData);
// First, validate that the entry point itself corresponds to a valid
// code header. If it does not, this frame does not meet the test
// preconditions, so skip it.
DacpCodeHeaderData codeHeaderData;
int hr = sosDac.GetCodeHeaderData(new ClrDataAddress(entryPoint.Value), &codeHeaderData);
if (hr != 0)
continue;
// Offset by 1 byte to create an address that is still in the same
// RangeList range but is not a valid precode. This is the same
// scenario that caused the original CI failure: GetCodeHeaderData
// calls NonVirtualEntry2MethodDesc, which calls GetMethodDescFromStubAddress,
// which throws InvalidOperationException for invalid precode bytes.
// The fix catches this and returns E_INVALIDARG (matching the DAC).
DacpCodeHeaderData invalidCodeHeaderData;
hr = sosDac.GetCodeHeaderData(new ClrDataAddress(entryPoint.Value + 1), &invalidCodeHeaderData);

Copilot uses AI. Check for mistakes.
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.

2 participants