Skip to content

[cDAC] Return E_FAIL when module metadata is unavailable#130904

Draft
max-charlamb wants to merge 1 commit into
dotnet:mainfrom
max-charlamb:max-charlamb/cdac-metadata-unavailable-hresult
Draft

[cDAC] Return E_FAIL when module metadata is unavailable#130904
max-charlamb wants to merge 1 commit into
dotnet:mainfrom
max-charlamb:max-charlamb/cdac-metadata-unavailable-hresult

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Summary

When a module's metadata is unavailable, several ISOS/IXCLRData/DacDbi COM
methods relied on a null-forgiving MetadataReader (GetMetadata(...)!), which
surfaced as a NullReferenceException (E_POINTER) instead of the E_FAIL the
native DAC returns.

Native semantic parity

At the high-confidence COM-boundary sites -- where the enclosing method already
catches exceptions and returns ex.HResult, and the native DAC returns E_FAIL
for missing metadata -- the metadata read now throws
Marshal.GetExceptionForHR(HResults.E_FAIL) when GetMetadata returns null:

  • IXCLRDataModule.StartEnumMethodDefinitionsByName
  • ISOSDacInterface.GetFieldDescData
  • DacDbi GetObjectFields (enclosing-class metadata resolution)

Scope

To keep this change to well-understood COM boundaries, the following are
intentionally left unchanged:

  • Signature formatting / type-name building (SigFormat, TypeNameBuilder).
  • The ClrDataFrame local-signature reader, whose null result is converted to a
    DEFAULT value flag rather than surfaced as an error.
  • Contract-layer (Signature_1, RuntimeTypeSystem_1) metadata reads.

Testing

  • ClrDataModuleMetadataTests.StartEnumMethodDefinitionsByName_MissingMetadataReturnsEFail
    -- asserts the COM method returns E_FAIL (not E_POINTER /
    InvalidOperationException) when metadata is unavailable.
  • Full cDAC unit suite: 2702 passed, 16 skipped, 0 failed.

Note

This PR was generated with the assistance of GitHub Copilot.

When a module's metadata is unavailable, several ISOS/IXCLRData/DacDbi COM
methods relied on a null-forgiving MetadataReader (GetMetadata(...)!), which
surfaced as a NullReferenceException (E_POINTER) rather than the E_FAIL the
native DAC returns.

Return E_FAIL at the high-confidence COM-boundary sites where the enclosing
method already catches exceptions and returns ex.HResult, and where the native
DAC returns E_FAIL when metadata is unavailable:
- IXCLRDataModule.StartEnumMethodDefinitionsByName
- ISOSDacInterface.GetFieldDescData
- DacDbi GetObjectFields (enclosing-class metadata resolution)

The metadata read now throws Marshal.GetExceptionForHR(HResults.E_FAIL) when
GetMetadata returns null.

Signature formatting / type-name building (SigFormat, TypeNameBuilder), the
ClrDataFrame local-signature reader (whose null result is converted to a DEFAULT
value flag), and the contract-layer metadata reads are intentionally left
unchanged to keep this change to well-understood COM boundaries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f2aa5dc4-0c99-43f0-af14-734143849c4a
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 aligns several cDAC COM-boundary implementations with native DAC behavior by returning E_FAIL (instead of surfacing NullReferenceException / E_POINTER) when module metadata cannot be obtained, and adds a targeted regression test for the IXCLRDataModule.StartEnumMethodDefinitionsByName scenario.

Changes:

  • Replace null-forgiving GetMetadata(... )! usages at selected COM boundaries with ?? throw Marshal.GetExceptionForHR(HResults.E_FAIL)! so the enclosing catch (Exception ex) { return ex.HResult; } paths return E_FAIL.
  • Apply the same missing-metadata handling in ISOSDacInterface.GetFieldDescData and DacDbi GetObjectFields (enclosing-class metadata resolution).
  • Add a unit test validating StartEnumMethodDefinitionsByName returns E_FAIL when IEcmaMetadata.GetMetadata returns null.

Reviewed changes

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

File Description
src/native/managed/cdac/tests/UnitTests/ClrDataModuleMetadataTests.cs Adds a regression test for IXCLRDataModule.StartEnumMethodDefinitionsByName when metadata is unavailable.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs Returns E_FAIL for missing module metadata in StartEnumMethodDefinitionsByName by throwing an E_FAIL-HResult exception.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs Returns E_FAIL (instead of NRE/E_POINTER) when GetMetadata returns null in GetFieldDescData.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs Returns E_FAIL when enclosing-type metadata is unavailable in GetObjectFields.

Comment on lines +17 to +33
private static readonly MockTarget.Architecture s_arch = new() { IsLittleEndian = true, Is64Bit = true };
private static readonly TargetPointer s_modulePointer = new(0x1000);
private static readonly ModuleHandle s_moduleHandle = new(new TargetPointer(0x2000));

[Fact]
public void StartEnumMethodDefinitionsByName_MissingMetadataReturnsEFail()
{
var loader = new Mock<ILoader>();
loader.Setup(l => l.GetModuleHandleFromModulePtr(s_modulePointer)).Returns(s_moduleHandle);
var ecmaMetadata = new Mock<IEcmaMetadata>();
ecmaMetadata.Setup(e => e.GetMetadata(s_moduleHandle)).Returns((MetadataReader?)null);

TestPlaceholderTarget target = new TestPlaceholderTarget.Builder(s_arch)
.UseReader((ulong _, Span<byte> _) => -1)
.AddMockContract(loader)
.AddMockContract(ecmaMetadata)
.Build();

@max-charlamb max-charlamb left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We should remove the null forgiving operator usage on the other GetMetadata calls as well. The goal is to make the error more clear if the method returns null.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This test isn't important; we don't need to match the native error codes exactly. Let's remove it.

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