From 758d3462ba25cb7d2350a5425b6a9d0a65bf4248 Mon Sep 17 00:00:00 2001 From: Mateusz Wawrzyczek Date: Wed, 1 Jul 2026 15:39:09 +0200 Subject: [PATCH] Avoid system_limit crash on very large BVV gaps add_aux/2 built the "seen" bitmap with `1 bsl (M-N-1)`. When the gap between the entry base N and the incoming dot M is huge (millions), this allocates a multi-megabit bignum and crashes the emulator with {system_limit, ...}. Cap the shift: when the gap exceeds MAX_BSL_BITS, advance the base directly to {M, 0} instead of materialising a giant bitmap. --- src/swc_node.erl | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/swc_node.erl b/src/swc_node.erl index c91c4fd..12d5457 100644 --- a/src/swc_node.erl +++ b/src/swc_node.erl @@ -125,13 +125,22 @@ add(BVV, {Id, Counter}) -> Entry = maps:get(Id, BVV, {0,0}), maps:put(Id, add_aux(Entry, Counter), BVV). +%% Maximum bitmap shift, kept under OTP's bignum system_limit (~4 Mbit). +%% Above this gap we advance the base directly instead of building a giant +%% bitmap, which would crash with {system_limit, ...} on `bsl`. +-define(MAX_BSL_BITS, 3000000). + %% @doc Adds a dot to a BVV entry, returning the normalized entry. -spec add_aux(entry(), counter()) -> entry(). add_aux({N,B}, M) -> case N < M of false -> norm(N, B); - true -> M2 = B bor (1 bsl (M-N-1)), - norm(N, M2) + true -> + Gap = M - N - 1, + case Gap > ?MAX_BSL_BITS of + true -> {M, 0}; + false -> norm(N, B bor (1 bsl Gap)) + end end. %% @doc Merges all entries from the two BVVs. @@ -253,7 +262,8 @@ add_aux_test() -> ?assertEqual( add_aux({5,3}, 4), {7,0} ), ?assertEqual( add_aux({2,5}, 4), {5,0} ), ?assertEqual( add_aux({2,5}, 6), {3,6} ), - ?assertEqual( add_aux({2,4}, 6), {2,12} ). + ?assertEqual( add_aux({2,4}, 6), {2,12} ), + ?assertEqual( add_aux({0,0}, 5000000), {5000000, 0} ). merge_test() -> ?assertEqual( merge( #{"a" => {5,3}} , #{"a" => {2,4}} ), #{"a" => {7,0}} ),