Skip to content

Commit 288de11

Browse files
authored
[Mono]: Fix static closed delegate fnptr crash. (#68701)
* Fix static closed delegate fnptr crash. When accessing a function pointer to a static closed delegate like done in added test: GetFunctionPointerForDelegate_MarshalledClosedStaticDelegate it will trigger a read outside of the allocated mspecs buffer since invoke_sig and method signature arguments wont match. There was already logic to adjust this in emit_managed_wrapper_ilgen, but done after call to emit_managed_wrapper_validate_signature that will touch memory and depending on its content, trigger a crash. Fix make sure we do signature adjustments first and then validate the signature. Fix also adjust a couple of mspecs allocations to use g_new0 as all others to make sure we get NULL pointers in the mspecs array. Since this scenario was not covered on CI, commit also adds a new test in GetFunctionPointerForDelegateTests.cs covering this scenario.
1 parent c9d8f80 commit 288de11

File tree

4 files changed

+39
-15
lines changed

4 files changed

+39
-15
lines changed

src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/Marshal/GetFunctionPointerForDelegateTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,29 @@ public void GetFunctionPointer_GenericDelegate_ThrowsArgumentException()
9292
AssertExtensions.Throws<ArgumentException>("delegate", () => Marshal.GetFunctionPointerForDelegate(d));
9393
}
9494

95+
[Fact]
96+
[SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser.")]
97+
public void GetFunctionPointerForDelegate_MarshalledOpenStaticDelegate()
98+
{
99+
MethodInfo targetMethod = typeof(GetFunctionPointerForDelegateTests).GetMethod(nameof(Method), BindingFlags.NonPublic | BindingFlags.Static);
100+
Delegate original = targetMethod.CreateDelegate(typeof(NonGenericDelegate), null);
101+
IntPtr ptr = Marshal.GetFunctionPointerForDelegate(original);
102+
Assert.NotEqual(IntPtr.Zero, ptr);
103+
}
104+
105+
[Fact]
106+
[SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser.")]
107+
public void GetFunctionPointerForDelegate_MarshalledClosedStaticDelegate()
108+
{
109+
MethodInfo targetMethod = typeof(GetFunctionPointerForDelegateTests).GetMethod(nameof(Method), BindingFlags.NonPublic | BindingFlags.Static);
110+
Delegate original = targetMethod.CreateDelegate(typeof(NoArgsDelegate), "value");
111+
IntPtr ptr = Marshal.GetFunctionPointerForDelegate(original);
112+
Assert.NotEqual(IntPtr.Zero, ptr);
113+
}
114+
95115
public delegate void GenericDelegate<T>(T t);
96116
public delegate void NonGenericDelegate(string t);
117+
public delegate void NoArgsDelegate();
97118

98119
private static void Method(string s) { }
99120
}

src/mono/mono/metadata/cominterop.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2089,7 +2089,7 @@ cominterop_get_ccw_method (MonoClass *iface, MonoMethod *method, MonoError *erro
20892089
adjust_method = cominterop_get_managed_wrapper_adjusted (method);
20902090
sig_adjusted = mono_method_signature_internal (adjust_method);
20912091

2092-
mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2092+
mspecs = g_new0 (MonoMarshalSpec*, sig_adjusted->param_count + 1);
20932093
mono_method_get_marshal_info (method, mspecs);
20942094

20952095
/* move managed args up one */

src/mono/mono/metadata/marshal-ilgen.c

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,7 @@ emit_native_wrapper_validate_signature (MonoMethodBuilder *mb, MonoMethodSignatu
743743
if (mspecs) {
744744
for (int i = 0; i < sig->param_count; i ++) {
745745
if (mspecs [i + 1] && mspecs [i + 1]->native == MONO_NATIVE_CUSTOM) {
746-
if (!mspecs [i + 1]->data.custom_data.custom_name || strlen (mspecs [i + 1]->data.custom_data.custom_name) == 0) {
746+
if (!mspecs [i + 1]->data.custom_data.custom_name || *mspecs [i + 1]->data.custom_data.custom_name == '\0') {
747747
mono_mb_emit_exception_full (mb, "System", "TypeLoadException", g_strdup ("Missing ICustomMarshaler type"));
748748
return FALSE;
749749
}
@@ -5023,7 +5023,7 @@ emit_managed_wrapper_validate_signature (MonoMethodSignature* sig, MonoMarshalSp
50235023
if (mspecs) {
50245024
for (int i = 0; i < sig->param_count; i ++) {
50255025
if (mspecs [i + 1] && mspecs [i + 1]->native == MONO_NATIVE_CUSTOM) {
5026-
if (!mspecs [i + 1]->data.custom_data.custom_name || strlen (mspecs [i + 1]->data.custom_data.custom_name) == 0) {
5026+
if (!mspecs [i + 1]->data.custom_data.custom_name || *mspecs [i + 1]->data.custom_data.custom_name == '\0') {
50275027
mono_error_set_generic_error (error, "System", "TypeLoadException", "Missing ICustomMarshaler type");
50285028
return FALSE;
50295029
}
@@ -5067,8 +5067,21 @@ emit_managed_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_s
50675067
sig = m->sig;
50685068
csig = m->csig;
50695069

5070-
if (!emit_managed_wrapper_validate_signature (sig, mspecs, error))
5070+
if (!sig->hasthis && sig->param_count != invoke_sig->param_count) {
5071+
/* Closed delegate */
5072+
g_assert (sig->param_count == invoke_sig->param_count + 1);
5073+
closed = TRUE;
5074+
/* Use a new signature without the first argument */
5075+
sig = mono_metadata_signature_dup (sig);
5076+
memmove (&sig->params [0], &sig->params [1], (sig->param_count - 1) * sizeof (MonoType*));
5077+
sig->param_count --;
5078+
}
5079+
5080+
if (!emit_managed_wrapper_validate_signature (sig, mspecs, error)) {
5081+
if (closed)
5082+
g_free (sig);
50715083
return;
5084+
}
50725085

50735086
MonoType *int_type = mono_get_int_type ();
50745087
MonoType *boolean_type = m_class_get_byval_arg (mono_defaults.boolean_class);
@@ -5079,16 +5092,6 @@ emit_managed_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_s
50795092
/* allocate local 2 (boolean) delete_old */
50805093
mono_mb_add_local (mb, boolean_type);
50815094

5082-
if (!sig->hasthis && sig->param_count != invoke_sig->param_count) {
5083-
/* Closed delegate */
5084-
g_assert (sig->param_count == invoke_sig->param_count + 1);
5085-
closed = TRUE;
5086-
/* Use a new signature without the first argument */
5087-
sig = mono_metadata_signature_dup (sig);
5088-
memmove (&sig->params [0], &sig->params [1], (sig->param_count - 1) * sizeof (MonoType*));
5089-
sig->param_count --;
5090-
}
5091-
50925095
if (!MONO_TYPE_IS_VOID(sig->ret)) {
50935096
/* allocate local 3 to store the return value */
50945097
mono_mb_add_local (mb, sig->ret);

src/mono/mono/metadata/marshal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3561,7 +3561,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
35613561
csig = mono_metadata_signature_dup_full (get_method_image (method), sig);
35623562
mono_marshal_set_callconv_from_modopt (method, csig, FALSE);
35633563

3564-
mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
3564+
mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
35653565
mono_method_get_marshal_info (method, mspecs);
35663566

35673567
if (mono_class_try_get_suppress_gc_transition_attribute_class ()) {

0 commit comments

Comments
 (0)