[cDAC] Return E_FAIL when module metadata is unavailable#130904
[cDAC] Return E_FAIL when module metadata is unavailable#130904max-charlamb wants to merge 1 commit into
Conversation
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: 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. |
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
There was a problem hiding this comment.
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 enclosingcatch (Exception ex) { return ex.HResult; }paths returnE_FAIL. - Apply the same missing-metadata handling in
ISOSDacInterface.GetFieldDescDataand DacDbiGetObjectFields(enclosing-class metadata resolution). - Add a unit test validating
StartEnumMethodDefinitionsByNamereturnsE_FAILwhenIEcmaMetadata.GetMetadatareturnsnull.
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. |
| 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
left a comment
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
This test isn't important; we don't need to match the native error codes exactly. Let's remove it.
Summary
When a module's metadata is unavailable, several
ISOS/IXCLRData/DacDbi COMmethods relied on a null-forgiving
MetadataReader(GetMetadata(...)!), whichsurfaced as a
NullReferenceException(E_POINTER) instead of theE_FAILthenative 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 returnsE_FAILfor missing metadata -- the metadata read now throws
Marshal.GetExceptionForHR(HResults.E_FAIL)whenGetMetadatareturns null:IXCLRDataModule.StartEnumMethodDefinitionsByNameISOSDacInterface.GetFieldDescDataGetObjectFields(enclosing-class metadata resolution)Scope
To keep this change to well-understood COM boundaries, the following are
intentionally left unchanged:
SigFormat,TypeNameBuilder).ClrDataFramelocal-signature reader, whose null result is converted to aDEFAULTvalue flag rather than surfaced as an error.Signature_1,RuntimeTypeSystem_1) metadata reads.Testing
ClrDataModuleMetadataTests.StartEnumMethodDefinitionsByName_MissingMetadataReturnsEFail-- asserts the COM method returns
E_FAIL(notE_POINTER/InvalidOperationException) when metadata is unavailable.Note
This PR was generated with the assistance of GitHub Copilot.