@@ -72,36 +72,37 @@ public DynamicInvokeInfo(MethodBase method, IntPtr invokeThunk)
72
72
{
73
73
Transform transform = default ;
74
74
75
- Type argumentType = parameters [ i ] . ParameterType ;
75
+ var argumentType = ( RuntimeType ) parameters [ i ] . ParameterType ;
76
76
if ( argumentType . IsByRef )
77
77
{
78
78
_needsCopyBack = true ;
79
79
transform |= Transform . ByRef ;
80
- argumentType = argumentType . GetElementType ( ) ! ;
80
+ argumentType = ( RuntimeType ) argumentType . GetElementType ( ) ! ;
81
81
}
82
82
Debug . Assert ( ! argumentType . IsByRef ) ;
83
83
84
- EETypePtr eeArgumentType = argumentType . TypeHandle . ToEETypePtr ( ) ;
85
-
86
- if ( eeArgumentType . IsValueType )
84
+ // This can return a null MethodTable for reference types.
85
+ // The compiler makes sure it returns a non-null MT for everything else.
86
+ EETypePtr eeArgumentType = argumentType . ToEETypePtrMayBeNull ( ) ;
87
+ if ( argumentType . IsValueType )
87
88
{
88
- Debug . Assert ( argumentType . IsValueType ) ;
89
+ Debug . Assert ( eeArgumentType . IsValueType ) ;
89
90
90
91
if ( eeArgumentType . IsByRefLike )
91
92
_argumentCount = ArgumentCount_NotSupported_ByRefLike ;
92
93
93
94
if ( eeArgumentType . IsNullable )
94
95
transform |= Transform . Nullable ;
95
96
}
96
- else if ( eeArgumentType . IsPointer )
97
+ else if ( argumentType . IsPointer )
97
98
{
98
- Debug . Assert ( argumentType . IsPointer ) ;
99
+ Debug . Assert ( eeArgumentType . IsPointer ) ;
99
100
100
101
transform |= Transform . Pointer ;
101
102
}
102
- else if ( eeArgumentType . IsFunctionPointer )
103
+ else if ( argumentType . IsFunctionPointer )
103
104
{
104
- Debug . Assert ( argumentType . IsFunctionPointer ) ;
105
+ Debug . Assert ( eeArgumentType . IsFunctionPointer ) ;
105
106
106
107
transform |= Transform . FunctionPointer ;
107
108
}
@@ -119,19 +120,18 @@ public DynamicInvokeInfo(MethodBase method, IntPtr invokeThunk)
119
120
{
120
121
Transform transform = default ;
121
122
122
- Type returnType = methodInfo . ReturnType ;
123
+ var returnType = ( RuntimeType ) methodInfo . ReturnType ;
123
124
if ( returnType . IsByRef )
124
125
{
125
126
transform |= Transform . ByRef ;
126
- returnType = returnType . GetElementType ( ) ! ;
127
+ returnType = ( RuntimeType ) returnType . GetElementType ( ) ! ;
127
128
}
128
129
Debug . Assert ( ! returnType . IsByRef ) ;
129
130
130
- EETypePtr eeReturnType = returnType . TypeHandle . ToEETypePtr ( ) ;
131
-
132
- if ( eeReturnType . IsValueType )
131
+ EETypePtr eeReturnType = returnType . ToEETypePtrMayBeNull ( ) ;
132
+ if ( returnType . IsValueType )
133
133
{
134
- Debug . Assert ( returnType . IsValueType ) ;
134
+ Debug . Assert ( eeReturnType . IsValueType ) ;
135
135
136
136
if ( returnType != typeof ( void ) )
137
137
{
@@ -150,17 +150,17 @@ public DynamicInvokeInfo(MethodBase method, IntPtr invokeThunk)
150
150
_argumentCount = ArgumentCount_NotSupported ; // ByRef to void return
151
151
}
152
152
}
153
- else if ( eeReturnType . IsPointer )
153
+ else if ( returnType . IsPointer )
154
154
{
155
- Debug . Assert ( returnType . IsPointer ) ;
155
+ Debug . Assert ( eeReturnType . IsPointer ) ;
156
156
157
157
transform |= Transform . Pointer ;
158
158
if ( ( transform & Transform . ByRef ) == 0 )
159
159
transform |= Transform . AllocateReturnBox ;
160
160
}
161
- else if ( eeReturnType . IsFunctionPointer )
161
+ else if ( returnType . IsFunctionPointer )
162
162
{
163
- Debug . Assert ( returnType . IsFunctionPointer ) ;
163
+ Debug . Assert ( eeReturnType . IsFunctionPointer ) ;
164
164
165
165
transform |= Transform . FunctionPointer ;
166
166
if ( ( transform & Transform . ByRef ) == 0 )
@@ -597,6 +597,12 @@ private unsafe ref byte InvokeDirectWithFewArguments(
597
597
return defaultValue ;
598
598
}
599
599
600
+ private void ThrowForNeverValidNonNullArgument ( EETypePtr srcEEType , int index )
601
+ {
602
+ Debug . Assert ( index != 0 || _isStatic ) ;
603
+ throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , Method . GetParametersAsSpan ( ) [ index - ( _isStatic ? 0 : 1 ) ] . ParameterType , destinationIsByRef : false ) ;
604
+ }
605
+
600
606
private unsafe void CheckArguments (
601
607
Span < object ? > copyOfParameters ,
602
608
void * byrefParameters ,
@@ -636,16 +642,25 @@ private unsafe void CheckArguments(
636
642
EETypePtr srcEEType = arg . GetEETypePtr ( ) ;
637
643
EETypePtr dstEEType = argumentInfo . Type ;
638
644
639
- if ( ! ( srcEEType . RawValue == dstEEType . RawValue ||
640
- RuntimeImports . AreTypesAssignable ( srcEEType , dstEEType ) ||
641
- ( dstEEType . IsInterface && arg is System . Runtime . InteropServices . IDynamicInterfaceCastable castable
642
- && castable . IsInterfaceImplemented ( new RuntimeTypeHandle ( dstEEType ) , throwIfNotImplemented : false ) ) ) )
645
+ if ( srcEEType . RawValue != dstEEType . RawValue )
643
646
{
644
- // ByRefs have to be exact match
645
- if ( ( argumentInfo . Transform & Transform . ByRef ) != 0 )
646
- throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , argumentInfo . Type , destinationIsByRef : true ) ;
647
+ // Destination type can be null if we don't have a MethodTable for this type. This means one cannot
648
+ // possibly pass a valid non-null object instance here.
649
+ if ( dstEEType . IsNull )
650
+ {
651
+ ThrowForNeverValidNonNullArgument ( srcEEType , i ) ;
652
+ }
647
653
648
- arg = InvokeUtils . CheckArgumentConversions ( arg , argumentInfo . Type , InvokeUtils . CheckArgumentSemantics . DynamicInvoke , binderBundle ) ;
654
+ if ( ! ( RuntimeImports . AreTypesAssignable ( srcEEType , dstEEType ) ||
655
+ ( dstEEType . IsInterface && arg is System . Runtime . InteropServices . IDynamicInterfaceCastable castable
656
+ && castable . IsInterfaceImplemented ( new RuntimeTypeHandle ( dstEEType ) , throwIfNotImplemented : false ) ) ) )
657
+ {
658
+ // ByRefs have to be exact match
659
+ if ( ( argumentInfo . Transform & Transform . ByRef ) != 0 )
660
+ throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , argumentInfo . Type , destinationIsByRef : true ) ;
661
+
662
+ arg = InvokeUtils . CheckArgumentConversions ( arg , argumentInfo . Type , InvokeUtils . CheckArgumentSemantics . DynamicInvoke , binderBundle ) ;
663
+ }
649
664
}
650
665
651
666
if ( ( argumentInfo . Transform & Transform . Reference ) == 0 )
@@ -704,16 +719,25 @@ private unsafe void CheckArguments(
704
719
EETypePtr srcEEType = arg . GetEETypePtr ( ) ;
705
720
EETypePtr dstEEType = argumentInfo . Type ;
706
721
707
- if ( ! ( srcEEType . RawValue == dstEEType . RawValue ||
708
- RuntimeImports . AreTypesAssignable ( srcEEType , dstEEType ) ||
709
- ( dstEEType . IsInterface && arg is System . Runtime . InteropServices . IDynamicInterfaceCastable castable
710
- && castable . IsInterfaceImplemented ( new RuntimeTypeHandle ( dstEEType ) , throwIfNotImplemented : false ) ) ) )
722
+ if ( srcEEType . RawValue != dstEEType . RawValue )
711
723
{
712
- // ByRefs have to be exact match
713
- if ( ( argumentInfo . Transform & Transform . ByRef ) != 0 )
714
- throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , argumentInfo . Type , destinationIsByRef : true ) ;
724
+ // Destination type can be null if we don't have a MethodTable for this type. This means one cannot
725
+ // possibly pass a valid non-null object instance here.
726
+ if ( dstEEType . IsNull )
727
+ {
728
+ ThrowForNeverValidNonNullArgument ( srcEEType , i ) ;
729
+ }
715
730
716
- arg = InvokeUtils . CheckArgumentConversions ( arg , argumentInfo . Type , InvokeUtils . CheckArgumentSemantics . DynamicInvoke , binderBundle : null ) ;
731
+ if ( ! ( RuntimeImports . AreTypesAssignable ( srcEEType , dstEEType ) ||
732
+ ( dstEEType . IsInterface && arg is System . Runtime . InteropServices . IDynamicInterfaceCastable castable
733
+ && castable . IsInterfaceImplemented ( new RuntimeTypeHandle ( dstEEType ) , throwIfNotImplemented : false ) ) ) )
734
+ {
735
+ // ByRefs have to be exact match
736
+ if ( ( argumentInfo . Transform & Transform . ByRef ) != 0 )
737
+ throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , argumentInfo . Type , destinationIsByRef : true ) ;
738
+
739
+ arg = InvokeUtils . CheckArgumentConversions ( arg , argumentInfo . Type , InvokeUtils . CheckArgumentSemantics . DynamicInvoke , binderBundle : null ) ;
740
+ }
717
741
}
718
742
719
743
if ( ( argumentInfo . Transform & Transform . Reference ) == 0 )
0 commit comments