Skip to content

Commit 427dd48

Browse files
authored
Merge pull request atomvm#513 from pguyot/w16/fix-term-to-binary-boxed-ints
Fix issues with term_to_binary with boxed ints
2 parents 19fea87 + 2cabb6d commit 427dd48

File tree

3 files changed

+21
-2
lines changed

3 files changed

+21
-2
lines changed

src/libAtomVM/externalterm.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -621,11 +621,19 @@ static int calculate_heap_usage(const uint8_t *external_term_buf, size_t remaini
621621
}
622622
uint8_t sign = external_term_buf[2];
623623
*eterm_size = SMALL_BIG_EXT_BASE_SIZE + num_bytes;
624-
avm_uint64_t value = read_bytes(external_term_buf + 3, num_bytes);
624+
avm_uint64_t unsigned_value = read_bytes(external_term_buf + 3, num_bytes);
625625
// NB. We currently support max 64-bit signed integers (assuming two's complement signed values in 63 bits)
626-
if (UNLIKELY((sign == 0 && value > INT64_MAX) || (sign != 0 && value > (((avm_uint64_t) INT64_MAX) + 1)))) {
626+
if (UNLIKELY((sign == 0 && unsigned_value > INT64_MAX) || (sign != 0 && unsigned_value > (((avm_uint64_t) INT64_MAX) + 1)))) {
627627
return INVALID_TERM_SIZE;
628628
}
629+
// Compute the size with the sign as -2^27 or -2^59 can be encoded
630+
// on 1 term while 2^27 and 2^59 respectively (32/64 bits) cannot.
631+
avm_int64_t value = 0;
632+
if (sign != 0x00) {
633+
value = -((avm_int64_t) unsigned_value);
634+
} else {
635+
value = (avm_int64_t) unsigned_value;
636+
}
629637
return term_boxed_integer_size(value);
630638
}
631639

src/libAtomVM/term.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,11 @@ static inline term term_make_maybe_boxed_int64(Context *ctx, avm_int64_t value)
832832

833833
static inline size_t term_boxed_integer_size(avm_int64_t value)
834834
{
835+
#if BOXED_TERMS_REQUIRED_FOR_INT64 == 2
836+
if ((value < AVM_INT_MIN) || (value > AVM_INT_MAX)) {
837+
return BOXED_INT64_SIZE;
838+
}
839+
#endif
835840
if ((value < MIN_NOT_BOXED_INT) || (value > MAX_NOT_BOXED_INT)) {
836841
return BOXED_INT_SIZE;
837842
} else {

tests/erlang_tests/small_big_ext.erl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ start() ->
4949
true = test_reverse(-pow(31), <<131, 98, 128, 0, 0, 0>>),
5050
true = test_reverse(-pow(31) - 1, <<131, 110, 4, 1, 1, 0, 0, 128>>),
5151

52+
%% edge cases around boxed integers in 32 bits and 64 bits platforms
53+
true = test_reverse(pow(27) - 1, <<131, 98, 7, 255, 255, 255>>),
54+
true = test_reverse(-pow(27), <<131, 98, 248, 0, 0, 0>>),
55+
true = test_reverse(pow(59) - 1, <<131, 110, 8, 0, 255, 255, 255, 255, 255, 255, 255, 7>>),
56+
true = test_reverse(-pow(59), <<131, 110, 8, 1, 0, 0, 0, 0, 0, 0, 0, 8>>),
57+
5258
%% missing sign
5359
ok = assert_badarg(
5460
fun() ->

0 commit comments

Comments
 (0)