From 439fe7b93743528782fbe1ff00dc65d08cb25a56 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 16 Aug 2012 15:51:01 +0200 Subject: Fix init:restart with hipelibs This is a workaround for init:restart. The root problem is that delete/purge_module does not clean up internal hipe bookkeeping (hipe_mfa_info's) properly. Symptom: Execution of deallocated beam code. --- erts/emulator/hipe/hipe_bif0.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'erts/emulator/hipe/hipe_bif0.c') diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index af593229c0..23ced284bf 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -1755,6 +1755,41 @@ BIF_RETTYPE hipe_bifs_mark_referred_from_1(BIF_ALIST_1) /* get_refs_from */ BIF_RET(NIL); } +/* Called by init:restart after unloading all hipe compiled modules + * to work around bug causing execution of deallocated beam code. + * Can be removed when delete/purge of native modules works better. + * Test: Do init:restart in debug compiled vm with hipe compiled kernel. + */ +static void hipe_purge_all_refs(void) +{ + struct hipe_mfa_info **bucket; + unsigned int i, nrbuckets; + + hipe_mfa_info_table_lock(); + + bucket = hipe_mfa_info_table.bucket; + nrbuckets = 1 << hipe_mfa_info_table.log2size; + for (i = 0; i < nrbuckets; ++i) { + while (bucket[i] != NULL) { + struct hipe_mfa_info* mfa = bucket[i]; + bucket[i] = mfa->bucket.next; + + while (mfa->refers_to) { + struct hipe_mfa_info_list *to = mfa->refers_to; + mfa->refers_to = to->next; + erts_free(ERTS_ALC_T_HIPE, to); + } + while (mfa->referred_from) { + struct ref* from = mfa->referred_from; + mfa->referred_from = from->next; + erts_free(ERTS_ALC_T_HIPE, from); + } + erts_free(ERTS_ALC_T_HIPE, mfa); + } + } + hipe_mfa_info_table_unlock(); +} + BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) { struct mfa mfa; @@ -1762,6 +1797,11 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) struct hipe_mfa_info_list *refers_to, *tmp_refers_to; struct ref **prev, *ref; + if (BIF_ARG_1 == am_all) { + hipe_purge_all_refs(); + BIF_RET(NIL); + } + if (!term_to_mfa(BIF_ARG_1, &mfa)) BIF_ERROR(BIF_P, BADARG); hipe_mfa_info_table_lock(); @@ -1799,6 +1839,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) BIF_RET(NIL); } + /* redirect_referred_from(CalleeMFA) * Redirect all pending-redirect refs in CalleeMFA's referred_from. * Then remove any pending-redirect && pending-remove refs from CalleeMFA's referred_from. -- cgit v1.2.3