Remove MethodDescCallSite in comutilnative.cpp#123986
Remove MethodDescCallSite in comutilnative.cpp#123986AaronRobinsonMSFT merged 14 commits intodotnet:mainfrom
MethodDescCallSite in comutilnative.cpp#123986Conversation
a4841a2 to
6fb04f5
Compare
Co-authored-by: Aaron R Robinson <[email protected]>
stephentoub
left a comment
There was a problem hiding this comment.
Code Review: PR #123986
Holistic Assessment
Motivation: This PR removes MethodDescCallSite usage in COM interop exception handling code in comutilnative.cpp, replacing it with direct calls via UnmanagedCallersOnly methods. This is part of a broader effort (#123864) to simplify and modernize the native/managed interop calling pattern.
Approach: The PR introduces three new [UnmanagedCallersOnly] static methods in Exception.CoreCLR.cs that handle BSTR allocation directly in managed code, and adds a new template method InvokeThrowing_Ret<T> to UnmanagedCallersOnlyCaller for methods that return values.
Net positive: ✅ Yes - This is a good simplification that reduces complexity in the native/managed boundary, removes the now-unused BStrFromString helper, and follows the established pattern from the UnmanagedCallersOnlyCaller class.
Detailed Findings
✅ Correctness
-
Proper exception propagation: The new managed methods correctly catch exceptions and store them in the out parameter, matching the expected pattern for
UnmanagedCallersOnlyCaller.InvokeThrowing_Ret. -
BSTR allocation behavior preserved: The new code uses
Interop.OleAut32.SysAllocStringLendirectly from managed code. The semantics are preserved - returnsIntPtr.Zerofor null/empty strings where appropriate. -
Method signatures match: The
corelib.hbindings correctly map to the new method signatures, andmetasig.hhas proper signature definitions.
⚠️ Potential Issues
-
OOM handling difference (Line 143 in
comutilnative.cpp):- Old code:
BStrFromStringexplicitly threwCOMPlusThrowOM()whenSysAllocStringreturnedNULL. - New code:
SysAllocStringLenreturningIntPtr.Zero(on OOM) will propagate up as a null BSTR without throwing. - Impact: This changes error behavior - instead of throwing
OutOfMemoryException, callers may receiveNULLBSTRs. The COM error handling path inGetExceptionDatamay not expect this. - Recommendation: Consider checking the return value and throwing
OutOfMemoryExceptionwhenSysAllocStringLenreturnsIntPtr.Zerofor non-null input strings, OR verify that downstream consumers handle null BSTRs correctly.
- Old code:
-
GetHelpContextBstrdoes not initialize*bstr(Lines 328-342 inException.CoreCLR.cs):- If an exception is thrown before
*bstris assigned, the output pointer remains uninitialized. - The other two methods return
IntPtr.Zeroin the catch block, but this method doesn't assign anything on exception. - Recommendation: Initialize
*bstr = IntPtr.Zero;at the start of the method, or assign it in the catch block.
- If an exception is thrown before
💡 Suggestions
-
Documentation for
InvokeThrowing_Ret: Consider adding a brief comment incallhelpers.hexplaining that this variant is for methods returning values (similar to the existing class-level comment forInvokeThrowing). -
Consistency: The
InvokeThrowing_Rettemplate duplicates the sanity check andOVERRIDE_TYPE_LOAD_LEVEL_LIMITlogic fromInvokeThrowing. Consider whether these could share a common helper to reduce duplication.
Cross-Cutting Analysis
- FEATURE_COMINTEROP guards: Correctly applied to new managed code and method bindings.
- Old method bindings removed: The old
METHOD__EXCEPTION__GET_MESSAGE,METHOD__EXCEPTION__GET_CLASS_NAME,METHOD__EXCEPTION__GET_SOURCE, andMETHOD__EXCEPTION__GET_HELP_CONTEXTbindings are correctly removed fromcorelib.h. GetHelpContextvisibility change: The method was changed frominternaltoprivate, which is correct since it's now only called from within the class.
Test Coverage
No new tests are added. The COM interop exception handling path is typically exercised through existing COM interop tests. Recommend verifying:
- COM exception description/source/help retrieval still works correctly
- OOM scenarios don't cause regressions (if the OOM handling change above is intentional)
Summary
Verdict:
The overall approach is sound and follows established patterns. Two items need attention:
- OOM handling: The loss of explicit
COMPlusThrowOM()for BSTR allocation failures should be intentional or addressed. - Uninitialized pointer:
GetHelpContextBstrshould initialize*bstrtoIntPtr.Zerobefore the try block.
After addressing these, the PR is ready to merge.
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs
Outdated
Show resolved
Hide resolved
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs
Outdated
Show resolved
Hide resolved
src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Jan Kotas <[email protected]>
This isn't accurate. The new code follows the same semantics. The
This is fair feedback, but can be ignored. This is a throwing function and callers should expect those exceptions to indicate invalid "out" state. It doesn't hurt to initialize it though. |
Contributes to #123864. Adds support for returning value.