From: Zoltan Varga Date: Sun, 23 Apr 2017 23:16:49 +0000 (-0400) Subject: Make the loading of llvm EH info async safe. (#4725) X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=1debf3934120547b3003c0ec4ec90bae4b08ee13;p=mono.git Make the loading of llvm EH info async safe. (#4725) * [aot] Emit class references in EH info in such as way that they can be skipped when reading them in async context. * [aot] Rewrite the LLVM EH info loading code by moving allocations to callers so the lower level code is async safe. * [aot] Make the memory allocation in the loading of llvm EH info async safe. Remove fields from MonoLLVMFDEInfo which are passed as parameters. * [runtime] Add the ability to store the unwind info address/length in the MonoJitInfo structure instead of referencing it using the 'unwind_info' field. * [aot] Make the loading of llvm EH information async safe. --- diff --git a/mono/metadata/domain-internals.h b/mono/metadata/domain-internals.h index 6b3369fd2e4..3cfa0224612 100644 --- a/mono/metadata/domain-internals.h +++ b/mono/metadata/domain-internals.h @@ -184,12 +184,22 @@ typedef struct { int thunks_size; } MonoThunkJitInfo; +typedef struct { + guint8 *unw_info; + int unw_info_len; +} MonoUnwindJitInfo; + typedef enum { JIT_INFO_NONE = 0, JIT_INFO_HAS_GENERIC_JIT_INFO = (1 << 0), JIT_INFO_HAS_TRY_BLOCK_HOLES = (1 << 1), JIT_INFO_HAS_ARCH_EH_INFO = (1 << 2), - JIT_INFO_HAS_THUNK_INFO = (1 << 3) + JIT_INFO_HAS_THUNK_INFO = (1 << 3), + /* + * If this is set, the unwind info is stored in the structure, instead of being pointed to by the + * 'unwind_info' field. + */ + JIT_INFO_HAS_UNWIND_INFO = (1 << 4) } MonoJitInfoFlags; struct _MonoJitInfo { @@ -217,6 +227,7 @@ struct _MonoJitInfo { gboolean has_try_block_holes:1; gboolean has_arch_eh_info:1; gboolean has_thunk_info:1; + gboolean has_unwind_info:1; gboolean from_aot:1; gboolean from_llvm:1; gboolean dbg_attrs_inited:1; @@ -536,6 +547,9 @@ mono_jit_info_get_arch_eh_info (MonoJitInfo *ji); MonoThunkJitInfo* mono_jit_info_get_thunk_info (MonoJitInfo *ji); +MonoUnwindJitInfo* +mono_jit_info_get_unwind_info (MonoJitInfo *ji); + /* * Installs a new function which is used to return a MonoJitInfo for a method inside * an AOT module. diff --git a/mono/metadata/jit-info.c b/mono/metadata/jit-info.c index 50ca4e7e31d..cf9992615e8 100644 --- a/mono/metadata/jit-info.c +++ b/mono/metadata/jit-info.c @@ -801,6 +801,8 @@ mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes) size += sizeof (MonoArchEHJitInfo); if (flags & JIT_INFO_HAS_THUNK_INFO) size += sizeof (MonoThunkJitInfo); + if (flags & JIT_INFO_HAS_UNWIND_INFO) + size += sizeof (MonoUnwindJitInfo); return size; } @@ -820,6 +822,8 @@ mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_ ji->has_arch_eh_info = 1; if (flags & JIT_INFO_HAS_THUNK_INFO) ji->has_thunk_info = 1; + if (flags & JIT_INFO_HAS_UNWIND_INFO) + ji->has_unwind_info = 1; } /** @@ -996,3 +1000,22 @@ mono_jit_info_get_thunk_info (MonoJitInfo *ji) return NULL; } } + +MonoUnwindJitInfo* +mono_jit_info_get_unwind_info (MonoJitInfo *ji) +{ + if (ji->has_unwind_info) { + char *ptr = (char*)&ji->clauses [ji->num_clauses]; + if (ji->has_generic_jit_info) + ptr += sizeof (MonoGenericJitInfo); + if (ji->has_try_block_holes) + ptr += try_block_hole_table_size (ji); + if (ji->has_arch_eh_info) + ptr += sizeof (MonoArchEHJitInfo); + if (ji->has_thunk_info) + ptr += sizeof (MonoThunkJitInfo); + return (MonoUnwindJitInfo*)ptr; + } else { + return NULL; + } +} diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 4b94301b046..c18f91c9749 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -6134,11 +6134,23 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg, gboolean stor clause = &header->clauses [k]; encode_value (clause->flags, p, &p); - if (clause->data.catch_class) { - encode_value (1, p, &p); - encode_klass_ref (acfg, clause->data.catch_class, p, &p); - } else { - encode_value (0, p, &p); + if (!(clause->flags == MONO_EXCEPTION_CLAUSE_FILTER || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) { + if (clause->data.catch_class) { + guint8 *buf2, *p2; + int len; + + buf2 = (guint8 *)g_malloc (4096); + p2 = buf2; + encode_klass_ref (acfg, clause->data.catch_class, p2, &p2); + len = p2 - buf2; + g_assert (len < 4096); + encode_value (len, p, &p); + memcpy (p, buf2, len); + p += p2 - buf2; + g_free (buf2); + } else { + encode_value (0, p, &p); + } } /* Emit the IL ranges too, since they might not be available at runtime */ diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 3a5b1813ee1..d5ae8dbeece 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -2665,15 +2665,15 @@ is_thumb_code (MonoAotModule *amodule, guint8 *code) * * Decode the EH information emitted by our modified LLVM compiler and construct a * MonoJitInfo structure from it. - * LOCKING: Acquires the domain lock. + * If JINFO is NULL, set OUT_LLVM_CLAUSES to the number of llvm level clauses. + * This function is async safe when called in async context. */ -static MonoJitInfo* -decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, - MonoMethod *method, guint8 *code, guint32 code_len, +static void +decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, MonoJitInfo *jinfo, + guint8 *code, guint32 code_len, MonoJitExceptionInfo *clauses, int num_clauses, - MonoJitInfoFlags flags, GSList **nesting, - int *this_reg, int *this_offset) + int *this_reg, int *this_offset, int *out_llvm_clauses) { guint8 *p, *code1, *code2; guint8 *fde, *cie, *code_start, *code_end; @@ -2683,14 +2683,19 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, MonoJitExceptionInfo *ei; guint32 fde_len, ei_len, nested_len, nindex; gpointer *type_info; - MonoJitInfo *jinfo; MonoLLVMFDEInfo info; + guint8 *unw_info; + gboolean async; + + async = mono_thread_info_is_async_context (); if (!amodule->mono_eh_frame) { - jinfo = (MonoJitInfo *)mono_domain_alloc0_lock_free (domain, mono_jit_info_size (flags, num_clauses, 0)); - mono_jit_info_init (jinfo, method, code, code_len, flags, num_clauses, 0); + if (!jinfo) { + *out_llvm_clauses = num_clauses; + return; + } memcpy (jinfo->clauses, clauses, num_clauses * sizeof (MonoJitExceptionInfo)); - return jinfo; + return; } g_assert (amodule->mono_eh_frame && code); @@ -2759,13 +2764,29 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, /* This won't overflow because there is +1 entry in the table */ fde_len = table [(pos * 2) + 2 + 1] - table [(pos * 2) + 1]; - mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, code_start, &info); - ei = info.ex_info; + /* Compute lengths */ + mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, code_start, &info, NULL, NULL, NULL); + + if (async) { + /* These are leaked, but the leak is bounded */ + ei = mono_domain_alloc0_lock_free (domain, info.ex_info_len * sizeof (MonoJitExceptionInfo)); + type_info = mono_domain_alloc0_lock_free (domain, info.ex_info_len * sizeof (gpointer)); + unw_info = mono_domain_alloc0_lock_free (domain, info.unw_info_len); + } else { + ei = (MonoJitExceptionInfo *)g_malloc0 (info.ex_info_len * sizeof (MonoJitExceptionInfo)); + type_info = (gpointer *)g_malloc0 (info.ex_info_len * sizeof (gpointer)); + unw_info = (guint8*)g_malloc0 (info.unw_info_len); + } + mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, code_start, &info, ei, type_info, unw_info); + ei_len = info.ex_info_len; - type_info = info.type_info; *this_reg = info.this_reg; *this_offset = info.this_offset; + /* + * LLVM might represent one IL region with multiple regions. + */ + /* Count number of nested clauses */ nested_len = 0; for (i = 0; i < ei_len; ++i) { @@ -2777,18 +2798,16 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, nested_len ++; } - /* - * LLVM might represent one IL region with multiple regions, so have to - * allocate a new JI. - */ - jinfo = - (MonoJitInfo *)mono_domain_alloc0_lock_free (domain, mono_jit_info_size (flags, ei_len + nested_len, 0)); - mono_jit_info_init (jinfo, method, code, code_len, flags, ei_len + nested_len, 0); + if (!jinfo) { + *out_llvm_clauses = ei_len + nested_len; + return; + } - jinfo->unwind_info = mono_cache_unwind_info (info.unw_info, info.unw_info_len); - /* This signals that unwind_info points to a normal cached unwind info */ - jinfo->from_aot = 0; - jinfo->from_llvm = 1; + /* Store the unwind info addr/length in the MonoJitInfo structure itself so its async safe */ + MonoUnwindJitInfo *jinfo_unwind = mono_jit_info_get_unwind_info (jinfo); + g_assert (jinfo_unwind); + jinfo_unwind->unw_info = unw_info; + jinfo_unwind->unw_info_len = info.unw_info_len; for (i = 0; i < ei_len; ++i) { /* @@ -2838,8 +2857,6 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, } } g_assert (nindex == ei_len + nested_len); - - return jinfo; } static gpointer @@ -2924,24 +2941,41 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, MonoJitExceptionInfo *clauses; GSList **nesting; - // FIXME: async - g_assert (!async); - /* * Part of the info is encoded by the AOT compiler, the rest is in the .eh_frame * section. */ - clauses = g_new0 (MonoJitExceptionInfo, num_clauses); - nesting = g_new0 (GSList*, num_clauses); + if (async) { + if (num_clauses < 16) { + clauses = g_newa (MonoJitExceptionInfo, num_clauses); + nesting = g_newa (GSList*, num_clauses); + } else { + clauses = alloc0_jit_info_data (domain, sizeof (MonoJitExceptionInfo) * num_clauses, TRUE); + nesting = alloc0_jit_info_data (domain, sizeof (GSList*) * num_clauses, TRUE); + } + memset (clauses, 0, sizeof (MonoJitExceptionInfo) * num_clauses); + memset (nesting, 0, sizeof (GSList*) * num_clauses); + } else { + clauses = g_new0 (MonoJitExceptionInfo, num_clauses); + nesting = g_new0 (GSList*, num_clauses); + } for (i = 0; i < num_clauses; ++i) { MonoJitExceptionInfo *ei = &clauses [i]; ei->flags = decode_value (p, &p); - if (decode_value (p, &p)) { - ei->data.catch_class = decode_klass_ref (amodule, p, &p, &error); - mono_error_cleanup (&error); /* FIXME don't swallow the error */ + if (!(ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) { + int len = decode_value (p, &p); + + if (len > 0) { + if (async) { + p += len; + } else { + ei->data.catch_class = decode_klass_ref (amodule, p, &p, &error); + mono_error_cleanup (&error); /* FIXME don't swallow the error */ + } + } } ei->clause_index = i; @@ -2956,16 +2990,29 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain, int nesting_index = decode_value (p, &p); if (nesting_index == -1) break; + // FIXME: async + g_assert (!async); nesting [i] = g_slist_prepend (nesting [i], GINT_TO_POINTER (nesting_index)); } } - jinfo = decode_llvm_mono_eh_frame (amodule, domain, method, code, code_len, clauses, num_clauses, flags, nesting, &this_reg, &this_offset); + flags |= JIT_INFO_HAS_UNWIND_INFO; + + int num_llvm_clauses; + /* Get the length first */ + decode_llvm_mono_eh_frame (amodule, domain, NULL, code, code_len, clauses, num_clauses, nesting, &this_reg, &this_offset, &num_llvm_clauses); + len = mono_jit_info_size (flags, num_llvm_clauses, num_holes); + jinfo = (MonoJitInfo *)alloc0_jit_info_data (domain, len, async); + mono_jit_info_init (jinfo, method, code, code_len, flags, num_llvm_clauses, num_holes); - g_free (clauses); - for (i = 0; i < num_clauses; ++i) - g_slist_free (nesting [i]); - g_free (nesting); + decode_llvm_mono_eh_frame (amodule, domain, jinfo, code, code_len, clauses, num_clauses, nesting, &this_reg, &this_offset, NULL); + + if (!async) { + g_free (clauses); + for (i = 0; i < num_clauses; ++i) + g_slist_free (nesting [i]); + g_free (nesting); + } } else { len = mono_jit_info_size (flags, num_clauses, num_holes); jinfo = (MonoJitInfo *)alloc0_jit_info_data (domain, len, async); diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index cacc74c49bc..45ceb0d6629 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -2995,7 +2995,12 @@ mono_restore_context (MonoContext *ctx) guint8* mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len) { - if (ji->from_aot) + if (ji->has_unwind_info) { + /* The address/length in the MonoJitInfo structure itself */ + MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji); + *unwind_info_len = info->unw_info_len; + return info->unw_info; + } else if (ji->from_aot) return mono_aot_get_unwind_info (ji, unwind_info_len); else return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len); diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index b53dafd323e..c40b98b9f2d 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -7719,6 +7719,7 @@ decode_llvm_eh_info (EmitContext *ctx, gpointer eh_frame) guint32 ei_len, i, nested_len; gpointer *type_info; gint32 *table; + guint8 *unw_info; /* * Decode the one element EH table emitted by the MonoException class @@ -7751,9 +7752,16 @@ decode_llvm_eh_info (EmitContext *ctx, gpointer eh_frame) fde = (guint8*)eh_frame + fde_offset; cie = (guint8*)table; - mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, cfg->native_code, &info); + /* Compute lengths */ + mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, cfg->native_code, &info, NULL, NULL, NULL); - cfg->encoded_unwind_ops = info.unw_info; + ei = (MonoJitExceptionInfo *)g_malloc0 (info.ex_info_len * sizeof (MonoJitExceptionInfo)); + type_info = (gpointer *)g_malloc0 (info.ex_info_len * sizeof (gpointer)); + unw_info = (guint8*)g_malloc0 (info.unw_info_len); + + mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, cfg->native_code, &info, ei, type_info, unw_info); + + cfg->encoded_unwind_ops = unw_info; cfg->encoded_unwind_ops_len = info.unw_info_len; if (cfg->verbose_level > 1) mono_print_unwind_info (cfg->encoded_unwind_ops, cfg->encoded_unwind_ops_len); @@ -7762,9 +7770,7 @@ decode_llvm_eh_info (EmitContext *ctx, gpointer eh_frame) cfg->llvm_this_offset = info.this_offset; } - ei = info.ex_info; ei_len = info.ex_info_len; - type_info = info.type_info; // Nested clauses are currently disabled nested_len = 0; diff --git a/mono/mini/mini-unwind.h b/mono/mini/mini-unwind.h index 26c7ada5df3..cdcebec8214 100644 --- a/mono/mini/mini-unwind.h +++ b/mono/mini/mini-unwind.h @@ -196,18 +196,15 @@ guint8* mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len /* Data retrieved from an LLVM Mono FDE entry */ typedef struct { - /* Malloc'ed */ - guint8 *unw_info; guint32 unw_info_len; - MonoJitExceptionInfo *ex_info; guint32 ex_info_len; - gpointer *type_info; + int type_info_len; int this_reg; int this_offset; } MonoLLVMFDEInfo; void -mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res) MONO_LLVM_INTERNAL; +mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res, MonoJitExceptionInfo *ei, gpointer *type_info, guint8 *unw_info) MONO_LLVM_INTERNAL; GSList* mono_unwind_get_cie_program (void); diff --git a/mono/mini/mini.h b/mono/mini/mini.h index 191386a06bb..98714bd2200 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -122,7 +122,7 @@ #endif /* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION 139 +#define MONO_AOT_FILE_VERSION 140 //TODO: This is x86/amd64 specific. #define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6)) diff --git a/mono/mini/unwind.c b/mono/mini/unwind.c index 2dc04322dc6..72f5d0d59e0 100644 --- a/mono/mini/unwind.c +++ b/mono/mini/unwind.c @@ -867,9 +867,10 @@ read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp) * decode_lsda: * * Decode the Mono specific Language Specific Data Area generated by LLVM. + * This function is async safe. */ static void -decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset) +decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo *ex_info, gpointer *type_info, guint32 *ex_info_len, int *this_reg, int *this_offset) { guint8 *p; int i, ncall_sites, this_encoding; @@ -905,12 +906,8 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 ncall_sites = decode_uleb128 (p, &p); p = (guint8*)ALIGN_TO ((mgreg_t)p, 4); - if (ex_info) { - *ex_info = (MonoJitExceptionInfo *)g_malloc0 (ncall_sites * sizeof (MonoJitExceptionInfo)); + if (ex_info_len) *ex_info_len = ncall_sites; - } - if (type_info) - *type_info = (gpointer *)g_malloc0 (ncall_sites * sizeof (gpointer)); for (i = 0; i < ncall_sites; ++i) { int block_start_offset, block_size, landing_pad; @@ -930,11 +927,11 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo); if (ex_info) { - if (*type_info) - (*type_info) [i] = tinfo; - (*ex_info)[i].try_start = code + block_start_offset; - (*ex_info)[i].try_end = code + block_start_offset + block_size; - (*ex_info)[i].handler_start = code + landing_pad; + if (type_info) + type_info [i] = tinfo; + ex_info[i].try_start = code + block_start_offset; + ex_info[i].try_end = code + block_start_offset + block_size; + ex_info[i].handler_start = code + landing_pad; } } } @@ -1073,7 +1070,16 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi if (lsda_offset != 0) { lsda = fde_aug + lsda_offset; - decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset); + /* Get the lengths first */ + guint32 len; + decode_lsda (lsda, code, NULL, NULL, &len, this_reg, this_offset); + + if (ex_info) + *ex_info = (MonoJitExceptionInfo *)g_malloc0 (len * sizeof (MonoJitExceptionInfo)); + if (type_info) + *type_info = (gpointer *)g_malloc0 (len * sizeof (gpointer)); + + decode_lsda (lsda, code, ex_info ? *ex_info : NULL, type_info ? *type_info : NULL, ex_info_len, this_reg, this_offset); } } @@ -1116,13 +1122,15 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi * mono_unwind_decode_mono_fde: * * Decode an FDE entry in the LLVM emitted mono EH frame. - * info->ex_info is set to a malloc-ed array of MonoJitExceptionInfo structures, - * only try_start, try_end and handler_start is set. - * info->type_info is set to a malloc-ed array containing the ttype table from the - * LSDA. + * If EI/TYPE_INFO/UNW_INFO are NULL, compute only the value of the scalar fields in INFO. + * Otherwise: + * - Fill out EX_INFO with try_start, try_end and handler_start. + * - Fill out TYPE_INFO with the ttype table from the LSDA. + * - Fill out UNW_INFO with the unwind info. + * This function is async safe. */ void -mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res) +mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res, MonoJitExceptionInfo *ex_info, gpointer *type_info, guint8 *unw_info) { guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf; int has_aug, aug_len, cie_cfi_len, fde_cfi_len; @@ -1152,7 +1160,10 @@ mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 /* The LSDA is embedded directly into the FDE */ lsda = fde_aug; - decode_lsda (lsda, code, &res->ex_info, &res->ex_info_len, &res->type_info, &res->this_reg, &res->this_offset); + /* Get the lengths first */ + decode_lsda (lsda, code, NULL, NULL, &res->ex_info_len, &res->this_reg, &res->this_offset); + + decode_lsda (lsda, code, ex_info, type_info, NULL, &res->this_reg, &res->this_offset); } /* Decode CIE */ @@ -1183,12 +1194,13 @@ mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 cie_cfi_len = p - cie_cfi; fde_cfi_len = (fde + fde_len - fde_cfi); - buf = (guint8 *)g_malloc0 (cie_cfi_len + fde_cfi_len); - memcpy (buf, cie_cfi, cie_cfi_len); - memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len); + buf = unw_info; + if (buf) { + memcpy (buf, cie_cfi, cie_cfi_len); + memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len); + } res->unw_info_len = cie_cfi_len + fde_cfi_len; - res->unw_info = buf; } /*