From c70ca686fe269db6079a2ca1c7e09cdfc0cfa903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 5 Sep 2016 16:16:23 +0200 Subject: Don't leak old code when loading a modules with an on_load function Normally, calling code:delete/1 before re-loading the code for a module is unnecessary but causes no problem. But there will be be problems if the new code has an on_load function. Code with an on_load function will always be loaded as old code to allowed it to be easily purged if the on_load function would fail. If the on_load function succeeds, the old and current code will be swapped. So in the scenario where code:delete/1 has been called explicitly, there is old code but no current code. Loading code with an on_load function will cause the reference to the old code to be overwritten. That will at best cause a memory leak, and at worst an emulator crash (especially if NIFs are involved). To avoid that situation, we will put the code with the on_load function in a special, third slot in Module. ERL-240 --- erts/emulator/beam/erl_nif.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'erts/emulator/beam/erl_nif.c') diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 559b4017e7..3a547982da 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -3203,18 +3203,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 && -- cgit v1.2.3