diff options
author | Björn Gustavsson <[email protected]> | 2016-09-15 11:40:39 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2016-09-15 11:40:39 +0200 |
commit | 687eae1e86817403249f03f534a256a28c5d5251 (patch) | |
tree | 75369a6be94deb0e0c0ad2287102dbb16c34b026 /erts/emulator/beam | |
parent | 060949fb1ee7d1af366372b43dde5add421a5f73 (diff) | |
parent | fde238fb52133a6c7a2a3f2a2e16f1c1bef62394 (diff) | |
download | otp-687eae1e86817403249f03f534a256a28c5d5251.tar.gz otp-687eae1e86817403249f03f534a256a28c5d5251.tar.bz2 otp-687eae1e86817403249f03f534a256a28c5d5251.zip |
Merge branch 'maint'
* maint:
erts: Add nif_SUITE:t_on_load
erts: Improve nif_SUITE:upgrade test
Don't leak old code when loading a modules with an on_load function
Conflicts:
erts/preloaded/ebin/erts_code_purger.beam
erts/preloaded/ebin/erts_internal.beam
erts/preloaded/src/erts_code_purger.erl
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r-- | erts/emulator/beam/atom.names | 1 | ||||
-rw-r--r-- | erts/emulator/beam/beam_bif_load.c | 62 | ||||
-rw-r--r-- | erts/emulator/beam/beam_load.c | 15 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif.c | 18 | ||||
-rw-r--r-- | erts/emulator/beam/module.c | 3 | ||||
-rw-r--r-- | erts/emulator/beam/module.h | 1 |
6 files changed, 76 insertions, 24 deletions
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 437cbddde7..66af05c1f2 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -507,6 +507,7 @@ atom port_limit atom port_op atom positive atom prepare +atom prepare_on_load atom print atom priority atom private diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index c7e13f276d..153fa205ed 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -53,6 +53,7 @@ static struct { ErlFunEntry *def_funs[10]; Uint fe_size; Uint fe_ix; + struct erl_module_instance saved_old; } purge_state; Process *erts_code_purger = NULL; @@ -103,6 +104,8 @@ init_purge_state(void) purge_state.fe_size = sizeof(purge_state.def_funs); purge_state.fe_size /= sizeof(purge_state.def_funs[0]); purge_state.fe_ix = 0; + + purge_state.saved_old.code_hdr = 0; } void @@ -727,10 +730,13 @@ BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1) { Module* modp = erts_get_module(BIF_ARG_1, erts_active_code_ix()); - if (modp && modp->old.code_hdr) { - BIF_TRAP_CODE_PTR_0(BIF_P, modp->old.code_hdr->on_load_function_ptr); + if (!modp || !modp->on_load) { + BIF_ERROR(BIF_P, BADARG); } - else { + if (modp->on_load->code_hdr) { + BIF_TRAP_CODE_PTR_0(BIF_P, + modp->on_load->code_hdr->on_load_function_ptr); + } else { BIF_ERROR(BIF_P, BADARG); } } @@ -753,14 +759,14 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) code_ix = erts_active_code_ix(); modp = erts_get_module(BIF_ARG_1, code_ix); - if (!modp || !modp->old.code_hdr) { + if (!modp || !modp->on_load || !modp->on_load->code_hdr) { error: erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_release_code_write_permission(); BIF_ERROR(BIF_P, BADARG); } - if (modp->old.code_hdr->on_load_function_ptr == NULL) { + if (modp->on_load->code_hdr->on_load_function_ptr == NULL) { goto error; } if (BIF_ARG_2 != am_false && BIF_ARG_2 != am_true) { @@ -769,14 +775,17 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) if (BIF_ARG_2 == am_true) { int i; - struct erl_module_instance t; /* - * Swap old and new code. + * Make the code with the on_load function current. */ - t = modp->curr; - modp->curr = modp->old; - modp->old = t; + + if (modp->curr.code_hdr) { + modp->old = modp->curr; + } + modp->curr = *modp->on_load; + erts_free(ERTS_ALC_T_PREPARED_CODE, modp->on_load); + modp->on_load = 0; /* * The on_load function succeded. Fix up export entries. @@ -1444,7 +1453,8 @@ BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2) switch (BIF_ARG_2) { - case am_prepare: { + case am_prepare: + case am_prepare_on_load: { /* * Prepare for purge by marking all fun * entries referring to the code to purge @@ -1469,7 +1479,22 @@ BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2) /* * Any code to purge? */ - erts_rlock_old_code(code_ix); + + if (BIF_ARG_2 == am_prepare_on_load) { + erts_rwlock_old_code(code_ix); + } else { + erts_rlock_old_code(code_ix); + } + + if (BIF_ARG_2 == am_prepare_on_load) { + ASSERT(modp->on_load); + ASSERT(modp->on_load->code_hdr); + purge_state.saved_old = modp->old; + modp->old = *modp->on_load; + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) modp->on_load); + modp->on_load = 0; + } + if (!modp->old.code_hdr) res = am_false; else { @@ -1483,7 +1508,12 @@ BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2) end = (BeamInstr *)((char *)code + modp->old.code_length); erts_fun_purge_prepare(code, end); } - erts_runlock_old_code(code_ix); + + if (BIF_ARG_2 == am_prepare_on_load) { + erts_rwunlock_old_code(code_ix); + } else { + erts_runlock_old_code(code_ix); + } } #ifndef ERTS_SMP @@ -1616,8 +1646,14 @@ BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2) modp->old.code_length = 0; modp->old.catches = BEAM_CATCHES_NIL; erts_remove_from_ranges(code); + ERTS_BIF_PREP_RET(ret, am_true); } + + if (purge_state.saved_old.code_hdr) { + modp->old = purge_state.saved_old; + purge_state.saved_old.code_hdr = 0; + } erts_rwunlock_old_code(code_ix); } if (is_blocking) { diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index d1f9e6c91c..d69b18e22f 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -833,11 +833,20 @@ erts_finish_loading(Binary* magic, Process* c_p, size = stp->loaded_size; erts_total_code_size += size; - if (stp->on_load) { - inst_p = &mod_tab_p->old; - } else { + + if (!stp->on_load) { inst_p = &mod_tab_p->curr; + } else { + mod_tab_p->on_load = + (struct erl_module_instance *) + erts_alloc(ERTS_ALC_T_PREPARED_CODE, + sizeof(struct erl_module_instance)); + inst_p = mod_tab_p->on_load; + inst_p->nif = 0; + inst_p->num_breakpoints = 0; + inst_p->num_traced_exports = 0; } + inst_p->code_hdr = stp->hdr; inst_p->code_length = size; diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 14a1207f61..b53d3d4c19 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -3206,18 +3206,20 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) if (init_func != NULL) handle = init_func; + this_mi = &module_p->curr; + prev_mi = &module_p->old; if (in_area(caller, module_p->old.code_hdr, module_p->old.code_length)) { - if (module_p->old.code_hdr->on_load_function_ptr) { - this_mi = &module_p->old; + ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old " + "module '%T' not allowed", mod_atom); + goto error; + } else if (module_p->on_load) { + ASSERT(module_p->on_load->code_hdr->on_load_function_ptr); + if (module_p->curr.code_hdr) { prev_mi = &module_p->curr; } else { - ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old " - "module '%T' not allowed", mod_atom); - goto error; + prev_mi = &module_p->old; } - } else { - this_mi = &module_p->curr; - prev_mi = &module_p->old; + this_mi = module_p->on_load; } if (init_func == NULL && diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index 3eb11f1693..4f36377450 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -85,6 +85,7 @@ static Module* module_alloc(Module* tmpl) obj->old.num_breakpoints = 0; obj->curr.num_traced_exports = 0; obj->old.num_traced_exports = 0; + obj->on_load = 0; return obj; } @@ -201,6 +202,7 @@ void module_start_staging(void) dst_mod->curr = src_mod->curr; dst_mod->old = src_mod->old; + dst_mod->on_load = src_mod->on_load; } /* @@ -214,6 +216,7 @@ void module_start_staging(void) dst_mod->curr = src_mod->curr; dst_mod->old = src_mod->old; + dst_mod->on_load = src_mod->on_load; } newsz = index_table_sz(dst); erts_smp_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 5a60bc90d9..1c1afc8461 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -39,6 +39,7 @@ typedef struct erl_module { struct erl_module_instance curr; struct erl_module_instance old; /* protected by "old_code" rwlock */ + struct erl_module_instance* on_load; } Module; Module* erts_get_module(Eterm mod, ErtsCodeIndex code_ix); |