@@ -37,10 +37,10 @@ public static bool RequiresReflectionMethodBodyScannerForCallSite (LinkContext c
37
37
if ( methodDefinition == null )
38
38
return false ;
39
39
40
- return
41
- GetIntrinsicIdForMethod ( methodDefinition ) > IntrinsicId . RequiresReflectionBodyScanner_Sentinel ||
40
+ return GetIntrinsicIdForMethod ( methodDefinition ) > IntrinsicId . RequiresReflectionBodyScanner_Sentinel ||
42
41
context . Annotations . FlowAnnotations . RequiresDataFlowAnalysis ( methodDefinition ) ||
43
- context . Annotations . HasLinkerAttribute < RequiresUnreferencedCodeAttribute > ( methodDefinition ) ;
42
+ context . Annotations . HasLinkerAttribute < RequiresUnreferencedCodeAttribute > ( methodDefinition )
43
+ || methodDefinition . IsPInvokeImpl ;
44
44
}
45
45
46
46
public static bool RequiresReflectionMethodBodyScannerForMethodBody ( FlowAnnotations flowAnnotations , MethodDefinition methodDefinition )
@@ -75,7 +75,7 @@ public void ScanAndProcessReturnValue (MethodBody methodBody)
75
75
{
76
76
Scan ( methodBody ) ;
77
77
78
- if ( methodBody . Method . ReturnType . MetadataType != MetadataType . Void ) {
78
+ if ( GetReturnTypeWithoutModifiers ( methodBody . Method . ReturnType ) . MetadataType != MetadataType . Void ) {
79
79
var method = methodBody . Method ;
80
80
var requiredMemberTypes = _context . Annotations . FlowAnnotations . GetReturnParameterAnnotation ( method ) ;
81
81
if ( requiredMemberTypes != 0 ) {
@@ -1729,6 +1729,20 @@ methodParams[argsParam] is ArrayValue arrayValue &&
1729
1729
break ;
1730
1730
1731
1731
default :
1732
+
1733
+ if ( calledMethodDefinition . IsPInvokeImpl ) {
1734
+ // Is the PInvoke dangerous?
1735
+ bool comDangerousMethod = IsComInterop ( calledMethodDefinition . MethodReturnType , calledMethodDefinition . ReturnType ) ;
1736
+ foreach ( ParameterDefinition pd in calledMethodDefinition . Parameters ) {
1737
+ comDangerousMethod |= IsComInterop ( pd , pd . ParameterType ) ;
1738
+ }
1739
+
1740
+ if ( comDangerousMethod ) {
1741
+ reflectionContext . AnalyzingPattern ( ) ;
1742
+ reflectionContext . RecordUnrecognizedPattern ( 2050 , $ "P/invoke method '{ calledMethodDefinition . GetDisplayName ( ) } ' declares a parameter with COM marshalling. Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed.") ;
1743
+ }
1744
+ }
1745
+
1732
1746
if ( requiresDataFlowAnalysis ) {
1733
1747
reflectionContext . AnalyzingPattern ( ) ;
1734
1748
for ( int parameterIndex = 0 ; parameterIndex < methodParams . Count ; parameterIndex ++ ) {
@@ -1755,7 +1769,7 @@ methodParams[argsParam] is ArrayValue arrayValue &&
1755
1769
1756
1770
// To get good reporting of errors we need to track the origin of the value for all method calls
1757
1771
// but except Newobj as those are special.
1758
- if ( calledMethodDefinition . ReturnType . MetadataType != MetadataType . Void ) {
1772
+ if ( GetReturnTypeWithoutModifiers ( calledMethodDefinition . ReturnType ) . MetadataType != MetadataType . Void ) {
1759
1773
methodReturnValue = CreateMethodReturnValue ( calledMethodDefinition , returnValueDynamicallyAccessedMemberTypes ) ;
1760
1774
1761
1775
return true ;
@@ -1771,7 +1785,7 @@ methodParams[argsParam] is ArrayValue arrayValue &&
1771
1785
// didn't set the return value (and the method has a return value), we will set it to be an
1772
1786
// unknown value with the return type of the method.
1773
1787
if ( methodReturnValue == null ) {
1774
- if ( calledMethod . ReturnType . MetadataType != MetadataType . Void ) {
1788
+ if ( GetReturnTypeWithoutModifiers ( calledMethod . ReturnType ) . MetadataType != MetadataType . Void ) {
1775
1789
methodReturnValue = CreateMethodReturnValue ( calledMethodDefinition , returnValueDynamicallyAccessedMemberTypes ) ;
1776
1790
}
1777
1791
}
@@ -1794,6 +1808,64 @@ methodParams[argsParam] is ArrayValue arrayValue &&
1794
1808
return true ;
1795
1809
}
1796
1810
1811
+ bool IsComInterop ( IMarshalInfoProvider marshalInfoProvider , TypeReference parameterType )
1812
+ {
1813
+ // This is best effort. One can likely find ways how to get COM without triggering these alarms.
1814
+ // AsAny marshalling of a struct with an object-typed field would be one, for example.
1815
+
1816
+ // This logic roughly corresponds to MarshalInfo::MarshalInfo in CoreCLR,
1817
+ // not trying to handle invalid cases and distinctions that are not interesting wrt
1818
+ // "is this COM?" question.
1819
+
1820
+ NativeType nativeType = NativeType . None ;
1821
+ if ( marshalInfoProvider . HasMarshalInfo ) {
1822
+ nativeType = marshalInfoProvider . MarshalInfo . NativeType ;
1823
+ }
1824
+
1825
+ if ( nativeType == NativeType . IUnknown || nativeType == NativeType . IDispatch || nativeType == NativeType . IntF ) {
1826
+ // This is COM by definition
1827
+ return true ;
1828
+ }
1829
+
1830
+ if ( nativeType == NativeType . None ) {
1831
+ // Resolve will look at the element type
1832
+ var parameterTypeDef = _context . TryResolve ( parameterType ) ;
1833
+
1834
+ if ( parameterTypeDef != null ) {
1835
+ if ( parameterTypeDef . IsTypeOf ( "System" , "Array" ) ) {
1836
+ // System.Array marshals as IUnknown by default
1837
+ return true ;
1838
+ } else if ( parameterTypeDef . IsTypeOf ( "System" , "String" ) ||
1839
+ parameterTypeDef . IsTypeOf ( "System.Text" , "StringBuilder" ) ) {
1840
+ // String and StringBuilder are special cased by interop
1841
+ return false ;
1842
+ }
1843
+
1844
+ if ( parameterTypeDef . IsValueType ) {
1845
+ // Value types don't marshal as COM
1846
+ return false ;
1847
+ } else if ( parameterTypeDef . IsInterface ) {
1848
+ // Interface types marshal as COM by default
1849
+ return true ;
1850
+ } else if ( parameterTypeDef . IsMulticastDelegate ( ) ) {
1851
+ // Delegates are special cased by interop
1852
+ return false ;
1853
+ } else if ( parameterTypeDef . IsSubclassOf ( "System.Runtime.InteropServices" , "CriticalHandle" ) ) {
1854
+ // Subclasses of CriticalHandle are special cased by interop
1855
+ return false ;
1856
+ } else if ( parameterTypeDef . IsSubclassOf ( "System.Runtime.InteropServices" , "SafeHandle" ) ) {
1857
+ // Subclasses of SafeHandle are special cased by interop
1858
+ return false ;
1859
+ } else if ( ! parameterTypeDef . IsSequentialLayout && ! parameterTypeDef . IsExplicitLayout ) {
1860
+ // Rest of classes that don't have layout marshal as COM
1861
+ return true ;
1862
+ }
1863
+ }
1864
+ }
1865
+
1866
+ return false ;
1867
+ }
1868
+
1797
1869
bool AnalyzeGenericInstatiationTypeArray ( ValueNode arrayParam , ref ReflectionPatternContext reflectionContext , MethodReference calledMethod , IList < GenericParameter > genericParameters )
1798
1870
{
1799
1871
bool hasRequirements = false ;
0 commit comments