diff --git a/CHANGELOG.md b/CHANGELOG.md index ecedd437fc..6eaba53c6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed a bug where negative or oversized segment sizes were not rejected in binary matching - Fixed the `network` mdns configuration to read the documented `host` key; the previously required, undocumented `hostname` key is still accepted +- Fixed `rem` returning wrong results on 32-bit builds when an operand is a big integer with + a 64-bit magnitude, such as `(1 bsl 63) rem 7` ## [0.7.0-alpha.1] - 2026-04-06 diff --git a/src/libAtomVM/bif.c b/src/libAtomVM/bif.c index 42cae38ee8..20849bcaeb 100644 --- a/src/libAtomVM/bif.c +++ b/src/libAtomVM/bif.c @@ -1443,7 +1443,7 @@ static term rem_boxed_helper(Context *ctx, uint32_t fail_label, uint32_t live, t RAISE_ERROR_BIF(fail_label, BADARITH_ATOM); } if (term_is_boxed_integer(arg2)) { - size |= term_boxed_size(arg2); + size = MAX(size, (int) term_boxed_size(arg2)); } else if (UNLIKELY(!term_is_integer(arg2))) { TRACE("error: arg1: 0x%lx, arg2: 0x%lx\n", arg1, arg2); RAISE_ERROR_BIF(fail_label, BADARITH_ATOM); @@ -1466,8 +1466,7 @@ static term rem_boxed_helper(Context *ctx, uint32_t fail_label, uint32_t live, t } #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 - case 2: - case 3: { + case 2: { avm_int64_t val1 = term_maybe_unbox_int64(arg1); avm_int64_t val2 = term_maybe_unbox_int64(arg2); if (UNLIKELY(val2 == 0)) { diff --git a/tests/erlang_tests/bigint.erl b/tests/erlang_tests/bigint.erl index 2a5ab2fba4..431028563b 100644 --- a/tests/erlang_tests/bigint.erl +++ b/tests/erlang_tests/bigint.erl @@ -259,8 +259,27 @@ test_rem() -> ), <<"E3AE0EA63AE33EA79B071316BC9A7F1B">> = erlang:integer_to_binary(Int8 rem Int9, 16), + % operands with a 64-bit magnitude take 3 boxed terms on 32-bit builds and + % must not be mistaken for regular 2-term boxed int64 values + Int10 = erlang:binary_to_integer(?MODULE:id(<<"8000000000000000">>), 16), + Int11 = erlang:binary_to_integer(?MODULE:id(<<"8000000000000005">>), 16), + Int12 = erlang:binary_to_integer(?MODULE:id(<<"-8000000000000001">>), 16), + Int13 = erlang:binary_to_integer(?MODULE:id(<<"FFFFFFFFFFFFFFFF">>), 16), + Int14 = erlang:binary_to_integer(?MODULE:id(<<"7FFFFFFFFFFFFFFF">>), 16), + + 1 = Int10 rem ?MODULE:id(7), + 808 = Int10 rem ?MODULE:id(1000), + 8 = Int10 rem ?MODULE:id(1073741825), + -2 = Int12 rem ?MODULE:id(7), + 5 = ?MODULE:id(5) rem Int13, + 5 = Int13 rem ?MODULE:id(10), + 42 = ?MODULE:id(42) rem Int10, + <<"7FFFFFFFFFFFFFFF">> = erlang:integer_to_binary(Int14 rem Int11, 16), + <<"8000000000000000">> = erlang:integer_to_binary(Int10 rem Int11, 16), + ok = expect_error(badarith, fun() -> Int0 rem ?MODULE:id(0) end), ok = expect_error(badarith, fun() -> Int1 rem ?MODULE:id(0) end), + ok = expect_error(badarith, fun() -> Int10 rem ?MODULE:id(0) end), 0.