From bff25b77cb7051241bd4324a6ee251f68ffdf3a8 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Wed, 31 Jan 2024 16:11:07 -0500 Subject: [PATCH] [mono][llvm] Fix memory leaks in the llvm backend. Extracted from https://github.com/dotnet/runtime/pull/97096. Author: Johan Lorensson lateralusx.github@gmail.com --- src/mono/mono/mini/mini-llvm.c | 115 +++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 41 deletions(-) diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index e2c68179bf7c9a..dcac99bdb41569 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -606,7 +606,16 @@ ThisType (void) } static Address* -create_address (MonoLLVMModule *module, LLVMValueRef value, LLVMTypeRef type) +create_address (EmitContext *ctx, LLVMValueRef value, LLVMTypeRef type) +{ + Address *res = (Address *)mono_mempool_alloc0 (ctx->mempool, sizeof(Address)); + res->value = value; + res->type = type; + return res; +} + +static Address* +create_module_address (MonoLLVMModule *module, LLVMValueRef value, LLVMTypeRef type) { Address *res = g_new0 (Address, 1); res->value = value; @@ -615,7 +624,7 @@ create_address (MonoLLVMModule *module, LLVMValueRef value, LLVMTypeRef type) } static void -address_free (gpointer addr) +free_module_address (gpointer addr) { g_free (addr); } @@ -1535,6 +1544,7 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * { LLVMTypeRef ret_type; LLVMTypeRef *param_types = NULL; + LLVMTypeRef *etypes = NULL; LLVMTypeRef res; int pindex, vret_arg_pindex = 0; gboolean vretaddr = FALSE; @@ -1618,7 +1628,7 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * param_types = g_new0 (LLVMTypeRef, (sig->param_count * 8) + 3); if (element_types) - *element_types = g_new0 (LLVMTypeRef, (sig->param_count * 8) + 3); + etypes = g_new0 (LLVMTypeRef, (sig->param_count * 8) + 3); pindex = 0; if (cinfo->ret.storage == LLVMArgVtypeByRef) { /* @@ -1630,10 +1640,11 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * param_types [pindex] = type_to_llvm_arg_type (ctx, sig->ret); if (!ctx_ok (ctx)) { g_free (param_types); + g_free (etypes); return NULL; } - if (element_types) - (*element_types) [pindex] = param_types [pindex]; + if (etypes) + etypes [pindex] = param_types [pindex]; param_types [pindex] = pointer_type (param_types [pindex]); pindex ++; } @@ -1707,8 +1718,8 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * param_types [pindex] = type_to_llvm_arg_type (ctx, ainfo->type); if (!ctx_ok (ctx)) break; - if (element_types) - (*element_types) [pindex] = param_types [pindex]; + if (etypes) + etypes [pindex] = param_types [pindex]; param_types [pindex] = pointer_type (param_types [pindex]); pindex ++; break; @@ -1724,8 +1735,8 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * param_types [pindex] = type_to_llvm_arg_type (ctx, ainfo->type); if (!ctx_ok (ctx)) break; - if (element_types) - (*element_types) [pindex] = param_types [pindex]; + if (etypes) + etypes [pindex] = param_types [pindex]; param_types [pindex] = pointer_type (param_types [pindex]); pindex ++; break; @@ -1746,13 +1757,13 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * break; case LLVMArgGsharedvtFixed: case LLVMArgGsharedvtFixedVtype: - if (element_types) - (*element_types) [pindex] = type_to_llvm_arg_type (ctx, ainfo->type); + if (etypes) + etypes [pindex] = type_to_llvm_arg_type (ctx, ainfo->type); param_types [pindex ++] = pointer_type (type_to_llvm_arg_type (ctx, ainfo->type)); break; case LLVMArgGsharedvtVariable: - if (element_types) - (*element_types) [pindex] = IntPtrType (); + if (etypes) + etypes [pindex] = IntPtrType (); param_types [pindex ++] = pointer_type (IntPtrType ()); break; default: @@ -1762,6 +1773,7 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * } if (!ctx_ok (ctx)) { g_free (param_types); + g_free (etypes); return NULL; } if (vretaddr && vret_arg_pindex == pindex) @@ -1781,6 +1793,9 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * res = LLVMFunctionType (ret_type, param_types, pindex, FALSE); g_free (param_types); + if (element_types) + *element_types = etypes; + return res; } @@ -2055,15 +2070,16 @@ get_aotconst_module (MonoLLVMModule *module, LLVMBuilderRef builder, MonoJumpInf // FIXME: char *name = get_aotconst_name (ji->type, ji->data.target, got_offset); char *symbol = g_strdup_printf ("aotconst_%s", name); - g_free (name); LLVMValueRef v = LLVMAddGlobal (module->lmodule, const_var_type, symbol); + g_free (name); + g_free (symbol); LLVMSetVisibility (v, LLVMHiddenVisibility); LLVMSetLinkage (v, LLVMInternalLinkage); LLVMSetInitializer (v, LLVMConstNull (const_var_type)); // FIXME: LLVMSetAlignment (v, 8); - addr = create_address (module, v, const_var_type); + addr = create_module_address (module, v, const_var_type); g_hash_table_insert (module->aotconst_vars, GINT_TO_POINTER (got_offset), addr); } @@ -2264,6 +2280,8 @@ get_callee_module (MonoLLVMModule *module, LLVMTypeRef llvm_sig, MonoJumpInfoTyp LLVMSetVisibility (callee, LLVMHiddenVisibility); g_hash_table_insert (module->plt_entries, (char*)callee_name, callee); + } else { + g_free (callee_name); } ji = g_new0 (MonoJumpInfo, 1); @@ -2349,6 +2367,8 @@ get_callee (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gcons LLVMSetVisibility (callee, LLVMHiddenVisibility); g_hash_table_insert (ctx->module->plt_entries, (char*)callee_name, callee); + } else { + g_free (callee_name); } if (ctx->cfg->compile_aot) { @@ -2956,7 +2976,7 @@ static Address* build_alloca_address (EmitContext *ctx, MonoType *t) { LLVMValueRef v = build_named_alloca (ctx, t, ""); - return create_address (ctx->module, v, type_to_llvm_type (ctx, t)); + return create_address (ctx, v, type_to_llvm_type (ctx, t)); } static LLVMValueRef @@ -3546,7 +3566,7 @@ emit_init_func (MonoLLVMModule *module, MonoAotInitSubtype subtype) LLVMDisposeBuilder (builder); g_free (name); - return create_address (module, func, func_type); + return create_module_address (module, func, func_type); } /* Emit a wrapper around the parameterless JIT icall ICALL_ID with a cold calling convention */ @@ -3989,7 +4009,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) // FIXME: Count only live vregs LLVMTypeRef pin_area_type = LLVMArrayType (IntPtrType (), ngc_vars); LLVMValueRef gc_pin_area = build_alloca_llvm_type_name (ctx, pin_area_type, 0, "gc_pin"); - ctx->gc_pin_area = create_address (ctx->module, gc_pin_area, pin_area_type); + ctx->gc_pin_area = create_address (ctx, gc_pin_area, pin_area_type); #endif /* @@ -4012,11 +4032,11 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) // FIXME: Allocate a smaller struct in the deopt case int size = cfg->deopt ? MONO_ABI_SIZEOF (MonoLMFExt) : MONO_ABI_SIZEOF (MonoLMF); etype = LLVMArrayType (LLVMInt8Type (), size); - ctx->addresses [var->dreg] = create_address (ctx->module, build_alloca_llvm_type_name (ctx, etype, sizeof (target_mgreg_t), "lmf"), etype); + ctx->addresses [var->dreg] = create_address (ctx, build_alloca_llvm_type_name (ctx, etype, sizeof (target_mgreg_t), "lmf"), etype); } else { char *name = g_strdup_printf ("vreg_loc_%d", var->dreg); etype = type_to_llvm_type (ctx, var->inst_vtype); - ctx->addresses [var->dreg] = create_address (ctx->module, build_named_alloca (ctx, var->inst_vtype, name), etype); + ctx->addresses [var->dreg] = create_address (ctx, build_named_alloca (ctx, var->inst_vtype, name), etype); g_free (name); } } @@ -4066,14 +4086,14 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) } case LLVMArgVtypeByVal: { g_assert (ctx->param_etypes [pindex]); - ctx->addresses [reg] = create_address (ctx->module, LLVMGetParam (ctx->lmethod, pindex), ctx->param_etypes [pindex]); + ctx->addresses [reg] = create_address (ctx, LLVMGetParam (ctx->lmethod, pindex), ctx->param_etypes [pindex]); break; } case LLVMArgVtypeAddr: case LLVMArgVtypeByRef: { /* The argument is passed by ref */ g_assert (ctx->param_etypes [pindex]); - ctx->addresses [reg] = create_address (ctx->module, LLVMGetParam (ctx->lmethod, pindex), ctx->param_etypes [pindex]); + ctx->addresses [reg] = create_address (ctx, LLVMGetParam (ctx->lmethod, pindex), ctx->param_etypes [pindex]); break; } case LLVMArgAsIArgs: { @@ -4143,7 +4163,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) /* The IR treats these as variables with addresses */ if (!ctx->addresses [reg]) { g_assert (ctx->param_etypes [pindex]); - ctx->addresses [reg] = create_address (ctx->module, LLVMGetParam (ctx->lmethod, pindex), ctx->param_etypes [pindex]); + ctx->addresses [reg] = create_address (ctx, LLVMGetParam (ctx->lmethod, pindex), ctx->param_etypes [pindex]); } break; default: { @@ -4286,7 +4306,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) ctx->il_state = build_alloca_llvm_type_name (ctx, il_state_type, 0, "il_state"); g_assert (cfg->il_state_var); - ctx->addresses [cfg->il_state_var->dreg] = create_address (ctx->module, ctx->il_state, il_state_type); + ctx->addresses [cfg->il_state_var->dreg] = create_address (ctx, ctx->il_state, il_state_type); /* Set il_state->il_offset = -1 */ index [0] = const_int32 (0); @@ -4548,7 +4568,9 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, static int tramp_index; char *name; - name = g_strdup_printf ("[tramp_%d] %s", tramp_index, mono_method_full_name (call->method, TRUE)); + char *full_method_name = mono_method_full_name (call->method, TRUE); + name = g_strdup_printf ("[tramp_%d] %s", tramp_index, full_method_name); + g_free (full_method_name); tramp_index ++; /* @@ -4571,7 +4593,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, LLVMValueRef tramp_var = LLVMAddGlobal (ctx->lmodule, tramp_var_type, name); LLVMSetInitializer (tramp_var, LLVMConstIntToPtr (const_int64 ((guint64)(size_t)target), tramp_var_type)); LLVMSetLinkage (tramp_var, LLVMExternalLinkage); - tramp_var_addr = create_address (ctx->module, tramp_var, tramp_var_type); + tramp_var_addr = create_address (ctx, tramp_var, tramp_var_type); g_hash_table_insert (ctx->jit_callees, call->method, tramp_var_addr); } callee = LLVMBuildLoad2 (builder, tramp_var_addr->type, tramp_var_addr->value, ""); @@ -4831,8 +4853,11 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, mono_llvm_set_call_notailcall (lcall); // Add original method name we are currently emitting as a custom string metadata (the only way to leave comments in LLVM IR) - if (mono_debug_enabled () && call && call->method) - mono_llvm_add_string_metadata (lcall, "managed_name", mono_method_full_name (call->method, TRUE)); + if (mono_debug_enabled () && call && call->method) { + char *full_method_name = mono_method_full_name (call->method, TRUE); + mono_llvm_add_string_metadata (lcall, "managed_name", full_method_name); + g_free (full_method_name); + } // As per the LLVM docs, a function has a noalias return value if and only if // it is an allocation function. This is an allocation function. @@ -4963,6 +4988,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, values [ins->dreg] = LLVMBuildLoad2 (builder, rtype, addr, load_name); } + g_free (param_etypes); *builder_ref = ctx->builder; } @@ -7819,7 +7845,7 @@ MONO_RESTORE_WARNING if (!addresses [ins->dreg]) { LLVMTypeRef etype = type_to_llvm_type (ctx, m_class_get_byval_arg (klass)); - addresses [ins->dreg] = create_address (ctx->module, build_named_alloca (ctx, m_class_get_byval_arg (klass), "vzero"), etype); + addresses [ins->dreg] = create_address (ctx, build_named_alloca (ctx, m_class_get_byval_arg (klass), "vzero"), etype); } LLVMValueRef ptr = build_ptr_cast (builder, addresses [ins->dreg]->value, pointer_type (LLVMInt8Type ())); emit_memset (ctx, ptr, const_int32 (mono_class_value_size (klass, NULL)), 0); @@ -7910,7 +7936,7 @@ MONO_RESTORE_WARNING MonoInst *var = get_vreg_to_inst (cfg, ins->sreg1); if (var && var->opcode == OP_GSHAREDVT_LOCAL) { - addresses [ins->dreg] = create_address (ctx->module, convert (ctx, emit_gsharedvt_ldaddr (ctx, var->dreg), pointer_type (IntPtrType ())), IntPtrType ()); + addresses [ins->dreg] = create_address (ctx, convert (ctx, emit_gsharedvt_ldaddr (ctx, var->dreg), pointer_type (IntPtrType ())), IntPtrType ()); } else { g_assert (addresses [ins->sreg1]); addresses [ins->dreg] = addresses [ins->sreg1]; @@ -7927,7 +7953,7 @@ MONO_RESTORE_WARNING if (!addresses [ins->sreg1]) { g_assert (!addresses [ins->dreg]); - addresses [ins->dreg] = create_address (ctx->module, build_named_alloca (ctx, t, "llvm_outarg_vt"), etype); + addresses [ins->dreg] = create_address (ctx, build_named_alloca (ctx, t, "llvm_outarg_vt"), etype); g_assert (values [ins->sreg1]); LLVMBuildStore (builder, convert (ctx, values [ins->sreg1], etype), addresses [ins->dreg]->value); } else if (ainfo->storage == LLVMArgVtypeAddr || values [ins->sreg1] == addresses [ins->sreg1]->value) { @@ -11585,7 +11611,7 @@ MONO_RESTORE_WARNING } if (!addresses [ins->dreg]) { LLVMTypeRef etype = type_to_llvm_type (ctx, m_class_get_byval_arg (ins->klass)); - addresses [ins->dreg] = create_address (ctx->module, build_named_alloca (ctx, m_class_get_byval_arg (ins->klass), oname), etype); + addresses [ins->dreg] = create_address (ctx, build_named_alloca (ctx, m_class_get_byval_arg (ins->klass), oname), etype); } LLVMTypeRef ret_t = simd_valuetuple_to_llvm_type (ctx, ins->klass); LLVMTypeRef vec_t = LLVMGetElementType (ret_t); @@ -12614,7 +12640,9 @@ emit_method_inner (EmitContext *ctx) int lcount = atoi (llvm_count_str); g_free (llvm_count_str); if (count == lcount) { - printf ("LAST: %s\n", mono_method_full_name (cfg->method, TRUE)); + char *full_method_name = mono_method_full_name (cfg->method, TRUE); + printf ("LAST: %s\n", full_method_name); + g_free (full_method_name); fflush (stdout); } if (count > lcount) { @@ -12962,7 +12990,7 @@ emit_method_inner (EmitContext *ctx) values [ins->dreg] = LLVMBuildPhi (builder, phi_type, dname); if (ins->opcode == OP_VPHI) - ctx->addresses [ins->dreg] = create_address (ctx->module, values [ins->dreg], etype); + ctx->addresses [ins->dreg] = create_address (ctx, values [ins->dreg], etype); g_ptr_array_add (ctx->phi_values, values [ins->dreg]); @@ -13263,7 +13291,9 @@ emit_method_inner (EmitContext *ctx) } if (cfg->verbose_level > 1) { - g_print ("\n*** Unoptimized LLVM IR for %s ***\n", mono_method_full_name (cfg->method, TRUE)); + char *full_method_name = mono_method_full_name (cfg->method, TRUE); + g_print ("\n*** Unoptimized LLVM IR for %s ***\n", full_method_name); + g_free (full_method_name); if (cfg->compile_aot) { mono_llvm_dump_value (method); } else { @@ -13706,11 +13736,11 @@ mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, module->max_got_offset = initial_got_size; module->context = LLVMGetGlobalContext (); module->cfgs = g_ptr_array_new (); - module->aotconst_vars = g_hash_table_new_full (NULL, NULL, NULL, address_free); + module->aotconst_vars = g_hash_table_new_full (NULL, NULL, NULL, free_module_address); module->llvm_types = g_hash_table_new (NULL, NULL); - module->plt_entries = g_hash_table_new (g_str_hash, g_str_equal); - module->plt_entries_ji = g_hash_table_new (NULL, NULL); - module->direct_callables = g_hash_table_new (g_str_hash, g_str_equal); + module->plt_entries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + module->plt_entries_ji = g_hash_table_new_full (NULL, NULL, g_free, NULL); + module->direct_callables = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); module->idx_to_lmethod = g_hash_table_new (NULL, NULL); module->method_to_lmethod = g_hash_table_new (NULL, NULL); module->method_to_call_info = g_hash_table_new (NULL, NULL); @@ -13789,7 +13819,7 @@ mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, LLVMSetVisibility (dummy_got_var, LLVMHiddenVisibility); LLVMSetLinkage (dummy_got_var, LLVMInternalLinkage); - module->dummy_got_var = create_address (module, dummy_got_var, got_type); + module->dummy_got_var = create_module_address (module, dummy_got_var, got_type); } /* Add initialization array */ @@ -13797,7 +13827,7 @@ mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, LLVMValueRef inited_var = LLVMAddGlobal (aot_module.lmodule, inited_type, "mono_inited_tmp"); LLVMSetInitializer (inited_var, LLVMConstNull (inited_type)); - module->inited_var = create_address (module, inited_var, inited_type); + module->inited_var = create_module_address (module, inited_var, inited_type); create_aot_info_var (module); @@ -13845,12 +13875,15 @@ mono_llvm_free_aot_module (void) g_hash_table_destroy (module->method_to_lmethod); g_hash_table_destroy (module->method_to_call_info); g_hash_table_destroy (module->idx_to_unbox_tramp); + g_hash_table_destroy (module->got_idx_to_type); g_hash_table_destroy (module->no_method_table_lmethods); g_hash_table_destroy (module->intrins_id_to_intrins); g_hash_table_destroy (module->intrins_id_to_type); g_ptr_array_free (module->cfgs, TRUE); g_ptr_array_free (module->callsite_list, TRUE); + if (module->used) + g_ptr_array_free (module->used, TRUE); } void