Skip to content

Commit 7dfcc87

Browse files
committed
opcodesswitch: fix BIF error handling in CALL_EXT (and similar)
BIF return value wasn't checked for errors, so there was a chance that invalid terms might appear around. As of v0.6.x was very unlikely since this required an out of memory with `min` and `max` functions. Signed-off-by: Davide Bettio <davide@uninstall.it>
1 parent b257211 commit 7dfcc87

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ certain VM instructions are used.
3333
- Fixed compilation with latest debian gcc-arm-none-eabi
3434
- Fix `network:stop/0` on ESP32 so the network can be started again
3535
- Fix a memory corruption caused by `binary:split/2,3`
36+
- Fix error handling when calling `min` and `max` with code compiled before OTP-26: there was a
37+
bug when handling errors from BIFs used as NIFs (when called with `CALL_EXT` and similar opcodes)`
3638

3739
## [0.6.5] - 2024-10-15
3840

src/libAtomVM/opcodesswitch.h

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,19 +1990,23 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
19901990
// Support compilers < OTP26 that generate CALL_EXT
19911991
// for min/2 and max/2
19921992
const struct Bif *bif = EXPORTED_FUNCTION_TO_BIF(func);
1993+
term return_value;
19931994
switch (arity) {
19941995
case 0:
1995-
x_regs[0] = bif->bif0_ptr(ctx);
1996+
return_value = bif->bif0_ptr(ctx);
19961997
break;
19971998
case 1:
1998-
x_regs[0] = bif->bif1_ptr(ctx, 0, x_regs[0]);
1999+
return_value = bif->bif1_ptr(ctx, 0, x_regs[0]);
19992000
break;
20002001
case 2:
2001-
x_regs[0] = bif->bif2_ptr(ctx, 0, x_regs[0], x_regs[1]);
2002+
return_value = bif->bif2_ptr(ctx, 0, x_regs[0], x_regs[1]);
20022003
break;
20032004
default:
20042005
fprintf(stderr, "Invalid arity %" PRIu32 " for bif\n", arity);
2006+
AVM_ABORT();
20052007
}
2008+
PROCESS_MAYBE_TRAP_RETURN_VALUE_RESTORE_PC(return_value, orig_pc);
2009+
x_regs[0] = return_value;
20062010

20072011
break;
20082012
}
@@ -2090,19 +2094,23 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
20902094
ctx->e += (n_words + 1);
20912095

20922096
const struct Bif *bif = EXPORTED_FUNCTION_TO_BIF(func);
2097+
term return_value;
20932098
switch (arity) {
20942099
case 0:
2095-
x_regs[0] = bif->bif0_ptr(ctx);
2100+
return_value = bif->bif0_ptr(ctx);
20962101
break;
20972102
case 1:
2098-
x_regs[0] = bif->bif1_ptr(ctx, 0, x_regs[0]);
2103+
return_value = bif->bif1_ptr(ctx, 0, x_regs[0]);
20992104
break;
21002105
case 2:
2101-
x_regs[0] = bif->bif2_ptr(ctx, 0, x_regs[0], x_regs[1]);
2106+
return_value = bif->bif2_ptr(ctx, 0, x_regs[0], x_regs[1]);
21022107
break;
21032108
default:
21042109
fprintf(stderr, "Invalid arity %" PRIu32 " for bif\n", arity);
2110+
AVM_ABORT();
21052111
}
2112+
PROCESS_MAYBE_TRAP_RETURN_VALUE_LAST(return_value);
2113+
x_regs[0] = return_value;
21062114

21072115
DO_RETURN();
21082116

@@ -3535,19 +3543,23 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
35353543
// Support compilers < OTP26 that generate CALL_EXT_ONLY
35363544
// for min/2 and max/2
35373545
const struct Bif *bif = EXPORTED_FUNCTION_TO_BIF(func);
3546+
term return_value;
35383547
switch (arity) {
35393548
case 0:
3540-
x_regs[0] = bif->bif0_ptr(ctx);
3549+
return_value = bif->bif0_ptr(ctx);
35413550
break;
35423551
case 1:
3543-
x_regs[0] = bif->bif1_ptr(ctx, 0, x_regs[0]);
3552+
return_value = bif->bif1_ptr(ctx, 0, x_regs[0]);
35443553
break;
35453554
case 2:
3546-
x_regs[0] = bif->bif2_ptr(ctx, 0, x_regs[0], x_regs[1]);
3555+
return_value = bif->bif2_ptr(ctx, 0, x_regs[0], x_regs[1]);
35473556
break;
35483557
default:
35493558
fprintf(stderr, "Invalid arity %" PRIu32 " for bif\n", arity);
3559+
AVM_ABORT();
35503560
}
3561+
PROCESS_MAYBE_TRAP_RETURN_VALUE_LAST(return_value);
3562+
x_regs[0] = return_value;
35513563

35523564
DO_RETURN();
35533565

0 commit comments

Comments
 (0)