From 635f2dca698bca61c2171979a8129550d7c87241 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Wed, 26 Nov 2025 08:33:50 +0100 Subject: [PATCH] Fix a binary corruption bug occurring with private_append When a binary is small enough to be on heap and private_append is used for binary construction, a new binary is created and it needs to be zero'd if further binary construction instructions only set bits. Fixes #2003 Signed-off-by: Paul Guyot --- src/libAtomVM/term.c | 2 +- tests/erlang_tests/test_bs.erl | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libAtomVM/term.c b/src/libAtomVM/term.c index 29e3a92af..17b32d4cf 100644 --- a/src/libAtomVM/term.c +++ b/src/libAtomVM/term.c @@ -1093,7 +1093,7 @@ term term_reuse_binary(term src, size_t size, Heap *heap, GlobalContext *glb) } // Not a refc binary or it's a const refc binary - create a new one size_t src_size = term_binary_size(src); - term t = term_create_uninitialized_binary(size, heap, glb); + term t = term_create_empty_binary(size, heap, glb); // Copy the source data (up to the smaller of src_size and size) size_t copy_size = src_size < size ? src_size : size; memcpy((void *) term_binary_data(t), (void *) term_binary_data(src), copy_size); diff --git a/tests/erlang_tests/test_bs.erl b/tests/erlang_tests/test_bs.erl index 70c052dc2..8baf0c086 100644 --- a/tests/erlang_tests/test_bs.erl +++ b/tests/erlang_tests/test_bs.erl @@ -63,6 +63,10 @@ start() -> <<1, 2, 3>> = test_bs_private_append(<<1, 2, 3>>), + % Large case sufficient to trigger a valgrind error if reused binary is not zero'd + Expected = make_binary_copy(32, 0, <<>>), + Expected = test_bs_private_append2(id(make_binary_copy(32, 240, <<>>)), <<>>), + nope = test_match_clause(<<"">>), nope = test_match_clause(<<16#FF>>), nope = test_match_clause(<<$n:8>>), @@ -378,6 +382,18 @@ test_bs_append(Bin1, Bin2) -> test_bs_private_append(Bin) -> <<<> || <> <= Bin>>. +% This encodes with private_append and ensures we do this with buffers allocated on the heap +test_bs_private_append2(<>, Acc) when byte_size(Acc) < 16 -> + test_bs_private_append2( + Rest, + <> + ); +test_bs_private_append2(<>, Acc) -> + test_bs_private_append2(Rest, <>); +test_bs_private_append2(<<>>, Acc) -> + Acc. + test_match_clause( <<$n:8, FixedBinaryData:4/binary, Rest/binary>> ) -> @@ -410,6 +426,11 @@ make_binary(Size, Accum) -> Byte = Size rem 256, make_binary(Size - 1, <>). +make_binary_copy(0, _Byte, Acc) -> + Acc; +make_binary_copy(Count, Byte, Acc) -> + make_binary_copy(Count - 1, Byte, <>). + test_put_match_string(Prefix, Suffix) -> Bin = <<$f:8, $o:8, $o:8, Suffix/binary>>, <> = Bin.