From cdd8e9ca6a947f8cc5c8a565f951a1fe99f92aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 25 Jun 2024 17:07:19 +0200 Subject: [PATCH 1/3] Handle funs when loading was aborted In the cleaning up of the off-heap list, don't crash when the pointer to a fun entry is NULL. That can happen if loading failed for some reason (the BEAM file was corrupted or too old). --- erts/emulator/beam/erl_message.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 6319cf7ee136..ba04d623530d 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -171,7 +171,10 @@ erts_cleanup_offheap_list(struct erl_off_heap_header* first) erts_bin_release(u.br->val); break; case FUN_REF_SUBTAG: - if (erts_refc_dectest(&(u.fref->entry)->refc, 0) == 0) { + /* The pointer to the fun entry can be NULL if loading + * was aborted because of an invalid BEAM file. */ + if (u.fref->entry && + erts_refc_dectest(&(u.fref->entry)->refc, 0) == 0) { erts_erase_fun_entry(u.fref->entry); } break; From 359f49c777d0ca3fac7c7dabd80efbdf749e493c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 25 Jun 2024 17:15:07 +0200 Subject: [PATCH 2/3] Handle obsolete instructions with more than 6 operands Attempting to load an obsolete instruction with more than 6 operands could crash the runtime system. --- erts/emulator/beam/beam_load.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index af2747a77e2d..289b5c5aab24 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -492,16 +492,28 @@ static int load_code(LoaderState* stp) * Use bit masks to quickly find the most specific of the * the possible specific instructions associated with this * specific instruction. + * + * Note that currently only instructions having no more + * than 6 operands are supported. */ int specific, arity, arg, i; Uint32 mask[3] = {0, 0, 0}; - arity = gen_opc[tmp_op->op].arity; + if (num_specific != 0) { + /* The `bs_append` instruction made obsolete in + * Erlang/OTP 28 has 8 operands. Therefore, the if + * statement preventing the loop that follows to be + * entered is necessary to prevent writing beyond the + * last entry of the mask array. */ + arity = gen_opc[tmp_op->op].arity; - for (arg = 0; arg < arity; arg++) { - int type = tmp_op->a[arg].type; + ASSERT(2 * (sizeof(mask) / sizeof(mask[0])) >= arity); - mask[arg / 2] |= (1u << type) << ((arg % 2) << 4); + for (arg = 0; arg < arity; arg++) { + int type = tmp_op->a[arg].type; + + mask[arg / 2] |= (1u << type) << ((arg % 2) << 4); + } } specific = gen_opc[tmp_op->op].specific; From 7ebe7f491d8f9bdf82c36ab5bd16a2aaee28d5ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 25 Jun 2024 17:35:37 +0200 Subject: [PATCH 3/3] Correct the test for obsolete instructions When attempting to load obsolete instructions, the loading failed to recognize them and produced an unhelpful message instead of a polite request to recompile the module. This bug was introduced in 4dbc9988e7f764. --- erts/emulator/beam/beam_load.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 289b5c5aab24..7bc6a04874a6 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -579,7 +579,7 @@ static int load_code(LoaderState* stp) * No specific operations and no transformations means that * the instruction is obsolete. */ - if (num_specific == 0 && gen_opc[tmp_op->op].transform == -1) { + if (num_specific == 0 && gen_opc[tmp_op->op].transform == 0) { BeamLoadError0(stp, PLEASE_RECOMPILE); }