Skip to content

Commit ed48c7c

Browse files
committed
Forward port changes from v0.6 release branch
Merge `binary:split/2,3` fix from release-0.6 and few other fixes.
2 parents 087d892 + 0d6a00e commit ed48c7c

File tree

9 files changed

+98
-34
lines changed

9 files changed

+98
-34
lines changed

.github/workflows/build-and-test-on-freebsd.yaml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,17 @@ concurrency:
3434

3535
jobs:
3636
build-and-test-on-freebsd:
37-
runs-on: ubuntu-22.04
37+
runs-on: ubuntu-24.04
3838
name: Build and test AtomVM on FreeBSD
3939
env:
4040
ATOMVM_EXAMPLE: "atomvm-example"
41+
42+
strategy:
43+
fail-fast: false
44+
45+
matrix:
46+
os_release: ["13.4", "14.2"]
47+
4148
steps:
4249

4350
- uses: actions/checkout@v4
@@ -47,17 +54,17 @@ jobs:
4754
uses: vmactions/freebsd-vm@v1
4855
timeout-minutes: 20
4956
with:
50-
release: 13.2
57+
release: ${{ matrix.os_release }}
5158
envs: 'ATOMVM_EXAMPLE'
5259
usesh: true
5360
sync: rsync
5461
copyback: false
5562

5663
prepare: |
57-
pkg install -y curl cmake gperf erlang elixir mbedtls
64+
pkg install -y curl cmake gperf erlang elixir rebar3 mbedtls
5865
5966
run: |
60-
67+
set -e
6168
echo "%%"
6269
echo "%% System Info"
6370
echo "%%"

.github/workflows/esp32-simtest.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ jobs:
5555
runs-on: ubuntu-24.04
5656
if: needs.cli_token.outputs.token_check == 'true'
5757
container: espressif/idf:${{ matrix.idf-version }}
58+
services:
59+
wokwi-ci-server:
60+
image: wokwi/wokwi-ci-server
61+
ports:
62+
- 3000:3000
63+
5864
strategy:
5965
fail-fast: false
6066
# focus on device diversity.
@@ -120,6 +126,10 @@ jobs:
120126
idf.py -DSDKCONFIG_DEFAULTS='sdkconfig.ci.wokwi' set-target ${{matrix.esp-idf-target}}
121127
idf.py build
122128
129+
- name: Configure Wokwi environment
130+
run: |
131+
echo "WOKWI_CLI_SERVER=ws://wokwi-ci-server:3000" >> $GITHUB_ENV
132+
123133
- name: Run ESP32-sim tests using Wokwi CI
124134
working-directory: ./src/platforms/esp32/test/
125135
env:

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ certain VM instructions are used.
5050
- Fixed compilation with latest debian gcc-arm-none-eabi
5151
- Fix `network:stop/0` on ESP32 so the network can be started again
5252
- Fix matching of binaries on unaligned boundaries for code compiled with older versions of OTP
53+
- Fix a memory corruption caused by `binary:split/2,3`
5354

5455
## [0.6.5] - 2024-10-15
5556

src/libAtomVM/nifs.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3181,15 +3181,19 @@ static term nif_binary_split(Context *ctx, int argc, term argv[])
31813181
size_t num_segments = 1;
31823182
const char *temp_bin_data = bin_data;
31833183
int temp_bin_size = bin_size;
3184+
size_t heap_size = 0;
31843185
do {
31853186
const char *found = (const char *) memmem(temp_bin_data, temp_bin_size, pattern_data, pattern_size);
31863187
if (!found) break;
31873188
num_segments++;
3189+
heap_size += CONS_SIZE + term_sub_binary_heap_size(argv[0], found - temp_bin_data);
31883190
int next_search_offset = found - temp_bin_data + pattern_size;
31893191
temp_bin_data += next_search_offset;
31903192
temp_bin_size -= next_search_offset;
31913193
} while (global && temp_bin_size >= pattern_size);
31923194

3195+
heap_size += CONS_SIZE + term_sub_binary_heap_size(argv[0], temp_bin_size);
3196+
31933197
term result_list = term_nil();
31943198

31953199
if (num_segments == 1) {
@@ -3202,7 +3206,7 @@ static term nif_binary_split(Context *ctx, int argc, term argv[])
32023206
}
32033207

32043208
// binary:split/2,3 always return sub binaries, except when copied binaries are as small as sub-binaries.
3205-
if (UNLIKELY(memory_ensure_free_with_roots(ctx, LIST_SIZE(num_segments, TERM_BOXED_SUB_BINARY_SIZE), 2, argv, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
3209+
if (UNLIKELY(memory_ensure_free_with_roots(ctx, heap_size, 2, argv, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
32063210
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
32073211
}
32083212

src/libAtomVM/otp_net.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ static term eai_errno_to_term(int err, GlobalContext *glb)
8686
#ifdef HAVE_EXTENDED_EAI_ERRNO
8787
case EAI_BADHINTS:
8888
return globalcontext_make_atom(glb, ATOM_STR("\xB", "eaibadhints"));
89+
#ifdef HAVE_EAI_OVERFLOW
8990
case EAI_OVERFLOW:
9091
return globalcontext_make_atom(glb, ATOM_STR("\xB", "eaioverflow"));
92+
#endif
9193
case EAI_PROTOCOL:
9294
return globalcontext_make_atom(glb, ATOM_STR("\xB", "eaiprotocol"));
9395
case EAI_SYSTEM:

src/libAtomVM/term.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ static inline term term_from_literal_binary(const void *data, size_t size, Heap
10441044
*/
10451045
static inline size_t term_sub_binary_heap_size(term binary, size_t len)
10461046
{
1047-
if (term_is_refc_binary(binary) && len >= SUB_BINARY_MIN) {
1047+
if ((term_is_refc_binary(binary) || term_is_sub_binary(binary)) && len >= SUB_BINARY_MIN) {
10481048
return TERM_BOXED_SUB_BINARY_SIZE;
10491049
} else {
10501050
return term_binary_heap_size(len);

src/platforms/generic_unix/lib/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ check_symbol_exists(EAI_BADHINTS "netdb.h" HAVE_EXTENDED_EAI_ERRNO)
104104
if (HAVE_EXTENDED_EAI_ERRNO)
105105
target_compile_definitions(libAtomVM${PLATFORM_LIB_SUFFIX} PUBLIC HAVE_EXTENDED_EAI_ERRNO)
106106
endif()
107+
check_symbol_exists(EAI_OVERFLOW "netdb.h" HAVE_EAI_OVERFLOW)
108+
if (HAVE_EAI_OVERFLOW)
109+
target_compile_definitions(libAtomVM${PLATFORM_LIB_SUFFIX} PUBLIC HAVE_EAI_OVERFLOW)
110+
endif()
107111

108112
if (COVERAGE)
109113
include(CodeCoverage)

tests/erlang_tests/test_binary_split.erl

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,63 +20,99 @@
2020

2121
-module(test_binary_split).
2222

23-
-export([start/0, split_compare/3, split_compare/2, compare_bin/2, fail_split/1]).
23+
-export([start/0, split_compare/3, split_compare/2, compare_bin/2, fail_split/1, id/1]).
2424

2525
start() ->
26-
split_compare(<<"Hello:World">>, <<"Hello">>, <<"World">>) +
27-
split_compare(<<"Hello:::World:">>, <<"Hello">>, <<"::World:">>) +
28-
split_compare(<<"Test:">>, <<"Test">>, <<>>) +
29-
split_compare(<<":">>, <<>>, <<>>) +
30-
split_compare(<<>>, <<>>) +
31-
split_compare(<<"Test">>, <<>>) +
32-
split_compare2(<<"Test">>, <<>>) +
33-
split_compare2(<<"helloSEPARATORworld">>, <<"hello">>, <<"world">>) +
34-
fail_split(<<>>) +
35-
fail_split({1, 2}) +
36-
fail_split2({1, 2}).
26+
ok = split_compare(<<"Hello:World">>, <<"Hello">>, <<"World">>),
27+
ok = split_compare(<<"Hello:::World:">>, <<"Hello">>, <<"::World:">>),
28+
ok = split_compare(<<"Test:">>, <<"Test">>, <<>>),
29+
ok = split_compare(<<":">>, <<>>, <<>>),
30+
ok = split_compare(<<>>, <<>>),
31+
ok = split_compare(<<"Test">>, <<>>),
32+
ok = split_compare2(<<"Test">>, <<>>),
33+
ok = split_compare2(<<"helloSEPARATORworld">>, <<"hello">>, <<"world">>),
34+
ok = fail_split(<<>>),
35+
ok = fail_split({1, 2}),
36+
ok = fail_split2({1, 2}),
37+
case erlang:system_info(machine) of
38+
"BEAM" -> ok;
39+
"ATOM" -> ok = memory_allocation_split()
40+
end,
41+
0.
3742

3843
split_compare(Bin, Part1) ->
3944
[A] = binary:split(Bin, <<":">>),
4045
compare_bin(Part1, A).
4146

4247
split_compare(Bin, Part1, Part2) ->
4348
[A, B] = binary:split(Bin, <<":">>),
44-
compare_bin(Part1, A) + compare_bin(B, Part2).
49+
ok = compare_bin(Part1, A),
50+
ok = compare_bin(B, Part2).
4551

4652
split_compare2(Bin, Part1) ->
4753
[A] = binary:split(Bin, <<"SEPARATOR">>),
4854
compare_bin(Part1, A).
4955

5056
split_compare2(Bin, Part1, Part2) ->
5157
[A, B] = binary:split(Bin, <<"SEPARATOR">>),
52-
compare_bin(Part1, A) + compare_bin(B, Part2).
58+
ok = compare_bin(Part1, A),
59+
ok = compare_bin(B, Part2).
5360

5461
compare_bin(Bin1, Bin2) ->
5562
compare_bin(Bin1, Bin2, byte_size(Bin1) - 1).
5663

5764
compare_bin(_Bin1, _Bin2, -1) ->
58-
1;
65+
ok;
5966
compare_bin(Bin1, Bin2, Index) ->
6067
B1 = binary:at(Bin1, Index),
61-
case binary:at(Bin2, Index) of
62-
B1 ->
63-
compare_bin(Bin1, Bin2, Index - 1);
64-
_Any ->
65-
0
66-
end.
68+
B1 = binary:at(Bin2, Index),
69+
compare_bin(Bin1, Bin2, Index - 1).
6770

6871
fail_split(Separator) ->
6972
try binary:split(<<"TESTBIN">>, Separator) of
70-
_Any -> 2000
73+
_Any -> {unexpected, _Any}
7174
catch
72-
error:badarg -> 1;
73-
_:_ -> 4000
75+
error:badarg -> ok;
76+
T:V -> {unexpected, {T, V}}
7477
end.
7578

7679
fail_split2(Bin) ->
7780
try binary:split(Bin, <<"TESTSEPARATOR">>) of
78-
_Any -> 2000
81+
_Any -> {unxpected, _Any}
7982
catch
80-
error:badarg -> 1;
81-
_:_ -> 4000
83+
error:badarg -> ok;
84+
T:V -> {unxpected, {T, V}}
8285
end.
86+
87+
memory_allocation_split() ->
88+
Parent = self(),
89+
Hostname = <<"atomvm">>,
90+
{Pid, MonitorRef} = spawn_opt(
91+
fun() ->
92+
% Carefully designed lists to generate a crash on unix 64 bits
93+
% This binary is 63 bytes long, so it's stored on heap on 64 bits
94+
% binary:split should allocate sufficient bytes as subbinaries
95+
% have to be on heap as well
96+
HeapBin = list_to_binary([
97+
id(Hostname), <<"@atomvms3.object.stream.atomvms3.object.stream.atomvms3.o">>
98+
]),
99+
List1 = binary:split(HeapBin, <<"@">>, [global]),
100+
Parent ! {self(), List1}
101+
end,
102+
[link, monitor, {atomvm_heap_growth, minimum}]
103+
),
104+
ok =
105+
receive
106+
{Pid, List1} ->
107+
2 = length(List1),
108+
ok
109+
after 5000 -> timeout
110+
end,
111+
normal =
112+
receive
113+
{'DOWN', MonitorRef, process, Pid, Reason} -> Reason
114+
after 5000 -> timeout
115+
end,
116+
ok.
117+
118+
id(X) -> X.

tests/test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ struct Test tests[] = {
319319
TEST_CASE(test_unicode),
320320

321321
TEST_CASE_EXPECTED(test_binary_part, 12),
322-
TEST_CASE_EXPECTED(test_binary_split, 16),
322+
TEST_CASE(test_binary_split),
323323

324324
TEST_CASE_COND(plusone, 134217728, LONG_MAX != 9223372036854775807),
325325

0 commit comments

Comments
 (0)