From 8856d3df230a96b19ed6343b6a565311413b39e0 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Sat, 11 Sep 2021 00:04:39 -0400 Subject: [PATCH] [mini] Use alloca for runtime_invoke retval buffer Fixes https://github.com/dotnet/runtime/issues/58957 Related to https://github.com/dotnet/runtime/pull/58215 which was attempting to fix https://github.com/dotnet/runtime/issues/58190 --- src/mono/mono/mini/mini-runtime.c | 37 ++++++++++++------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index 2abfe01772b27..e6682fb1fa627 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -3159,9 +3159,8 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void { MonoMethodSignature *sig = info->sig; MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method); - gboolean retval_malloc = FALSE; - gpointer retval_ptr; - guint8 retval [MONO_SIZEOF_DYN_CALL_RET_BUF]; + int32_t retval_size = MONO_SIZEOF_DYN_CALL_RET_BUF; + gpointer retval = NULL; int i, pindex; error_init (error); @@ -3191,19 +3190,18 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void if (info->ret_box_class && !sig->ret->byref && (sig->ret->type == MONO_TYPE_VALUETYPE || (sig->ret->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (sig->ret)))) { - // if the return type is a struct and its too big for the stack buffer, malloc instead + // if the return type is a struct, allocate enough stack space to hold it MonoClass *ret_klass = mono_class_from_mono_type_internal (sig->ret); g_assert (!mono_class_has_failure (ret_klass)); int32_t inst_size = mono_class_instance_size (ret_klass); if (inst_size > MONO_SIZEOF_DYN_CALL_RET_BUF) { - retval_malloc = TRUE; - retval_ptr = g_new0 (guint8, inst_size); - g_assert (retval_ptr); + retval_size = inst_size; } } - if (!retval_malloc) - retval_ptr = &retval; - args [pindex ++] = &retval_ptr; + } + retval = g_alloca (retval_size); + if (sig->ret->type != MONO_TYPE_VOID) { + args [pindex ++] = &retval; } for (i = 0; i < sig->param_count; ++i) { MonoType *t = sig->params [i]; @@ -3252,9 +3250,7 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void if (sig->ret->byref) { return mono_value_box_checked (info->ret_box_class, *(gpointer*)retval, error); } else { - MonoObject *ret = mono_value_box_checked (info->ret_box_class, retval_ptr, error); - if (retval_malloc) - g_free (retval_ptr); + MonoObject *ret = mono_value_box_checked (info->ret_box_class, retval, error); return ret; } } else { @@ -3418,25 +3414,22 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec gpointer *args; int i, pindex, buf_size; guint8 *buf; - guint8 retbuf [MONO_SIZEOF_DYN_CALL_RET_BUF]; - guint8 *retval = &retbuf[0]; - gboolean retval_malloc = FALSE; + int32_t retval_size = MONO_SIZEOF_DYN_CALL_RET_BUF; + guint8 *retval = NULL; - /* if the return value is too big, put it in a dynamically allocated temporary */ + /* if the return type is a struct and it's too big, allocate more space for it */ if (info->ret_box_class && !sig->ret->byref && (sig->ret->type == MONO_TYPE_VALUETYPE || (sig->ret->type == MONO_TYPE_GENERICINST && !MONO_TYPE_IS_REFERENCE (sig->ret)))) { - // if the return type is a struct and its too big for the stack buffer, malloc instead MonoClass *ret_klass = mono_class_from_mono_type_internal (sig->ret); g_assert (!mono_class_has_failure (ret_klass)); int32_t inst_size = mono_class_instance_size (ret_klass); if (inst_size > MONO_SIZEOF_DYN_CALL_RET_BUF) { - retval_malloc = TRUE; - retval = g_new0 (guint8, inst_size); - g_assert (retval); + retval_size = inst_size; } } + retval = g_alloca (retval_size); /* Convert the arguments to the format expected by start_dyn_call () */ args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer)); @@ -3487,8 +3480,6 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec return mono_value_box_checked (info->ret_box_class, *(gpointer*)retval, error); } else { MonoObject *boxed_ret = mono_value_box_checked (info->ret_box_class, retval, error); - if (retval_malloc) - g_free (retval); return boxed_ret; } } else {