1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(binary_SUITE). 22 23%% Tests binaries and the BIFs: 24%% list_to_binary/1 25%% iolist_to_binary/1 26%% list_to_bitstring/1 27%% binary_to_list/1 28%% binary_to_list/3 29%% binary_to_term/1 30%% binary_to_term/2 31%% bitstring_to_list/1 32%% term_to_binary/1 33%% erlang:external_size/1 34%% size(Binary) 35%% iolist_size/1 36%% split_binary/2 37%% hash(Binary, N) 38%% phash(Binary, N) 39%% phash2(Binary, N) 40%% 41 42-include_lib("common_test/include/ct.hrl"). 43-include_lib("common_test/include/ct_event.hrl"). 44 45-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 46 init_per_group/2,end_per_group/2, 47 init_per_testcase/2, end_per_testcase/2, 48 copy_terms/1, conversions/1, deep_lists/1, deep_bitstr_lists/1, 49 bad_list_to_binary/1, bad_binary_to_list/1, 50 t_split_binary/1, bad_split/1, 51 terms/1, terms_float/1, float_middle_endian/1, 52 b2t_used_big/1, t2b_deterministic/1, 53 external_size/1, t_iolist_size/1, 54 t_iolist_size_huge_list/1, 55 t_iolist_size_huge_bad_arg_list/1, 56 t_iolist_size_shallow_trapping/1, 57 t_iolist_size_shallow_short_lists/1, 58 t_iolist_size_shallow_tiny_lists/1, 59 t_iolist_size_deep_trapping/1, 60 t_iolist_size_deep_short_lists/1, 61 t_iolist_size_deep_tiny_lists/1, 62 t_hash/1, 63 sub_bin_copy/1, 64 bad_size/1, 65 bad_term_to_binary/1, 66 bad_binary_to_term_2/1,safe_binary_to_term2/1, 67 bad_binary_to_term/1, bad_terms/1, more_bad_terms/1, 68 otp_5484/1,otp_5933/1, 69 ordering/1,unaligned_order/1,gc_test/1, 70 bit_sized_binary_sizes/1, 71 otp_6817/1,deep/1, 72 term2bin_tuple_fallbacks/1, 73 robustness/1,otp_8117/1, 74 otp_8180/1, trapping/1, large/1, 75 error_after_yield/1, cmp_old_impl/1, 76 t2b_system_limit/1, 77 term_to_iovec/1]). 78 79%% Internal exports. 80-export([sleeper/0,trapping_loop/4]). 81 82suite() -> [{ct_hooks,[ts_install_cth]}, 83 {timetrap,{minutes,4}}]. 84 85all() -> 86 [copy_terms, conversions, deep_lists, deep_bitstr_lists, 87 t_split_binary, bad_split, 88 bad_list_to_binary, bad_binary_to_list, terms, 89 terms_float, float_middle_endian, external_size, t_iolist_size, 90 t_iolist_size_huge_list, 91 t_iolist_size_huge_bad_arg_list, 92 {group, iolist_size_benchmarks}, 93 b2t_used_big, t2b_deterministic, 94 bad_binary_to_term_2, safe_binary_to_term2, 95 bad_binary_to_term, bad_terms, t_hash, bad_size, 96 sub_bin_copy, bad_term_to_binary, t2b_system_limit, 97 term_to_iovec, more_bad_terms, 98 otp_5484, otp_5933, 99 ordering, unaligned_order, gc_test, 100 bit_sized_binary_sizes, otp_6817, otp_8117, deep, 101 term2bin_tuple_fallbacks, 102 robustness, otp_8180, trapping, large, 103 error_after_yield, cmp_old_impl]. 104 105groups() -> 106 [ 107 { 108 iolist_size_benchmarks, 109 [], 110 [t_iolist_size_shallow_trapping, 111 t_iolist_size_shallow_short_lists, 112 t_iolist_size_shallow_tiny_lists, 113 t_iolist_size_deep_trapping, 114 t_iolist_size_deep_short_lists, 115 t_iolist_size_deep_tiny_lists 116 ] 117 } 118 ]. 119 120init_per_suite(Config) -> 121 A0 = case application:start(sasl) of 122 ok -> [sasl]; 123 _ -> [] 124 end, 125 A = case application:start(os_mon) of 126 ok -> [os_mon|A0]; 127 _ -> A0 128 end, 129 [{started_apps, A}|Config]. 130 131end_per_suite(Config) -> 132 As = proplists:get_value(started_apps, Config), 133 lists:foreach(fun (A) -> application:stop(A) end, As), 134 Config. 135 136 137init_per_group(_GroupName, Config) -> 138 Config. 139 140end_per_group(_GroupName, Config) -> 141 Config. 142 143init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 144 Config. 145 146end_per_testcase(_Func, _Config) -> 147 ok. 148 149-define(heap_binary_size, 64). 150 151copy_terms(Config) when is_list(Config) -> 152 Self = self(), 153 Pid = spawn_link(fun() -> copy_server(Self) end), 154 F = fun(Term) -> 155 Pid ! Term, 156 receive 157 Term -> ok; 158 Other -> 159 io:format("Sent: ~P\nGot back:~P", [Term,12,Other,12]), 160 ct:fail(bad_term) 161 end 162 end, 163 test_terms(F), 164 ok. 165 166copy_server(Parent) -> 167 receive 168 Term -> 169 Parent ! Term, 170 copy_server(Parent) 171 end. 172 173%% Tests list_to_binary/1, binary_to_list/1 and size/1, 174%% using flat lists. 175 176conversions(Config) when is_list(Config) -> 177 test_bin([]), 178 test_bin([1]), 179 test_bin([1, 2]), 180 test_bin([1, 2, 3]), 181 test_bin(lists:seq(0, ?heap_binary_size)), 182 test_bin(lists:seq(0, ?heap_binary_size+1)), 183 test_bin(lists:seq(0, 255)), 184 test_bin(lists:duplicate(50000, $@)), 185 186 %% Binary in list. 187 List = [1,2,3,4,5], 188 B1 = make_sub_binary(list_to_binary(List)), 189 5 = size(B1), 190 5 = size(make_unaligned_sub_binary(B1)), 191 40 = bit_size(B1), 192 40 = bit_size(make_unaligned_sub_binary(B1)), 193 B2 = list_to_binary([42,B1,19]), 194 B2 = list_to_binary([42,make_unaligned_sub_binary(B1),19]), 195 B2 = iolist_to_binary(B2), 196 B2 = iolist_to_binary(make_unaligned_sub_binary(B2)), 197 7 = size(B2), 198 7 = size(make_sub_binary(B2)), 199 56 = bit_size(B2), 200 56 = bit_size(make_sub_binary(B2)), 201 [42,1,2,3,4,5,19] = binary_to_list(B2), 202 [42,1,2,3,4,5,19] = binary_to_list(make_sub_binary(B2)), 203 [42,1,2,3,4,5,19] = binary_to_list(make_unaligned_sub_binary(B2)), 204 [42,1,2,3,4,5,19] = bitstring_to_list(B2), 205 [42,1,2,3,4,5,19] = bitstring_to_list(make_sub_binary(B2)), 206 [42,1,2,3,4,5,19] = bitstring_to_list(make_unaligned_sub_binary(B2)), 207 208 ok. 209 210test_bin(List) -> 211 Size = length(List), 212 Bin = list_to_binary(List), 213 Bin = iolist_to_binary(List), 214 Bin = list_to_bitstring(List), 215 Size = iolist_size(List), 216 Size = iolist_size(Bin), 217 Size = iolist_size(make_unaligned_sub_binary(Bin)), 218 Size = size(Bin), 219 Size = size(make_sub_binary(Bin)), 220 Size = size(make_unaligned_sub_binary(Bin)), 221 List = binary_to_list(Bin), 222 List = binary_to_list(make_sub_binary(Bin)), 223 List = binary_to_list(make_unaligned_sub_binary(Bin)), 224 List = bitstring_to_list(Bin), 225 List = bitstring_to_list(make_unaligned_sub_binary(Bin)). 226 227%% Tests list_to_binary/1, iolist_to_binary/1, list_to_bitstr/1, binary_to_list/1,3, 228%% bitstr_to_list/1, and size/1, using deep lists. 229 230deep_lists(Config) when is_list(Config) -> 231 test_deep_list(["abc"]), 232 test_deep_list([[12,13,[123,15]]]), 233 test_deep_list([[12,13,[lists:seq(0, 255), []]]]), 234 ok. 235 236test_deep_list(List) -> 237 FlatList = lists:flatten(List), 238 Size = length(FlatList), 239 Bin = list_to_binary(List), 240 Bin = iolist_to_binary(List), 241 Bin = iolist_to_binary(Bin), 242 Bin = list_to_bitstring(List), 243 Size = size(Bin), 244 Size = iolist_size(List), 245 Size = iolist_size(FlatList), 246 Size = iolist_size(Bin), 247 Bitsize = bit_size(Bin), 248 Bitsize = 8*Size, 249 FlatList = binary_to_list(Bin), 250 FlatList = bitstring_to_list(Bin), 251 io:format("testing plain binary..."), 252 t_binary_to_list_3(FlatList, Bin, 1, Size), 253 io:format("testing unaligned sub binary..."), 254 t_binary_to_list_3(FlatList, make_unaligned_sub_binary(Bin), 1, Size). 255 256t_binary_to_list_3(List, Bin, From, To) -> 257 going_up(List, Bin, From, To), 258 going_down(List, Bin, From, To), 259 going_center(List, Bin, From, To). 260 261going_up(List, Bin, From, To) when From =< To -> 262 List = binary_to_list(Bin, From, To), 263 going_up(tl(List), Bin, From+1, To); 264going_up(_List, _Bin, From, To) when From > To -> 265 ok. 266 267going_down(List, Bin, From, To) when To > 0-> 268 compare(List, binary_to_list(Bin, From, To), To-From+1), 269 going_down(List, Bin, From, To-1); 270going_down(_List, _Bin, _From, _To) -> 271 ok. 272 273going_center(List, Bin, From, To) when From >= To -> 274 compare(List, binary_to_list(Bin, From, To), To-From+1), 275 going_center(tl(List), Bin, From+1, To-1); 276going_center(_List, _Bin, _From, _To) -> 277 ok. 278 279compare([X|Rest1], [X|Rest2], Left) when Left > 0 -> 280 compare(Rest1, Rest2, Left-1); 281compare([_X|_], [_Y|_], _Left) -> 282 ct:fail("compare fail"); 283compare(_List, [], 0) -> 284 ok. 285 286deep_bitstr_lists(Config) when is_list(Config) -> 287 {<<7:3>>,[<<7:3>>]} = test_deep_bitstr([<<7:3>>]), 288 {<<42,5:3>>=Bin,[42,<<5:3>>]=List} = test_deep_bitstr([42,<<5:3>>]), 289 {Bin,List} = test_deep_bitstr([42|<<5:3>>]), 290 {Bin,List} = test_deep_bitstr([<<42,5:3>>]), 291 {Bin,List} = test_deep_bitstr([<<1:3>>,<<10:5>>|<<5:3>>]), 292 {Bin,List} = test_deep_bitstr([<<1:3>>,<<10:5>>,<<5:3>>]), 293 {Bin,List} = test_deep_bitstr([[<<1:3>>,<<10:5>>],[],<<5:3>>]), 294 {Bin,List} = test_deep_bitstr([[[<<1:3>>]|<<10:5>>],[],<<5:3>>]), 295 {Bin,List} = test_deep_bitstr([[<<0:1>>,<<0:1>>,[],<<1:1>>,<<10:5>>], 296 <<1:1>>,<<0:1>>,<<1:1>>]), 297 ok. 298 299test_deep_bitstr(List) -> 300 %%{'EXIT',{badarg,_}} = list_to_binary(List), 301 Bin = list_to_bitstring(List), 302 {Bin,bitstring_to_list(Bin)}. 303 304bad_list_to_binary(Config) when is_list(Config) -> 305 test_bad_bin(<<1:1>>), 306 test_bad_bin(atom), 307 test_bad_bin(42), 308 test_bad_bin([1|2]), 309 test_bad_bin([256]), 310 test_bad_bin([255, [256]]), 311 test_bad_bin([-1]), 312 test_bad_bin([atom_in_list]), 313 test_bad_bin([[<<8>>]|bad_tail]), 314 315 {'EXIT',{badarg,_}} = (catch list_to_binary(id(<<1,2,3>>))), 316 {'EXIT',{badarg,_}} = (catch list_to_binary(id([<<42:7>>]))), 317 {'EXIT',{badarg,_}} = (catch list_to_bitstring(id(<<1,2,3>>))), 318 319 %% Funs used to be implemented as a type of binary internally. 320 test_bad_bin(fun(X, Y) -> X*Y end), 321 test_bad_bin([1,fun(X) -> X + 1 end,2|fun() -> 0 end]), 322 test_bad_bin([fun(X) -> X + 1 end]), 323 324 %% Test iolists that do not fit in the address space. 325 %% Unfortunately, it would be too slow to test in a 64-bit emulator. 326 case erlang:system_info(wordsize) of 327 4 -> huge_iolists(); 328 _ -> ok 329 end. 330 331huge_iolists() -> 332 FourGigs = 1 bsl 32, 333 Sizes = [FourGigs+N || N <- lists:seq(0, 64)] ++ 334 [1 bsl N || N <- lists:seq(33, 37)], 335 Base = <<0:(1 bsl 20)/unit:8>>, 336 [begin 337 L = build_iolist(Sz, Base), 338 {'EXIT',{system_limit,_}} = (catch list_to_binary([L])), 339 {'EXIT',{system_limit,_}} = (catch list_to_bitstring([L])), 340 {'EXIT',{system_limit,_}} = (catch binary:list_to_bin([L])), 341 {'EXIT',{system_limit,_}} = (catch iolist_to_binary(L)) 342 end || Sz <- Sizes], 343 ok. 344 345test_bad_bin(List) -> 346 {'EXIT',{badarg,_}} = (catch list_to_binary(List)), 347 {'EXIT',{badarg,_}} = (catch iolist_to_binary(List)), 348 {'EXIT',{badarg,_}} = (catch list_to_bitstring(List)), 349 {'EXIT',{badarg,_}} = (catch iolist_size(List)). 350 351%% Tries binary_to_list/1,3 with bad arguments. 352bad_binary_to_list(Config) when is_list(Config) -> 353 bad_bin_to_list(fun(X) -> X * 42 end), 354 355 GoodBin = list_to_binary(lists:seq(1, 10)), 356 bad_bin_to_list(fun(X) -> X * 44 end, 1, 2), 357 bad_bin_to_list(GoodBin, 0, 1), 358 bad_bin_to_list(GoodBin, 2, 1), 359 bad_bin_to_list(GoodBin, 11, 11), 360 {'EXIT',{badarg,_}} = (catch binary_to_list(id(<<42:7>>))), 361 ok. 362 363bad_bin_to_list(BadBin) -> 364 {'EXIT',{badarg,_}} = (catch binary_to_list(BadBin)), 365 {'EXIT',{badarg,_}} = (catch bitstring_to_list(BadBin)). 366 367bad_bin_to_list(Bin, First, Last) -> 368 {'EXIT',{badarg,_}} = (catch binary_to_list(Bin, First, Last)). 369 370 371%% Tries to split a binary at all possible positions. 372 373t_split_binary(Config) when is_list(Config) -> 374 L = lists:seq(0, ?heap_binary_size-5), %Heap binary. 375 B = list_to_binary(L), 376 split(L, B, size(B)), 377 378 %% Sub binary of heap binary. 379 split(L, make_sub_binary(B), size(B)), 380 {X,Y} = split_binary(B, size(B) div 2), 381 split(binary_to_list(X), X, size(X)), 382 383 %% Unaligned sub binary of heap binary. 384 split(L, make_unaligned_sub_binary(B), size(B)), 385 {X,Y} = split_binary(B, size(B) div 2), 386 split(binary_to_list(X), X, size(X)), 387 388 %% Reference-counted binary. 389 L2 = lists:seq(0, ?heap_binary_size+1), 390 B2 = list_to_binary(L2), 391 split(L2, B2, size(B2)), 392 393 %% Sub binary of reference-counted binary. 394 split(L2, make_sub_binary(B2), size(B2)), 395 {X2,Y2} = split_binary(B2, size(B2) div 2), 396 split(binary_to_list(X2), X2, size(X2)), 397 398 %% Unaligned sub binary of reference-counted binary. 399 split(L2, make_unaligned_sub_binary(B2), size(B2)), 400 {X2,Y2} = split_binary(B2, size(B2) div 2), 401 split(binary_to_list(X2), X2, size(X2)), 402 403 ok. 404 405split(L, B, Pos) when Pos > 0 -> 406 {B1, B2} = split_binary(B, Pos), 407 B1 = list_to_binary(lists:sublist(L, 1, Pos)), 408 B2 = list_to_binary(lists:nthtail(Pos, L)), 409 split(L, B, Pos-1); 410split(_L, _B, 0) -> 411 ok. 412 413%% Tries split_binary/2 with bad arguments. 414bad_split(Config) when is_list(Config) -> 415 GoodBin = list_to_binary([1,2,3]), 416 bad_split(GoodBin, -1), 417 bad_split(GoodBin, 4), 418 bad_split(GoodBin, a), 419 420 %% Funs are a kind of binaries. 421 bad_split(fun(_X) -> 1 end, 1), 422 ok. 423 424bad_split(Bin, Pos) -> 425 {'EXIT',{badarg,_}} = (catch split_binary(Bin, Pos)). 426 427%% Test hash/2 with different type of binaries. 428t_hash(Config) when is_list(Config) -> 429 test_hash([]), 430 test_hash([253]), 431 test_hash(lists:seq(1, ?heap_binary_size)), 432 test_hash(lists:seq(1, ?heap_binary_size+1)), 433 test_hash([X rem 256 || X <- lists:seq(1, 312)]), 434 ok. 435 436test_hash(List) -> 437 Bin = list_to_binary(List), 438 Sbin = make_sub_binary(List), 439 Unaligned = make_unaligned_sub_binary(Sbin), 440 test_hash_1(Bin, Sbin, Unaligned, fun erlang:phash/2), 441 test_hash_1(Bin, Sbin, Unaligned, fun erlang:phash2/2). 442 443test_hash_1(Bin, Sbin, Unaligned, Hash) when is_function(Hash, 2) -> 444 N = 65535, 445 case {Hash(Bin, N),Hash(Sbin, N),Hash(Unaligned, N)} of 446 {H,H,H} -> ok; 447 {H1,H2,H3} -> 448 ct:fail("Different hash values: ~p, ~p, ~p\n", [H1,H2,H3]) 449 end. 450 451%% Try bad arguments to size/1. 452bad_size(Config) when is_list(Config) -> 453 {'EXIT',{badarg,_}} = (catch size(fun(X) -> X + 33 end)), 454 ok. 455 456bad_term_to_binary(Config) when is_list(Config) -> 457 T = id({a,b,c}), 458 {'EXIT',{badarg,_}} = (catch term_to_binary(T, not_a_list)), 459 {'EXIT',{badarg,_}} = (catch term_to_binary(T, [blurf])), 460 {'EXIT',{badarg,_}} = (catch term_to_binary(T, [iovec])), 461 {'EXIT',{badarg,_}} = (catch term_to_binary(T, [{compressed,-1}])), 462 {'EXIT',{badarg,_}} = (catch term_to_binary(T, [{compressed,10}])), 463 {'EXIT',{badarg,_}} = (catch term_to_binary(T, [{compressed,cucumber}])), 464 {'EXIT',{badarg,_}} = (catch term_to_binary(T, [{compressed}])), 465 {'EXIT',{badarg,_}} = (catch term_to_binary(T, [{version,1}|bad_tail])), 466 {'EXIT',{badarg,_}} = (catch term_to_binary(T, [{minor_version,-1}])), 467 {'EXIT',{badarg,_}} = (catch term_to_binary(T, [{minor_version,x}])), 468 469 ok. 470 471t2b_system_limit(Config) when is_list(Config) -> 472 case erlang:system_info(wordsize) of 473 8 -> 474 case proplists:get_value(system_total_memory, 475 memsup:get_system_memory_data()) of 476 Memory when is_integer(Memory), 477 Memory > 6*1024*1024*1024 -> 478 do_t2b_system_limit(); 479 _ -> 480 {skipped, "Not enough memory on this machine"} 481 end; 482 4 -> 483 {skipped, "Only interesting on 64-bit builds"} 484 end. 485 486do_t2b_system_limit() -> 487 F = fun() -> 488 io:format("Creating HugeBin~n", []), 489 Bits = (1 bsl 32) + 1, 490 HugeBin = <<0:Bits/unit:8>>, 491 test_t2b_system_limit(HugeBin, term_to_binary, 492 fun erlang:term_to_binary/1, 493 fun erlang:term_to_binary/2), 494 test_t2b_system_limit(HugeBin, term_to_iovec, 495 fun erlang:term_to_iovec/1, 496 fun erlang:term_to_iovec/2), 497 garbage_collect(), 498 ok 499 end, 500 Opts = [{args, "-pa " ++ filename:dirname(code:which(?MODULE))}], 501 {ok,Node} = test_server:start_node(?FUNCTION_NAME, slave, Opts), 502 erpc:call(Node, F). 503 504test_t2b_system_limit(HugeBin, Name, F1, F2) -> 505 io:format("Testing ~p(HugeBin)~n", [Name]), 506 {'EXIT',{system_limit,[{erlang,Name,[HugeBin],_}|_]}} = 507 t2b_eval(fun() -> F1(HugeBin) end), 508 509 io:format("Testing ~p(HugeBin, [compressed])~n", [Name]), 510 {'EXIT',{system_limit,[{erlang,Name,[HugeBin,[compressed]],_}|_]}} = 511 t2b_eval(fun() -> F2(HugeBin, [compressed]) end), 512 513 %% Check that it works also after we have trapped... 514 io:format("Creating HugeListBin~n", []), 515 HugeListBin = [lists:duplicate(2000000, 2000000), HugeBin], 516 517 io:format("Testing ~p(HugeListBin)~n", [Name]), 518 {'EXIT',{system_limit,[{erlang,Name,[HugeListBin],_}|_]}} = 519 t2b_eval(fun() -> F1(HugeListBin) end), 520 521 io:format("Testing ~p(HugeListBin, [compressed])~n", [Name]), 522 {'EXIT',{system_limit,[{erlang,Name,[HugeListBin,[compressed]],_}|_]}} = 523 t2b_eval(fun() -> F2(HugeListBin, [compressed]) end), 524 525 ok. 526 527t2b_eval(F) -> 528 Result = (catch F()), 529 io:put_chars(io_lib:format("~P\n", [Result,100])), 530 Result. 531 532term_to_iovec(Config) when is_list(Config) -> 533 Bin = list_to_binary(lists:duplicate(1000,100)), 534 Bin2 = list_to_binary(lists:duplicate(65,100)), 535 check_term_to_iovec({[Bin, atom, Bin, 1244, make_ref(), Bin]}), 536 check_term_to_iovec(Bin), 537 check_term_to_iovec([Bin,Bin,Bin,Bin]), 538 check_term_to_iovec(blipp), 539 check_term_to_iovec(lists:duplicate(1000,100)), 540 check_term_to_iovec([[Bin2]]), 541 check_term_to_iovec([erlang:ports(), Bin, erlang:processes()]), 542 ok. 543 544check_term_to_iovec(Term) -> 545 IoVec1 = erlang:term_to_iovec(Term), 546 ok = check_is_iovec(IoVec1), 547 IoVec2 = erlang:term_to_iovec(Term, []), 548 ok = check_is_iovec(IoVec2), 549 B = erlang:term_to_binary(Term), 550 IoVec1Bin = erlang:iolist_to_binary(IoVec1), 551 IoVec2Bin = erlang:iolist_to_binary(IoVec2), 552 try 553 B = IoVec1Bin 554 catch 555 _:_ -> 556 io:format("Binary: ~p~n", [B]), 557 io:format("I/O vec1 binary: ~p~n", [IoVec1Bin]), 558 io:format("I/O vec1: ~p~n", [IoVec1]), 559 ct:fail(not_same_result) 560 end, 561 try 562 B = IoVec2Bin 563 catch 564 _:_ -> 565 io:format("Binary: ~p~n", [B]), 566 io:format("I/O vec2 binary: ~p~n", [IoVec2Bin]), 567 io:format("I/O vec2: ~p~n", [IoVec2]), 568 ct:fail(not_same_result) 569 end. 570 571check_is_iovec([]) -> 572 ok; 573check_is_iovec([B|Bs]) when is_binary(B) -> 574 check_is_iovec(Bs). 575 576%% Tests binary_to_term/1 and term_to_binary/1. 577 578terms(Config) when is_list(Config) -> 579 TestFun = fun(Term) -> 580 S = io_lib:format("~p", [Term]), 581 io:put_chars(S), 582 583 Bin = term_to_binary(Term), 584 case erlang:external_size(Bin) of 585 Sz when is_integer(Sz), size(Bin) =< Sz -> 586 ok 587 end, 588 589 Bin1 = term_to_binary(Term, [{minor_version, 1}]), 590 case erlang:external_size(Bin1, [{minor_version, 1}]) of 591 Sz1 when is_integer(Sz1), size(Bin1) =< Sz1 -> 592 ok 593 end, 594 595 BinDet = term_to_binary(Term, [deterministic]), 596 case erlang:external_size(Bin) of 597 DetSz when is_integer(DetSz), byte_size(Bin) =< DetSz -> 598 ok 599 end, 600 601 Term = binary_to_term_stress(Bin), 602 Term = binary_to_term_stress(Bin, [safe]), 603 Term = binary_to_term_stress(BinDet), 604 Bin_sz = byte_size(Bin), 605 {Term,Bin_sz} = binary_to_term_stress(Bin, [used]), 606 607 BinE = <<Bin/binary, 1, 2, 3>>, 608 {Term,Bin_sz} = binary_to_term_stress(BinE, [used]), 609 610 BinU = make_unaligned_sub_binary(Bin), 611 Term = binary_to_term_stress(BinU), 612 Term = binary_to_term_stress(BinU, []), 613 Term = binary_to_term_stress(BinU, [safe]), 614 {Term,Bin_sz} = binary_to_term_stress(BinU, [used]), 615 616 BinUE = make_unaligned_sub_binary(BinE), 617 {Term,Bin_sz} = binary_to_term_stress(BinUE, [used]), 618 619 BinC = erlang:term_to_binary(Term, [compressed]), 620 BinC_sz = byte_size(BinC), 621 true = BinC_sz =< size(Bin), 622 Term = binary_to_term_stress(BinC), 623 {Term, BinC_sz} = binary_to_term_stress(BinC, [used]), 624 625 Bin = term_to_binary(Term, [{compressed,0}]), 626 terms_compression_levels(Term, size(Bin), 1), 627 628 BinUC = make_unaligned_sub_binary(BinC), 629 Term = binary_to_term_stress(BinUC), 630 {Term,BinC_sz} = binary_to_term_stress(BinUC, [used]), 631 632 BinCE = <<BinC/binary, 1, 2, 3>>, 633 {Term,BinC_sz} = binary_to_term_stress(BinCE, [used]), 634 635 BinUCE = make_unaligned_sub_binary(BinCE), 636 Term = binary_to_term_stress(BinUCE), 637 {Term,BinC_sz} = binary_to_term_stress(BinUCE, [used]) 638 end, 639 test_terms(TestFun), 640 ok. 641 642%% Test binary_to_term(_, [used]) returning a big Used integer. 643b2t_used_big(_Config) -> 644 case erlang:system_info(wordsize) of 645 8 -> 646 {skipped, "This is not a 32-bit machine"}; 647 4 -> 648 %% Use a long utf8 atom for large external format but compact on heap. 649 BigAtom = binary_to_atom(<< <<16#F0908D88:32>> || _ <- lists:seq(1,255) >>, 650 utf8), 651 Atoms = (1 bsl 17) + (1 bsl 9), 652 BigAtomList = lists:duplicate(Atoms, BigAtom), 653 BigBin = term_to_binary(BigAtomList), 654 {BigAtomList, Used} = binary_to_term(BigBin, [used]), 655 2 = erts_debug:size(Used), 656 Used = byte_size(BigBin), 657 Used = 1 + 1 + 4 + Atoms*(1+2+4*255) + 1, 658 ok 659 end. 660 661terms_compression_levels(Term, UncompressedSz, Level) when Level < 10 -> 662 BinC = erlang:term_to_binary(Term, [{compressed,Level}]), 663 Term = binary_to_term_stress(BinC), 664 Sz = byte_size(BinC), 665 true = Sz =< UncompressedSz, 666 terms_compression_levels(Term, UncompressedSz, Level+1); 667terms_compression_levels(_, _, _) -> ok. 668 669terms_float(Config) when is_list(Config) -> 670 test_floats(fun(Term) -> 671 Bin0 = term_to_binary(Term, [{minor_version,0}]), 672 Term = binary_to_term_stress(Bin0), 673 Bin1 = term_to_binary(Term), 674 Bin1 = term_to_binary(Term, [{minor_version,1}]), 675 Term = binary_to_term_stress(Bin1), 676 true = size(Bin1) < size(Bin0), 677 Size0 = erlang:external_size(Term, [{minor_version, 0}]), 678 Size1 = erlang:external_size(Term), 679 Size11 = erlang:external_size(Term, [{minor_version, 1}]), 680 true = (Size1 =:= Size11), 681 true = Size1 < Size0 682 end). 683 684float_middle_endian(Config) when is_list(Config) -> 685 %% Testing for roundtrip is not enough. 686 <<131,70,63,240,0,0,0,0,0,0>> = term_to_binary(1.0, [{minor_version,1}]), 687 1.0 = binary_to_term_stress(<<131,70,63,240,0,0,0,0,0,0>>). 688 689%% Test term_to_binary(Term, [deterministic]). 690t2b_deterministic(_Config) -> 691 _ = rand:uniform(), %Seed generator 692 io:format("Seed: ~p", [rand:export_seed()]), 693 Map0 = t2b_deterministic_1(100, #{1 => a, 1.0 => b}), 694 695 Map1 = maps:merge(make_map(10000), Map0), 696 test_deterministic(Map1), 697 698 case total_memory() of 699 Amount when Amount > 15 -> 700 t2b_deterministic_heavy(Map0); 701 _ -> 702 {comment,"heavy tests skipped"} 703 end. 704 705t2b_deterministic_heavy(Map0) -> 706 Map1 = maps:merge(make_map(1_000_000), Map0), 707 test_deterministic(Map1), 708 709 %% If the external representation of the term to be encoded is 710 %% estimated to fit in a heap binary (64 bytes), the internal 711 %% enc_term_int() function that does the actual encoding will be 712 %% called without an context and thus is unable to trap. In the 713 %% DEBUG build of the runtime system, maps with more than 3 714 %% elements will be large maps, and depending on the keys and 715 %% values, it is possible that a large map can fit in 64 716 %% bytes. Therefore, the encoding code for deterministic maps must 717 %% cannot assume that there always exists a context. 718 719 lists:foreach(fun(N) -> 720 Map = maps:from_list([{E,E} || E <- lists:seq(1, N)]), 721 test_deterministic(Map) 722 end, lists:seq(4, 16)), 723 724 %% Test that terminating a process that is encoding a huge map 725 %% will neither crash the runtime system nor leak memory. (Run the 726 %% test with memory sanitizer or valgrind to catch potential memory 727 %% leaks.) 728 erlang:trace_pattern({erlang, term_to_binary, 2}, true, []), 729 Map = huge_map(1_000_000, []), 730 rinse_and_repeat(2, Map). 731 732rinse_and_repeat(Wait, Map) -> 733 {Pid,Ref} = spawn_monitor(fun() -> 734 receive go -> ok end, 735 term_to_binary(Map, [deterministic]) 736 end), 737 erlang:trace(Pid, true, [call,arity]), 738 739 Pid ! go, 740 receive 741 {trace,Pid,call,{erlang,term_to_binary,2}} -> 742 %% Wait a short period to avoid killing term_to_binary/2 during 743 %% size calculation part. 744 receive after Wait -> ok end, 745 exit(Pid, kill); 746 Other -> 747 error(Other) 748 end, 749 750 receive 751 {'DOWN',Ref,process,Pid,Reason} -> 752 case Reason of 753 normal -> 754 %% The encoding operation finished before the process 755 %% was forcefully killed. Done. 756 ok; 757 killed -> 758 %% The process was killed in term_to_binary/2. We 759 %% can't know whether it was killed too early, so 760 %% we will try again with a slightly longer time. 761 rinse_and_repeat(Wait + Wait div 2, Map) 762 end; 763 Other2 -> 764 error(Other2) 765 end. 766 767huge_map(0, Acc) -> 768 maps:from_list(Acc); 769huge_map(N, Acc) -> 770 %% Create awkward keys to slow down the sorting. 771 Key = <<N:127/big>>, 772 huge_map(N-1, [{Key,N}|Acc]). 773 774t2b_deterministic_1(0, Map) -> 775 Map; 776t2b_deterministic_1(N, Map0) -> 777 test_deterministic(Map0), 778 Map = Map0#{random_term() => N}, 779 t2b_deterministic_1(N - 1, Map). 780 781test_deterministic(Map) -> 782 Bin = term_to_binary(Map, [deterministic]), 783 Map = binary_to_term(Bin), 784 785 %% Make sure that the keys for the map are ordered. 786 List0 = maps:to_list(Map), 787 List = lists:sort(fun(A, B) -> erts_internal:cmp_term(A, B) =< 0 end, List0), 788 List = decode_ext_map(Bin), 789 ok. 790 791decode_ext_map(MapBin) -> 792 MapTag = 116, 793 ListTag = 108, 794 NilTag = 106, 795 796 %% Rewrite the map to a list before decoding to preserve the order 797 %% the map elements. 798 <<131,MapTag,Size:32,Bin0/binary>> = MapBin, 799 ListBin = <<131,ListTag,(2*Size):32,Bin0/binary,NilTag>>, 800 List = binary_to_term(ListBin), 801 decode_ext_map_1(List). 802 803decode_ext_map_1([Key,Val|T]) -> 804 [{Key,Val}|decode_ext_map_1(T)]; 805decode_ext_map_1([]) -> []. 806 807make_map(N) -> 808 maps:from_list([{I,I*I} || I <- lists:seq(1, N)]). 809 810random_term() -> 811 case rand:uniform(11) of 812 1 -> 813 list_to_atom(integer_to_list(36#aaaa + rand:uniform(100) * 23, 36)); 814 2 -> 815 rand:uniform(); 816 3 -> 817 rand:uniform(10000000); 818 4 -> 819 (1 bsl rand:uniform(128)) + rand:uniform(10000000); 820 5 -> 821 self(); 822 6 -> 823 make_ref(); 824 7 -> 825 random_list(); 826 8 -> 827 list_to_tuple(random_list()); 828 9 -> 829 []; 830 10 -> 831 make_map(33); 832 11 -> 833 make_map(rand:uniform(10)) 834 end. 835 836random_list() -> 837 [random_term() || _ <- lists:seq(1, rand:uniform(10)-1)]. 838 839external_size(Config) when is_list(Config) -> 840 %% Build a term whose external size only fits in a big num (on 32-bit CPU). 841 external_size_1(16#11111111111111117777777777777777888889999, 0, 16#FFFFFFF), 842 843 %% Test that the same binary aligned and unaligned has the same external size. 844 Bin = iolist_to_binary([1,2,3,96]), 845 Unaligned = make_unaligned_sub_binary(Bin), 846 case {erlang:external_size(Bin),erlang:external_size(Unaligned)} of 847 {X,X} -> ok; 848 {Sz1,Sz2} -> 849 ct:fail(" Aligned size: ~p\n" 850 "Unaligned size: ~p\n", [Sz1,Sz2]) 851 end, 852 true = (erlang:external_size(Bin) =:= erlang:external_size(Bin, [{minor_version, 1}])), 853 true = (erlang:external_size(Unaligned) =:= erlang:external_size(Unaligned, [{minor_version, 1}])). 854 855external_size_1(Term, Size0, Limit) when Size0 < Limit -> 856 case erlang:external_size(Term) of 857 Size when is_integer(Size), Size0 < Size -> 858 io:format("~p", [Size]), 859 external_size_1([Term|Term], Size, Limit) 860 end; 861external_size_1(_, _, _) -> ok. 862 863t_iolist_size(Config) when is_list(Config) -> 864 _ = rand:uniform(), %Seed generator 865 io:format("Seed: ~p", [rand:export_seed()]), 866 867 Base = <<0:(1 bsl 20)/unit:8>>, 868 Powers = [1 bsl N || N <- lists:seq(2, 37)], 869 Sizes0 = [[N - rand:uniform(N div 2), 870 lists:seq(N-2, N+2), 871 N+N div 2, 872 N + rand:uniform(N div 2)] || 873 N <- Powers], 874 875 %% Test sizes around 1^32 more thoroughly. 876 FourGigs = 1 bsl 32, 877 Sizes1 = [FourGigs+N || N <- lists:seq(-8, 40)] ++ Sizes0, 878 Sizes2 = lists:flatten(Sizes1), 879 Sizes = lists:usort(Sizes2), 880 io:format("~p sizes:", [length(Sizes)]), 881 io:format("~p\n", [Sizes]), 882 _ = [Sz = iolist_size(build_iolist(Sz, Base)) || Sz <- Sizes], 883 ok. 884 885build_iolist(N, Base) when N < 16 -> 886 case rand:uniform(3) of 887 1 -> 888 <<Bin:N/binary,_/binary>> = Base, 889 Bin; 890 _ -> 891 lists:seq(1, N) 892 end; 893build_iolist(N, Base) when N =< byte_size(Base) -> 894 case rand:uniform(3) of 895 1 -> 896 <<Bin:N/binary,_/binary>> = Base, 897 Bin; 898 2 -> 899 <<Bin:N/binary,_/binary>> = Base, 900 [Bin]; 901 3 -> 902 case N rem 2 of 903 0 -> 904 L = build_iolist(N div 2, Base), 905 [L,L]; 906 1 -> 907 L = build_iolist(N div 2, Base), 908 [L,L,45] 909 end 910 end; 911build_iolist(N0, Base) -> 912 Small = rand:uniform(15), 913 Seq = lists:seq(1, Small), 914 N = N0 - Small, 915 case N rem 2 of 916 0 -> 917 L = build_iolist(N div 2, Base), 918 [L,L|Seq]; 919 1 -> 920 L = build_iolist(N div 2, Base), 921 [47,L,L|Seq] 922 end. 923 924approx_4GB_bin() -> 925 Bin = lists:duplicate(4194304, 255), 926 BinRet = erlang:iolist_to_binary(lists:duplicate(1124, Bin)), 927 BinRet. 928 929duplicate_iolist(IOList, 0) -> 930 IOList; 931duplicate_iolist(IOList, NrOfTimes) -> 932 duplicate_iolist([IOList, IOList], NrOfTimes - 1). 933 934t_iolist_size_huge_list(Config) when is_list(Config) -> 935 run_when_enough_resources( 936 fun() -> 937 {TimeToCreateIOList, IOList} = timer:tc(fun()->duplicate_iolist(approx_4GB_bin(), 32) end), 938 {IOListSizeTime, CalculatedSize} = timer:tc(fun()->erlang:iolist_size(IOList) end), 939 20248183924657750016 = CalculatedSize, 940 {comment, io_lib:format("Time to create iolist: ~f s. Time to calculate size: ~f s.", 941 [TimeToCreateIOList / 1000000, IOListSizeTime / 1000000])} 942 end). 943 944t_iolist_size_huge_bad_arg_list(Config) when is_list(Config) -> 945 run_when_enough_resources( 946 fun() -> 947 P = self(), 948 spawn_link(fun()-> IOListTmp = duplicate_iolist(approx_4GB_bin(), 32), 949 IOList = [IOListTmp, [badarg]], 950 {'EXIT',{badarg,_}} = (catch erlang:iolist_size(IOList)), 951 P ! ok 952 end), 953 receive ok -> ok end 954 end). 955 956%% iolist_size tests for shallow lists 957 958t_iolist_size_shallow_trapping(Config) when is_list(Config) -> 959 Lengths = [2000, 20000, 200000, 200000, 2000000, 20000000], 960 run_iolist_size_test_and_benchmark(Lengths, fun make_shallow_iolist/2). 961 962t_iolist_size_shallow_short_lists(Config) when is_list(Config) -> 963 Lengths = lists:duplicate(15000, 300), 964 run_iolist_size_test_and_benchmark(Lengths, fun make_shallow_iolist/2). 965 966t_iolist_size_shallow_tiny_lists(Config) when is_list(Config) -> 967 Lengths = lists:duplicate(250000, 18), 968 run_iolist_size_test_and_benchmark(Lengths, fun make_shallow_iolist/2). 969 970make_shallow_iolist(SizeDiv2, LastItem) -> 971 lists:map( 972 fun(I) -> 973 case I of 974 SizeDiv2 -> [1, LastItem]; 975 _ -> [1, 1] 976 end 977 end, 978 lists:seq(1, SizeDiv2)). 979 980%% iolist_size tests for deep lists 981 982t_iolist_size_deep_trapping(Config) when is_list(Config) -> 983 Lengths = [2000, 20000, 200000, 200000, 2000000, 10000000], 984 run_iolist_size_test_and_benchmark(Lengths, fun make_deep_iolist/2). 985 986t_iolist_size_deep_short_lists(Config) when is_list(Config) -> 987 Lengths = lists:duplicate(10000, 300), 988 run_iolist_size_test_and_benchmark(Lengths, fun make_deep_iolist/2). 989 990t_iolist_size_deep_tiny_lists(Config) when is_list(Config) -> 991 Lengths = lists:duplicate(150000, 18), 992 run_iolist_size_test_and_benchmark(Lengths, fun make_deep_iolist/2). 993 994make_deep_iolist(1, LastItem) -> 995 [1, LastItem]; 996make_deep_iolist(Depth, LastItem) -> 997 [[1, 1], make_deep_iolist(Depth - 1, LastItem)]. 998 999% Helper functions for iolist_size tests 1000 1001run_iolist_size_test_and_benchmark(Lengths, ListGenerator) -> 1002 run_when_enough_resources( 1003 fun() -> 1004 GoodListsWithSizes = 1005 lists:map(fun(Length) -> {Length*2, ListGenerator(Length, 1)} end, Lengths), 1006 BadListsWithSizes = 1007 lists:map(fun(Length) -> {Length*2, ListGenerator(Length, bad)} end, Lengths), 1008 erlang:garbage_collect(), 1009 report_throughput( 1010 fun() -> 1011 lists:foreach( 1012 fun(_)-> 1013 lists:foreach( 1014 fun({Size, List}) -> Size = iolist_size(List) end, 1015 GoodListsWithSizes), 1016 lists:foreach( 1017 fun({_, List}) -> {'EXIT',_} = (catch (iolist_size(List))) end, 1018 BadListsWithSizes) 1019 end, 1020 lists:seq(1,3)) 1021 end, 1022 lists:sum(Lengths)*4) 1023 end). 1024 1025report_throughput(Fun, NrOfItems) -> 1026 Parent = self(), 1027 spawn(fun() -> Parent ! timer:tc(Fun) end), 1028 {Time, _} = receive D -> D end, 1029 ItemsPerMicrosecond = NrOfItems / Time, 1030 ct_event:notify(#event{ name = benchmark_data, data = [{value, ItemsPerMicrosecond}]}), 1031 {comment, io_lib:format("Items per microsecond: ~p, Nr of items: ~p, Benchmark time: ~p seconds)", 1032 [ItemsPerMicrosecond, NrOfItems, Time/1000000])}. 1033 1034total_memory() -> 1035 %% Total memory in GB. 1036 try 1037 MemoryData = memsup:get_system_memory_data(), 1038 case lists:keysearch(total_memory, 1, MemoryData) of 1039 {value, {total_memory, TM}} -> 1040 TM div (1024*1024*1024); 1041 false -> 1042 {value, {system_total_memory, STM}} = 1043 lists:keysearch(system_total_memory, 1, MemoryData), 1044 STM div (1024*1024*1024) 1045 end 1046 catch 1047 _ : _ -> 1048 undefined 1049 end. 1050 1051run_when_enough_resources(Fun) -> 1052 case {total_memory(), erlang:system_info(wordsize)} of 1053 {Mem, 8} when is_integer(Mem) andalso Mem >= 15 -> 1054 Fun(); 1055 {Mem, WordSize} -> 1056 {skipped, 1057 io_lib:format("Not enough resources (System Memory >= ~p, Word Size = ~p)", 1058 [Mem, WordSize])} 1059 end. 1060 1061 1062%% OTP-4053 1063bad_binary_to_term_2(Config) when is_list(Config) -> 1064 {ok, N} = test_server:start_node(plopp, slave, []), 1065 R = rpc:call(N, erlang, binary_to_term, [<<131,111,255,255,255,0>>]), 1066 case R of 1067 {badrpc, {'EXIT', _}} -> 1068 ok; 1069 _Other -> 1070 ct:fail({rpcresult, R}) 1071 end, 1072 test_server:stop_node(N), 1073 ok. 1074 1075%% Try bad input to binary_to_term/1. 1076bad_binary_to_term(Config) when is_list(Config) -> 1077 bad_bin_to_term(an_atom), 1078 bad_bin_to_term({an,tuple}), 1079 bad_bin_to_term({a,list}), 1080 bad_bin_to_term(fun() -> self() end), 1081 bad_bin_to_term(fun(X) -> 42*X end), 1082 bad_bin_to_term(fun(X, Y) -> {X,Y} end), 1083 bad_bin_to_term(fun(X, Y, Z) -> {X,Y,Z} end), 1084 bad_bin_to_term(bit_sized_binary(term_to_binary({you,should,'not',see,this,term}))), 1085 1086 %% Bad float. 1087 bad_bin_to_term(<<131,70,-1:64>>), 1088 1089 %% Truncated UTF8 character (ERL-474) 1090 bad_bin_to_term(<<131,119,1,194,163>>), 1091 ok. 1092 1093bad_bin_to_term(BadBin) -> 1094 {'EXIT',{badarg,_}} = (catch binary_to_term_stress(BadBin)). 1095 1096bad_bin_to_term(BadBin,Opts) -> 1097 {'EXIT',{badarg,_}} = (catch binary_to_term_stress(BadBin,Opts)). 1098 1099%% Test safety options for binary_to_term/2 1100safe_binary_to_term2(Config) when is_list(Config) -> 1101 bad_bin_to_term(<<131,100,0,14,"undefined_atom">>, [safe]), 1102 bad_bin_to_term(<<131,100,0,14,"other_bad_atom">>, [safe]), 1103 BadHostAtom = <<100,0,14,"badguy@badhost">>, 1104 Empty = <<0,0,0,0>>, 1105 BadRef = <<131,114,0,3,BadHostAtom/binary,0,<<0,0,0,255>>/binary, 1106 Empty/binary,Empty/binary>>, 1107 bad_bin_to_term(BadRef, [safe]), % good ref, with a bad atom 1108 fullsweep_after = binary_to_term_stress(<<131,100,0,15,"fullsweep_after">>, [safe]), % should be a good atom 1109 BadExtFun = <<131,113,100,0,4,98,108,117,101,100,0,4,109,111,111,110,97,3>>, 1110 bad_bin_to_term(BadExtFun, [safe]), 1111 ok. 1112 1113%% Tests bad input to binary_to_term/1. 1114 1115bad_terms(Config) when is_list(Config) -> 1116 test_terms(fun corrupter/1), 1117 {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,3:32,0,11,22,33>>)), 1118 {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,3:32,9,11,22,33>>)), 1119 {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,0:32,1,11,22,33>>)), 1120 {'EXIT',{badarg,_}} = (catch binary_to_term(<<131,$M,-1:32,1,11,22,33>>)), 1121 ok. 1122 1123corrupter(Term) -> 1124 try 1125 S = io_lib:format("About to corrupt: ~P", [Term,12]), 1126 io:put_chars(S) 1127 catch 1128 error:badarg -> 1129 io:format("About to corrupt: <<bit-level-binary:~p", 1130 [bit_size(Term)]) 1131 end, 1132 Bin = term_to_binary(Term), 1133 corrupter(Bin, size(Bin)-1), 1134 CompressedBin = term_to_binary(Term, [compressed]), 1135 corrupter(CompressedBin, size(CompressedBin)-1). 1136 1137corrupter(Bin, Pos) when Pos >= 0 -> 1138 {ShorterBin, Rest} = split_binary(Bin, Pos), 1139 catch binary_to_term_stress(ShorterBin), %% emulator shouldn't crash 1140 MovedBin = list_to_binary([ShorterBin]), 1141 catch binary_to_term_stress(MovedBin), %% emulator shouldn't crash 1142 1143 %% Bit faults, shouldn't crash 1144 <<Byte,Tail/binary>> = Rest, 1145 Fun = fun(M) -> FaultyByte = Byte bxor M, 1146 catch binary_to_term_stress(<<ShorterBin/binary, 1147 FaultyByte, Tail/binary>>) end, 1148 lists:foreach(Fun,[1,2,4,8,16,32,64,128,255]), 1149 corrupter(Bin, Pos-1); 1150corrupter(_Bin, _) -> 1151 ok. 1152 1153more_bad_terms(Config) when is_list(Config) -> 1154 Data = proplists:get_value(data_dir, Config), 1155 BadFile = filename:join(Data, "bad_binary"), 1156 ok = io:format("File: ~s\n", [BadFile]), 1157 case file:read_file(BadFile) of 1158 {ok,Bin} -> 1159 {'EXIT',{badarg,_}} = (catch binary_to_term_stress(Bin)), 1160 ok; 1161 Other -> 1162 ct:fail(Other) 1163 end. 1164 1165otp_5484(Config) when is_list(Config) -> 1166 {'EXIT',_} = 1167 (catch 1168 binary_to_term_stress( 1169 <<131, 1170 104,2, %Tuple, 2 elements 1171 103, %Pid 1172 100,0,20,"wslin1427198@wslin14", 1173 %% Obviously bad values follow. 1174 255,255,255,255, 1175 255,255,255,255, 1176 255, 1177 106>>)), 1178 1179 {'EXIT',_} = 1180 (catch 1181 binary_to_term_stress( 1182 <<131, 1183 104,2, %Tuple, 2 elements 1184 103, %Pid 1185 106, %[] instead of atom. 1186 0,0,0,17, 1187 0,0,0,135, 1188 2, 1189 106>>)), 1190 1191 {'EXIT',_} = 1192 (catch 1193 binary_to_term_stress( 1194 %% A old-type fun in a list containing a bad creator pid. 1195 <<131,108,0,0,0,1,117,0,0,0,0,103,100,0,13,110,111,110,111,100,101,64,110,111,104,111,115,116,255,255,0,25,255,0,0,0,0,100,0,1,116,97,0,98,6,142,121,72,106>>)), 1196 1197 {'EXIT',_} = 1198 (catch 1199 binary_to_term_stress( 1200 %% A new-type fun in a list containing a bad creator pid. 1201 %% 1202 <<131, 1203 108,0,0,0,1, %List, 1 element 1204 112,0,0,0,66,0,52,216,81,158,148,250,237,109,185,9,208,60,202,156,244,218,0,0,0,0,0,0,0,0,100,0,1,116,97,0,98,6,142,121,72, 1205 103, %Pid. 1206 106, %[] instead of an atom. 1207 0,0,0,27,0,0,0,0,0,106>>)), 1208 1209 {'EXIT',_} = 1210 (catch 1211 binary_to_term_stress( 1212 %% A new-type fun in a list containing a bad module. 1213 <<131, 1214 108,0,0,0,1, %List, 1 element 1215 112,0,0,0,70,0,224,90,4,101,48,28,110,228,153,48,239,169,232,77,108,145,0,0,0,0,0,0,0,2, 1216 %%100,0,1,116, 1217 107,0,1,64, %String instead of atom (same length). 1218 97,0,98,6,64,82,230,103,100,0,13,110,111,110,111,100,101,64,110,111,104,111,115,116,0,0,0,48,0,0,0,0,0,97,42,97,7,106>>)), 1219 1220 {'EXIT',_} = 1221 (catch 1222 binary_to_term_stress( 1223 %% A new-type fun in a list containing a bad index. 1224 <<131, 1225 108,0,0,0,1, %List, 1 element 1226 112,0,0,0,70,0,224,90,4,101,48,28,110,228,153,48,239,169,232,77,108,145,0,0,0,0,0,0,0,2, 1227 100,0,1,116, 1228 %%97,0, %Integer: 0. 1229 104,0, %Tuple {} instead of integer. 1230 98,6,64,82,230,103,100,0,13,110,111,110,111,100,101,64,110,111,104,111,115,116,0,0,0,48,0,0,0,0,0,97,42,97,7,106>>)), 1231 1232 {'EXIT',_} = 1233 (catch 1234 binary_to_term_stress( 1235 %% A new-type fun in a list containing a bad unique value. 1236 <<131, 1237 108,0,0,0,1, %List, 1 element 1238 112,0,0,0,70,0,224,90,4,101,48,28,110,228,153,48,239,169,232,77,108,145,0,0,0,0,0,0,0,2, 1239 100,0,1,116, 1240 97,0, %Integer: 0. 1241 %%98,6,64,82,230, %Integer. 1242 100,0,2,64,65, %Atom instead of integer. 1243 103,100,0,13,110,111,110,111,100,101,64,110,111,104,111,115,116,0,0,0,48,0,0,0,0,0,97,42,97,7,106>>)), 1244 1245 %% An absurdly large atom. 1246 {'EXIT',_} = 1247 (catch binary_to_term_stress(iolist_to_binary([<<131,100,65000:16>>| 1248 lists:duplicate(65000, 42)]))), 1249 1250 %% Longer than 255 characters. 1251 {'EXIT',_} = 1252 (catch binary_to_term_stress(iolist_to_binary([<<131,100,256:16>>| 1253 lists:duplicate(256, 42)]))), 1254 1255 %% OTP-7218. Thanks to Matthew Dempsky. Also make sure that we 1256 %% cover the other error cases for external funs (EXPORT_EXT). 1257 {'EXIT',_} = 1258 (catch binary_to_term_stress( 1259 <<131, 1260 113, %EXPORT_EXP 1261 97,13, %Integer: 13 1262 97,13, %Integer: 13 1263 97,13>>)), %Integer: 13 1264 {'EXIT',_} = 1265 (catch binary_to_term_stress( 1266 <<131, 1267 113, %EXPORT_EXP 1268 100,0,1,64, %Atom: '@' 1269 97,13, %Integer: 13 1270 97,13>>)), %Integer: 13 1271 {'EXIT',_} = 1272 (catch binary_to_term_stress( 1273 <<131, 1274 113, %EXPORT_EXP 1275 100,0,1,64, %Atom: '@' 1276 100,0,1,64, %Atom: '@' 1277 106>>)), %NIL 1278 {'EXIT',_} = 1279 (catch binary_to_term_stress( 1280 <<131, 1281 113, %EXPORT_EXP 1282 100,0,1,64, %Atom: '@' 1283 100,0,1,64, %Atom: '@' 1284 98,255,255,255,255>>)), %Integer: -1 1285 {'EXIT',_} = 1286 (catch binary_to_term_stress( 1287 <<131, 1288 113, %EXPORT_EXP 1289 100,0,1,64, %Atom: '@' 1290 100,0,1,64, %Atom: '@' 1291 113,97,13,97,13,97,13>>)), %fun 13:13/13 1292 1293 %% Bad funs. 1294 {'EXIT',_} = (catch binary_to_term_stress(fake_fun(0, lists:seq(0, 256)))), 1295 ok. 1296 1297fake_fun(Arity, Env0) -> 1298 Uniq = erlang:md5([]), 1299 Index = 0, 1300 NumFree = length(Env0), 1301 Mod = list_to_binary(?MODULE_STRING), 1302 OldIndex = 0, 1303 OldUniq = 16#123456, 1304 <<131,Pid/binary>> = term_to_binary(self()), 1305 Env1 = [term_to_binary(Term) || Term <- Env0], 1306 Env = << <<Bin/binary>> || <<131,Bin/binary>> <- Env1 >>, 1307 B = <<Arity,Uniq/binary,Index:32,NumFree:32, 1308 $d,(byte_size(Mod)):16,Mod/binary, %Module. 1309 $a,OldIndex:8, 1310 $b,OldUniq:32, 1311 Pid/binary,Env/binary>>, 1312 <<131,$p,(byte_size(B)+4):32,B/binary>>. 1313 1314 1315%% More bad terms submitted by Matthias Lang. 1316otp_5933(Config) when is_list(Config) -> 1317 try_bad_lengths(<<131,$m>>), %binary 1318 try_bad_lengths(<<131,$n>>), %bignum 1319 try_bad_lengths(<<131,$o>>), %huge bignum 1320 ok. 1321 1322try_bad_lengths(B) -> 1323 try_bad_lengths(B, 16#FFFFFFFF). 1324 1325try_bad_lengths(B, L) when L > 16#FFFFFFF0 -> 1326 Bin = <<B/binary,L:32>>, 1327 io:format("~p\n", [Bin]), 1328 {'EXIT',_} = (catch binary_to_term_stress(Bin)), 1329 try_bad_lengths(B, L-1); 1330try_bad_lengths(_, _) -> ok. 1331 1332 1333otp_6817(Config) when is_list(Config) -> 1334 process_flag(min_heap_size, 20000), %Use the heap, not heap fragments. 1335 1336 %% Floats are only validated when the heap fragment has been allocated. 1337 BadFloat = <<131,99,53,46,48,$X,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,101,45,48,49,0,0,0,0,0>>, 1338 otp_6817_try_bin(BadFloat), 1339 1340 %% {Binary,BadFloat}: When the error in float is discovered, a refc-binary 1341 %% has been allocated and the list of refc-binaries goes through the 1342 %% limbo area between the heap top and stack. 1343 BinAndFloat = 1344 <<131,104,2,109,0,0,1,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20, 1345 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45, 1346 46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70, 1347 71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, 1348 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115, 1349 116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134, 1350 135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153, 1351 154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172, 1352 173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, 1353 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210, 1354 211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229, 1355 230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248, 1356 249,250,251,252,253,254,255,99,51,46,49,52,$B,$l,$u,$r,$f,48,48,48,48,48,48, 1357 48,48,49,50,52,51,52,101,43,48,48,0,0,0,0,0>>, 1358 otp_6817_try_bin(BinAndFloat), 1359 1360 %% {Fun,BadFloat} 1361 FunAndFloat = 1362 <<131,104,2,112,0,0,0,66,0,238,239,135,138,137,216,89,57,22,111,52,126,16,84, 1363 71,8,0,0,0,0,0,0,0,0,100,0,1,116,97,0,98,5,175,169,123,103,100,0,13,110,111, 1364 110,111,100,101,64,110,111,104,111,115,116,0,0,0,41,0,0,0,0,0,99,50,46,55,48, 1365 $Y,57,57,57,57,57,57,57,57,57,57,57,57,57,54,52,52,55,101,43,48,48,0,0,0,0,0>>, 1366 otp_6817_try_bin(FunAndFloat), 1367 1368 %% [ExternalPid|BadFloat] 1369 ExtPidAndFloat = 1370 <<131,108,0,0,0,1,103,100,0,13,107,97,108,108,101,64,115,116,114,105,100,101, 1371 114,0,0,0,36,0,0,0,0,2,99,48,46,$@,48,48,48,48,48,48,48,48,48,48,48,48,48,48, 1372 48,48,48,48,48,101,43,48,48,0,0,0,0,0>>, 1373 otp_6817_try_bin(ExtPidAndFloat), 1374 ok. 1375 1376otp_6817_try_bin(Bin) -> 1377 erlang:garbage_collect(), 1378 1379 %% If the bug is present, the heap pointer will moved when the invalid term 1380 %% is found and we will have a linked list passing through the limbo area 1381 %% between the heap top and the stack pointer. 1382 catch binary_to_term_stress(Bin), 1383 1384 %% If the bug is present, we will overwrite the pointers in the limbo area. 1385 Filler = erlang:make_tuple(1024, 16#3FA), 1386 id(Filler), 1387 1388 %% Will crash if the bug is present. 1389 erlang:garbage_collect(). 1390 1391%% Some bugs in binary_to_term when 32-bit integers are negative. 1392otp_8117(Config) when is_list(Config) -> 1393 [otp_8117_do(Op,-(1 bsl N)) || Op <- ['fun',named_fun,list,tuple], 1394 N <- lists:seq(0,31)], 1395 ok. 1396 1397otp_8117_do('fun',Neg) -> 1398 % Fun with negative num_free 1399 FunBin = term_to_binary(fun() -> ok end), 1400 <<B1:27/binary,_NumFree:32,Rest/binary>> = FunBin, 1401 bad_bin_to_term(<<B1/binary,Neg:32,Rest/binary>>); 1402otp_8117_do(named_fun,Neg) -> 1403 % Named fun with negative num_free 1404 FunBin = term_to_binary(fun F() -> F end), 1405 <<B1:27/binary,_NumFree:32,Rest/binary>> = FunBin, 1406 bad_bin_to_term(<<B1/binary,Neg:32,Rest/binary>>); 1407otp_8117_do(list,Neg) -> 1408 %% List with negative length 1409 bad_bin_to_term(<<131,104,2,108,Neg:32,97,11,104,1,97,12,97,13,106,97,14>>); 1410otp_8117_do(tuple,Neg) -> 1411 %% Tuple with negative arity 1412 bad_bin_to_term(<<131,104,2,105,Neg:32,97,11,97,12,97,13,97,14>>). 1413 1414 1415%% Tests ordering of binaries. 1416ordering(Config) when is_list(Config) -> 1417 B1 = list_to_binary([7,8,9]), 1418 B2 = make_sub_binary([1,2,3,4]), 1419 B3 = list_to_binary([1,2,3,5]), 1420 Unaligned = make_unaligned_sub_binary(B2), 1421 1422 %% From R8 binaries are compared as strings. 1423 1424 false = B1 == B2, 1425 false = B1 =:= B2, 1426 true = B1 /= B2, 1427 true = B1 =/= B2, 1428 1429 true = B1 > B2, 1430 true = B2 < B3, 1431 true = B2 =< B1, 1432 true = B2 =< B3, 1433 1434 true = B2 =:= Unaligned, 1435 true = B2 == Unaligned, 1436 true = Unaligned < B3, 1437 true = Unaligned =< B3, 1438 1439 %% Binaries are greater than all other terms. 1440 1441 true = B1 > 0, 1442 true = B1 > 39827491247298471289473333333333333333333333333333, 1443 true = B1 > -3489274937438742190467869234328742398347, 1444 true = B1 > 3.14, 1445 true = B1 > [], 1446 true = B1 > [a], 1447 true = B1 > {a}, 1448 true = B1 > self(), 1449 true = B1 > make_ref(), 1450 true = B1 > xxx, 1451 true = B1 > fun() -> 1 end, 1452 true = B1 > fun erlang:send/2, 1453 1454 Path = proplists:get_value(priv_dir, Config), 1455 AFile = filename:join(Path, "vanilla_file"), 1456 Port = open_port(AFile, [out]), 1457 true = B1 > Port, 1458 1459 true = B1 >= 0, 1460 true = B1 >= 39827491247298471289473333333333333333333333333333, 1461 true = B1 >= -3489274937438742190467869234328742398347, 1462 true = B1 >= 3.14, 1463 true = B1 >= [], 1464 true = B1 >= [a], 1465 true = B1 >= {a}, 1466 true = B1 >= self(), 1467 true = B1 >= make_ref(), 1468 true = B1 >= xxx, 1469 true = B1 >= fun() -> 1 end, 1470 true = B1 >= fun erlang:send/2, 1471 true = B1 >= Port, 1472 1473 ok. 1474 1475%% Test that comparison between binaries with different alignment work. 1476unaligned_order(Config) when is_list(Config) -> 1477 L = lists:seq(0, 7), 1478 [test_unaligned_order(I, J) || I <- L, J <- L], 1479 ok. 1480 1481test_unaligned_order(I, J) -> 1482 Align = {I,J}, 1483 io:format("~p ~p", [I,J]), 1484 true = test_unaligned_order_1('=:=', <<1,2,3,16#AA,16#7C,4,16#5F,5,16#5A>>, 1485 <<1,2,3,16#AA,16#7C,4,16#5F,5,16#5A>>, 1486 Align), 1487 false = test_unaligned_order_1('=/=', <<1,2,3>>, <<1,2,3>>, Align), 1488 true = test_unaligned_order_1('==', <<4,5,6>>, <<4,5,6>>, Align), 1489 false = test_unaligned_order_1('/=', <<1,2,3>>, <<1,2,3>>, Align), 1490 1491 true = test_unaligned_order_1('<', <<1,2>>, <<1,2,3>>, Align), 1492 true = test_unaligned_order_1('=<', <<1,2>>, <<1,2,3>>, Align), 1493 true = test_unaligned_order_1('=<', <<1,2,7,8>>, <<1,2,7,8>>, Align), 1494 ok. 1495 1496test_unaligned_order_1(Op, A, B, {Aa,Ba}) -> 1497 erlang:Op(unaligned_sub_bin(A, Aa), unaligned_sub_bin(B, Ba)). 1498 1499test_terms(Test_Func) -> 1500 Test_Func(atom), 1501 Test_Func(''), 1502 Test_Func('a'), 1503 Test_Func('ab'), 1504 Test_Func('abc'), 1505 Test_Func('abcd'), 1506 Test_Func('abcde'), 1507 Test_Func('abcdef'), 1508 Test_Func('abcdefg'), 1509 Test_Func('abcdefgh'), 1510 1511 Test_Func(fun() -> ok end), 1512 X = id([a,{b,c},c]), 1513 Y = id({x,y,z}), 1514 Z = id(1 bsl 8*257), 1515 Test_Func(fun() -> X end), 1516 Test_Func(fun() -> {X,Y} end), 1517 Test_Func([fun() -> {X,Y,Z} end, 1518 fun() -> {Z,X,Y} end, 1519 fun() -> {Y,Z,X} end]), 1520 1521 Test_Func({trace_ts,{even_bigger,{some_data,fun() -> ok end}},{1,2,3}}), 1522 Test_Func({trace_ts,{even_bigger,{some_data,<<1,2,3,4,5,6,7,8,9,10>>}}, 1523 {1,2,3}}), 1524 1525 Test_Func(1), 1526 Test_Func(42), 1527 Test_Func(-23), 1528 Test_Func(256), 1529 Test_Func(25555), 1530 Test_Func(-3333), 1531 1532 Test_Func(1.0), 1533 1534 Test_Func(183749783987483978498378478393874), 1535 Test_Func(-37894183749783987483978498378478393874), 1536 Very_Big = very_big_num(), 1537 Test_Func(Very_Big), 1538 Test_Func(-Very_Big+1), 1539 1540 Test_Func([]), 1541 Test_Func("abcdef"), 1542 Test_Func([a, b, 1, 2]), 1543 Test_Func([a|b]), 1544 1545 Test_Func({}), 1546 Test_Func({1}), 1547 Test_Func({a, b}), 1548 Test_Func({a, b, c}), 1549 Test_Func(list_to_tuple(lists:seq(0, 255))), 1550 Test_Func(list_to_tuple(lists:seq(0, 256))), 1551 1552 Test_Func(make_ref()), 1553 Test_Func([make_ref(), make_ref()]), 1554 1555 Test_Func(make_port()), 1556 1557 Test_Func(make_pid()), 1558 1559 Test_Func(Bin0 = list_to_binary(lists:seq(0, 14))), 1560 Test_Func(Bin1 = list_to_binary(lists:seq(0, ?heap_binary_size))), 1561 Test_Func(Bin2 = list_to_binary(lists:seq(0, ?heap_binary_size+1))), 1562 Test_Func(Bin3 = list_to_binary(lists:seq(0, 255))), 1563 1564 Test_Func(make_unaligned_sub_binary(Bin0)), 1565 Test_Func(make_unaligned_sub_binary(Bin1)), 1566 Test_Func(make_unaligned_sub_binary(Bin2)), 1567 Test_Func(make_unaligned_sub_binary(Bin3)), 1568 1569 Test_Func(make_sub_binary(lists:seq(42, 43))), 1570 Test_Func(make_sub_binary([42,43,44])), 1571 Test_Func(make_sub_binary([42,43,44,45])), 1572 Test_Func(make_sub_binary([42,43,44,45,46])), 1573 Test_Func(make_sub_binary([42,43,44,45,46,47])), 1574 Test_Func(make_sub_binary([42,43,44,45,46,47,48])), 1575 Test_Func(make_sub_binary(lists:seq(42, 49))), 1576 Test_Func(make_sub_binary(lists:seq(0, 14))), 1577 Test_Func(make_sub_binary(lists:seq(0, ?heap_binary_size))), 1578 Test_Func(make_sub_binary(lists:seq(0, ?heap_binary_size+1))), 1579 Test_Func(make_sub_binary(lists:seq(0, 255))), 1580 1581 Test_Func(make_unaligned_sub_binary(lists:seq(42, 43))), 1582 Test_Func(make_unaligned_sub_binary([42,43,44])), 1583 Test_Func(make_unaligned_sub_binary([42,43,44,45])), 1584 Test_Func(make_unaligned_sub_binary([42,43,44,45,46])), 1585 Test_Func(make_unaligned_sub_binary([42,43,44,45,46,47])), 1586 Test_Func(make_unaligned_sub_binary([42,43,44,45,46,47,48])), 1587 Test_Func(make_unaligned_sub_binary(lists:seq(42, 49))), 1588 Test_Func(make_unaligned_sub_binary(lists:seq(0, 14))), 1589 Test_Func(make_unaligned_sub_binary(lists:seq(0, ?heap_binary_size))), 1590 Test_Func(make_unaligned_sub_binary(lists:seq(0, ?heap_binary_size+1))), 1591 Test_Func(make_unaligned_sub_binary(lists:seq(0, 255))), 1592 1593 %% Bit level binaries. 1594 Test_Func(<<1:1>>), 1595 Test_Func(<<2:2>>), 1596 Test_Func(<<42:10>>), 1597 Test_Func(list_to_bitstring([<<5:6>>|lists:seq(0, 255)])), 1598 1599 Test_Func(F = fun(A) -> 42*A end), 1600 Test_Func(lists:duplicate(32, F)), 1601 1602 Test_Func(FF = fun binary_SUITE:all/0), 1603 Test_Func(lists:duplicate(32, FF)), 1604 1605 %% Maps. 1606 SmallMap = #{a => 1, b => 2, c => 3}, 1607 LargeMap1 = maps:from_list([{list_to_atom(integer_to_list(36#cafe+N*N*N, 36)),N} || 1608 N <- lists:seq(1, 33)]), 1609 LargeMap2 = maps:from_list([{list_to_atom(integer_to_list(36#dead+N, 36)),N} || 1610 N <- lists:seq(1, 50)]), 1611 MapWithMap = LargeMap1#{SmallMap => a, LargeMap1 => LargeMap2, LargeMap2 => LargeMap1, 1612 [LargeMap1,LargeMap2] => LargeMap1, 1613 <<"abc">> => SmallMap, <<"qrs">> => LargeMap1, 1614 <<"xyz">> => LargeMap2 }, 1615 Test_Func(#{}), 1616 Test_Func(SmallMap), 1617 Test_Func(LargeMap1), 1618 Test_Func(LargeMap2), 1619 Test_Func(MapWithMap), 1620 1621 ok. 1622 1623test_floats(Test_Func) -> 1624 Test_Func(5.5), 1625 Test_Func(-15.32), 1626 Test_Func(1.2435e25), 1627 Test_Func(1.2333e-20), 1628 Test_Func(199.0e+15), 1629 ok. 1630 1631very_big_num() -> 1632 very_big_num(33, 1). 1633 1634very_big_num(Left, Result) when Left > 0 -> 1635 very_big_num(Left-1, Result*256); 1636very_big_num(0, Result) -> 1637 Result. 1638 1639make_port() -> 1640 hd(erlang:ports()). 1641 1642make_pid() -> 1643 spawn_link(?MODULE, sleeper, []). 1644 1645sleeper() -> 1646 receive after infinity -> ok end. 1647 1648 1649%% Test that binaries are garbage collected properly. 1650gc_test(Config) when is_list(Config) -> 1651 %% Note: This test is only relevant for REFC binaries. 1652 %% Therefore, we take care that all binaries are REFC binaries. 1653 true = 192 > ?heap_binary_size, 1654 B = list_to_binary(lists:seq(1, 192)), 1655 Self = self(), 1656 F1 = fun() -> 1657 gc(), 1658 {binary,[]} = process_info(self(), binary), 1659 Self ! {self(),done} 1660 end, 1661 F = fun() -> 1662 receive go -> ok end, 1663 {binary,[{_,192,1}]} = process_info(self(), binary), 1664 gc(), 1665 {B1,B2} = my_split_binary(B, 68), 1666 gc(), 1667 gc(), 1668 {binary,L1} = process_info(self(), binary), 1669 [Binfo1,Binfo2,Binfo3] = L1, 1670 {_,192,3} = Binfo1 = Binfo2 = Binfo3, 1671 192 = size(B), 1672 68 = size(B1), 1673 124 = size(B2), 1674 F1() 1675 end, 1676 gc(), 1677 gc(), 1678 192 = size(B), 1679 gc_test1(spawn_opt(erlang, apply, [F,[]], [link,{fullsweep_after,0}])). 1680 1681gc_test1(Pid) -> 1682 gc(), 1683 Pid ! go, 1684 receive 1685 {Pid,done} -> ok 1686 after 10000 -> 1687 ct:fail("timeout") 1688 end. 1689 1690%% Like split binary, but returns REFC binaries. Only useful for gc_test/1. 1691 1692my_split_binary(B, Pos) -> 1693 Self = self(), 1694 Ref = make_ref(), 1695 spawn(fun() -> Self ! {Ref,split_binary(B, Pos)} end), 1696 receive 1697 {Ref,Result} -> Result 1698 end. 1699 1700gc() -> 1701 erlang:garbage_collect(), 1702 gc1(). 1703gc1() -> ok. 1704 1705bit_sized_binary_sizes(Config) when is_list(Config) -> 1706 [bsbs_1(A) || A <- lists:seq(1, 8)], 1707 ok. 1708 1709bsbs_1(A) -> 1710 BinSize = 32+A, 1711 io:format("A: ~p BinSize: ~p", [A,BinSize]), 1712 Bin = binary_to_term_stress(<<131,$M,5:32,A,0,0,0,0,0>>), 1713 BinSize = bit_size(Bin). 1714 1715%% lists:foldl(_,_,lists:seq(_,_)) with less heap consumption 1716lists_foldl_seq(Fun, Acc0, N, To) when N =< To -> 1717 Acc1 = Fun(N, Acc0), 1718 lists_foldl_seq(Fun, Acc1, N+1, To); 1719 1720lists_foldl_seq(_, Acc, _, _) -> 1721 Acc. 1722 1723deep(Config) when is_list(Config) -> 1724 deep_roundtrip(lists_foldl_seq(fun(E, A) -> 1725 [E,A] 1726 end, [], 1, 1000000)), 1727 erlang:garbage_collect(), 1728 deep_roundtrip(lists_foldl_seq(fun(E, A) -> 1729 {E,A} 1730 end, [], 1, 1000000)), 1731 erlang:garbage_collect(), 1732 deep_roundtrip(lists_foldl_seq(fun(E, A) -> 1733 fun() -> {E,A} end 1734 end, [], 1, 1000000)), 1735 erlang:garbage_collect(), 1736 ok. 1737 1738deep_roundtrip(T) -> 1739 B = term_to_binary(T), 1740 T = binary_to_term(B). 1741 1742term2bin_tuple_fallbacks(Config) when is_list(Config) -> 1743 erts_debug:set_internal_state(available_internal_state, true), 1744 1745 term2bin_tf(fun ?MODULE:all/1), 1746 term2bin_tf(<<1:1>>), 1747 term2bin_tf(<<90,80:7>>), 1748 1749 erts_debug:set_internal_state(available_internal_state, false), 1750 ok. 1751 1752term2bin_tf(Term) -> 1753 Tuple = case Term of 1754 Fun when is_function(Fun) -> 1755 {type, external} = erlang:fun_info(Fun, type), 1756 {module,M} = erlang:fun_info(Fun, module), 1757 {name,F} = erlang:fun_info(Fun, name), 1758 {M,F}; 1759 BS when bit_size(BS) rem 8 =/= 0 -> 1760 Bits = bit_size(BS) rem 8, 1761 {<<BS/bitstring, 0:(8-Bits)>>, Bits} 1762 end, 1763 Tuple = binary_to_term_stress(erts_debug:get_internal_state({term_to_binary_tuple_fallbacks,Term})). 1764 1765%% Test non-standard encodings never generated by term_to_binary/1 1766%% but recognized by binary_to_term/1. 1767 1768robustness(Config) when is_list(Config) -> 1769 [] = binary_to_term_stress(<<131,107,0,0>>), %Empty string. 1770 [] = binary_to_term_stress(<<131,108,0,0,0,0,106>>), %Zero-length list. 1771 1772 %% {[],a} where [] is a zero-length list. 1773 {[],a} = binary_to_term_stress(<<131,104,2,108,0,0,0,0,106,100,0,1,97>>), 1774 1775 %% {42,a} where 42 is a zero-length list with 42 in the tail. 1776 {42,a} = binary_to_term_stress(<<131,104,2,108,0,0,0,0,97,42,100,0,1,97>>), 1777 1778 %% {{x,y},a} where {x,y} is a zero-length list with {x,y} in the tail. 1779 {{x,y},a} = binary_to_term_stress(<<131,104,2,108,0,0,0,0, 1780 104,2,100,0,1,120,100,0,1, 1781 121,100,0,1,97>>), 1782 1783 %% Bignums fitting in 32 bits. 1784 16#7FFFFFFF = binary_to_term_stress(<<131,98,127,255,255,255>>), 1785 -1 = binary_to_term_stress(<<131,98,255,255,255,255>>), 1786 1787 ok. 1788 1789%% OTP-8180: Test several terms that have been known to crash the emulator. 1790%% (Thanks to Scott Lystig Fritchie.) 1791otp_8180(Config) when is_list(Config) -> 1792 Data = proplists:get_value(data_dir, Config), 1793 Wc = filename:join(Data, "zzz.*"), 1794 Files = filelib:wildcard(Wc), 1795 [run_otp_8180(F) || F <- Files], 1796 ok. 1797 1798run_otp_8180(Name) -> 1799 io:format("~s", [Name]), 1800 {ok,Bins} = file:consult(Name), 1801 [begin 1802 io:format("~p\n", [Bin]), 1803 {'EXIT',{badarg,_}} = (catch binary_to_term_stress(Bin)) 1804 end || Bin <- Bins], 1805 ok. 1806 1807%% Test that exit and GC during trapping term_to_binary and binary_to_term 1808%% does not crash. 1809trapping(Config) when is_list(Config)-> 1810 do_trapping(5, term_to_binary, 1811 fun() -> [lists:duplicate(2000000,2000000)] end), 1812 do_trapping(5, binary_to_term, 1813 fun() -> [term_to_binary(lists:duplicate(2000000,2000000))] end), 1814 do_trapping(5, binary_to_list, 1815 fun() -> [list_to_binary(lists:duplicate(2000000,$x))] end), 1816 do_trapping(5, list_to_binary, 1817 fun() -> [lists:duplicate(2000000,$x)] end), 1818 do_trapping(5, bitstring_to_list, 1819 fun() -> [list_to_bitstring([lists:duplicate(2000000,$x),<<7:4>>])] end), 1820 do_trapping(5, list_to_bitstring, 1821 fun() -> [[lists:duplicate(2000000,$x),<<7:4>>]] end) 1822 . 1823 1824do_trapping(0, _, _) -> 1825 ok; 1826do_trapping(N, Bif, ArgFun) -> 1827 io:format("N=~p: Do ~p ~s gc.\n", [N, Bif, case N rem 2 of 0 -> "with"; 1 -> "without" end]), 1828 Pid = spawn(?MODULE,trapping_loop,[Bif, ArgFun, 1000, self()]), 1829 receive ok -> ok end, 1830 Ref = make_ref(), 1831 case N rem 2 of 1832 0 -> 1833 erlang:garbage_collect(Pid, [{async,Ref}]), 1834 receive after 1 -> ok end; 1835 1 -> void 1836 end, 1837 exit(Pid, kill), 1838 case N rem 2 of 1839 0 -> 1840 receive {garbage_collect, Ref, _} -> ok end; 1841 1 -> 1842 void 1843 end, 1844 receive after 1 -> ok end, 1845 do_trapping(N-1, Bif, ArgFun). 1846 1847trapping_loop(Bif, ArgFun, N, Pid) -> 1848 Args = ArgFun(), 1849 Pid ! ok, 1850 trapping_loop2(Bif,Args,N). 1851trapping_loop2(_,_,0) -> 1852 ok; 1853trapping_loop2(Bif,Args,N) -> 1854 apply(erlang,Bif,Args), 1855 trapping_loop2(Bif, Args, N-1). 1856 1857large(Config) when is_list(Config) -> 1858 List = lists:flatten(lists:map(fun (_) -> 1859 [0,1,2,3,4,5,6,7,8] 1860 end, 1861 lists:seq(1, 131072))), 1862 Bin = list_to_binary(List), 1863 List = binary_to_list(Bin), 1864 PartList = lists:reverse(tl(tl(lists:reverse(tl(tl(List)))))), 1865 PartList = binary_to_list(Bin, 3, length(List)-2), 1866 ListBS = List ++ [<<7:4>>], 1867 ListBS = bitstring_to_list(list_to_bitstring(ListBS)), 1868 BitStr1 = list_to_bitstring(lists:duplicate(1024*1024, [<<1,5:3>>])), 1869 BitStr1 = list_to_bitstring(bitstring_to_list(BitStr1)), 1870 BitStr2 = list_to_bitstring([lists:duplicate(512*1024, [<<1,5:3>>]), 1871 Bin]), 1872 BitStr2 = list_to_bitstring(bitstring_to_list(BitStr2)), 1873 ok. 1874 1875error_after_yield(Config) when is_list(Config) -> 1876 L2BTrap = {erts_internal, list_to_binary_continue, 1}, 1877 error_after_yield(badarg, erlang, list_to_binary, 1, fun () -> [[mk_list(1000000), oops]] end, L2BTrap), 1878 error_after_yield(badarg, erlang, iolist_to_binary, 1, fun () -> [[list2iolist(mk_list(1000000)), oops]] end, L2BTrap), 1879 error_after_yield(badarg, erlang, list_to_bitstring, 1, fun () -> [[list2bitstrlist(mk_list(1000000)), oops]] end, L2BTrap), 1880 error_after_yield(badarg, binary, list_to_bin, 1, fun () -> [[mk_list(1000000), oops]] end, L2BTrap), 1881 1882 B2TTrap = {erts_internal, binary_to_term_trap, 1}, 1883 1884 error_after_yield(badarg, erlang, binary_to_term, 1, fun () -> [error_after_yield_bad_ext_term()] end, B2TTrap), 1885 error_after_yield(badarg, erlang, binary_to_term, 2, fun () -> [error_after_yield_bad_ext_term(), [safe]] end, B2TTrap), 1886 1887 case erlang:system_info(wordsize) of 1888 4 -> 1889 SysLimitSz = 1 bsl 32, 1890 error_after_yield(system_limit, erlang, list_to_binary, 1, fun () -> [[huge_iolist(SysLimitSz), $x]] end, L2BTrap), 1891 error_after_yield(system_limit, erlang, iolist_to_binary, 1, fun () -> [[huge_iolist(SysLimitSz), $x]] end, L2BTrap), 1892 error_after_yield(system_limit, erlang, list_to_bitstring, 1, fun () -> [[huge_iolist(SysLimitSz), $x]] end, L2BTrap), 1893 error_after_yield(system_limit, binary, list_to_bin, 1, fun () -> [[huge_iolist(SysLimitSz), $x]] end, L2BTrap); 1894 8 -> 1895 % Takes waaaay to long time to test system_limit on 64-bit archs... 1896 ok 1897 end, 1898 ok. 1899 1900error_after_yield(Type, M, F, AN, AFun, TrapFunc) -> 1901 io:format("Testing ~p for ~p:~p/~p~n", [Type, M, F, AN]), 1902 Tracer = self(), 1903 {Pid, Mon} = spawn_monitor(fun () -> 1904 A = AFun(), 1905 try 1906 erlang:yield(), 1907 erlang:trace(self(),true,[running,{tracer,Tracer}]), 1908 apply(M, F, A), 1909 exit({unexpected_success, {M, F, A}}) 1910 catch 1911 error:Type:Stk -> 1912 erlang:trace(self(),false,[running,{tracer,Tracer}]), 1913 %% We threw the exception from the native 1914 %% function we trapped to, but we want 1915 %% the BIF that originally was called 1916 %% to appear in the stack trace. 1917 [{M, F, A, _} | _] = Stk 1918 end 1919 end), 1920 receive 1921 {'DOWN', Mon, process, Pid, Reason} -> 1922 normal = Reason 1923 end, 1924 TD = erlang:trace_delivered(Pid), 1925 receive 1926 {trace_delivered, Pid, TD} -> 1927 NoYields = error_after_yield_sched(Pid, TrapFunc, 0), 1928 io:format("No of yields: ~p~n", [NoYields]), 1929 true = NoYields > 2 1930 end, 1931 ok. 1932 1933error_after_yield_sched(P, TrapFunc, N) -> 1934 receive 1935 {trace, P, out, TrapFunc} -> 1936 receive 1937 {trace, P, in, TrapFunc} -> 1938 error_after_yield_sched(P, TrapFunc, N+1) 1939 after 0 -> 1940 exit(trap_sched_mismatch) 1941 end; 1942 {trace, P, out, Func} -> 1943 receive 1944 {trace, P, in, Func} -> 1945 error_after_yield_sched(P, TrapFunc, N) 1946 after 0 -> 1947 exit(other_sched_mismatch) 1948 end 1949 after 0 -> 1950 N 1951 end. 1952 1953error_after_yield_bad_ext_term() -> 1954 TupleSz = 2000000, 1955 <<131, % Version magic 1956 AtomExt/binary>> = term_to_binary(an_atom_we_use_for_this), 1957 BadAtomExt = [100, %% ATOM_EXT 1958 255, 255, % Invalid size of 65535 bytes 1959 "oops"], 1960 1961 %% Produce a large tuple where the last element is invalid 1962 list_to_binary([131, %% Version magic 1963 105, %% LARGE_TUPLE_EXT 1964 <<TupleSz:32/big>>, %% Tuple size 1965 lists:duplicate(TupleSz-1, AtomExt), %% Valid atoms 1966 BadAtomExt]). %% Invalid atom at the end 1967 1968cmp_old_impl(Config) when is_list(Config) -> 1969 %% This test was originally a comparison with the non yielding 1970 %% implementation in R16B. Since OTP 22 we can't talk distribution with such 1971 %% old nodes (< 19). The test case it kept but compares with previous major 1972 %% version for semantic regression test. 1973 Cookie = atom_to_list(erlang:get_cookie()), 1974 Rel = (integer_to_list(list_to_integer(erlang:system_info(otp_release)) - 1) 1975 ++ "_latest"), 1976 case test_server:is_release_available(Rel) of 1977 false -> 1978 {skipped, "No OTP "++Rel++" available"}; 1979 true -> 1980 {ok, Node} = test_server:start_node(list_to_atom(atom_to_list(?MODULE)++"_"++Rel), 1981 peer, 1982 [{args, " -setcookie "++Cookie}, 1983 {erl, [{release, Rel}]}]), 1984 1985 cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(1))]}), 1986 cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(10))]}), 1987 cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(100))]}), 1988 cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(1000))]}), 1989 cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(10000))]}), 1990 cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(100000))]}), 1991 cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(1000000))]}), 1992 cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list(10000000))]}), 1993 cmp_node(Node, {erlang, list_to_binary, [list2iolist(mk_list_lb(10000000))]}), 1994 1995 cmp_node(Node, {erlang, binary_to_list, [list_to_binary(mk_list(1))]}), 1996 cmp_node(Node, {erlang, binary_to_list, [list_to_binary(mk_list(10))]}), 1997 cmp_node(Node, {erlang, binary_to_list, [list_to_binary(mk_list(100))]}), 1998 cmp_node(Node, {erlang, binary_to_list, [list_to_binary(mk_list(1000))]}), 1999 cmp_node(Node, {erlang, binary_to_list, [list_to_binary(mk_list(10000))]}), 2000 cmp_node(Node, {erlang, binary_to_list, [list_to_binary(mk_list(100000))]}), 2001 cmp_node(Node, {erlang, binary_to_list, [list_to_binary(mk_list(1000000))]}), 2002 cmp_node(Node, {erlang, binary_to_list, [list_to_binary(mk_list(10000000))]}), 2003 2004 cmp_node(Node, {erlang, list_to_bitstring, [list2bitstrlist(mk_list(1))]}), 2005 cmp_node(Node, {erlang, list_to_bitstring, [list2bitstrlist(mk_list(10))]}), 2006 cmp_node(Node, {erlang, list_to_bitstring, [list2bitstrlist(mk_list(100))]}), 2007 cmp_node(Node, {erlang, list_to_bitstring, [list2bitstrlist(mk_list(1000))]}), 2008 cmp_node(Node, {erlang, list_to_bitstring, [list2bitstrlist(mk_list(10000))]}), 2009 cmp_node(Node, {erlang, list_to_bitstring, [list2bitstrlist(mk_list(100000))]}), 2010 cmp_node(Node, {erlang, list_to_bitstring, [list2bitstrlist(mk_list(1000000))]}), 2011 cmp_node(Node, {erlang, list_to_bitstring, [list2bitstrlist(mk_list(10000000))]}), 2012 2013 cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(1)))]}), 2014 cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(10)))]}), 2015 cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(100)))]}), 2016 cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(1000)))]}), 2017 cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(10000)))]}), 2018 cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(100000)))]}), 2019 cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(1000000)))]}), 2020 cmp_node(Node, {erlang, bitstring_to_list, [list_to_bitstring(list2bitstrlist(mk_list(10000000)))]}), 2021 2022 test_server:stop_node(Node), 2023 2024 ok 2025 end. 2026 2027%% OTP-16265 2028%% This testcase is mainly targeted toward --enable-sharing-preserving. 2029sub_bin_copy(Config) when is_list(Config) -> 2030 Papa = self(), 2031 Echo = spawn_link(fun() -> echo(Papa) end), 2032 HeapBin = list_to_binary(lists:seq(1,3)), 2033 sub_bin_copy_1(HeapBin, Echo), 2034 ProcBin = list_to_binary(lists:seq(1,65)), 2035 sub_bin_copy_1(ProcBin, Echo), 2036 unlink(Echo), 2037 exit(Echo, kill), 2038 ok. 2039 2040sub_bin_copy_1(RealBin, Echo) -> 2041 Bits = bit_size(RealBin) - 1, 2042 <<SubBin:Bits/bits, _/bits>> = RealBin, 2043 2044 %% Send (copy) messages consisting of combinations of both 2045 %% the SubBin and the RealBin it refers to. 2046 [begin 2047 Echo ! Combo, 2048 {_, Combo} = {Combo, receive M -> M end} 2049 end 2050 || Len <- lists:seq(2,5), Combo <- combos([RealBin, SubBin], Len)], 2051 ok. 2052 2053combos(_, 0) -> 2054 [[]]; 2055combos(Elements, Len) -> 2056 [[E | C] || E <- Elements, C <- combos(Elements,Len-1)]. 2057 2058echo(Papa) -> 2059 receive M -> Papa ! M end, 2060 echo(Papa). 2061 2062 2063%% Utilities. 2064 2065huge_iolist(Lim) -> 2066 Sz = 1024, 2067 huge_iolist(list_to_binary(mk_list(Sz)), Sz, Lim). 2068 2069huge_iolist(X, Sz, Lim) when Sz >= Lim -> 2070 X; 2071huge_iolist(X, Sz, Lim) -> 2072 huge_iolist([X, X], Sz*2, Lim). 2073 2074cmp_node(Node, {M, F, A}) -> 2075 ResN = rpc:call(Node, M, F, A), 2076 Res = apply(M, F, A), 2077 case ResN =:= Res of 2078 true -> 2079 ok; 2080 false -> 2081 io:format("~p: ~p~n~p: ~p~n", 2082 [Node, ResN, node(), Res]), 2083 ct:fail(different_results) 2084 end. 2085 2086make_sub_binary(Bin) when is_binary(Bin) -> 2087 {_,B} = split_binary(list_to_binary([0,1,3,Bin]), 3), 2088 B; 2089make_sub_binary(List) -> 2090 make_sub_binary(list_to_binary(List)). 2091 2092make_unaligned_sub_binary(Bin0) when is_binary(Bin0) -> 2093 Bin1 = <<0:3,Bin0/binary,31:5>>, 2094 Sz = size(Bin0), 2095 <<0:3,Bin:Sz/binary,31:5>> = id(Bin1), 2096 Bin; 2097make_unaligned_sub_binary(List) -> 2098 make_unaligned_sub_binary(list_to_binary(List)). 2099 2100%% Add 1 bit to the size of the binary. 2101bit_sized_binary(Bin0) -> 2102 Bin = <<Bin0/binary,1:1>>, 2103 BitSize = bit_size(Bin), 2104 BitSize = 8*size(Bin) + 1, 2105 Bin. 2106 2107unaligned_sub_bin(Bin, 0) -> Bin; 2108unaligned_sub_bin(Bin0, Offs) -> 2109 F = rand:uniform(256), 2110 Roffs = 8-Offs, 2111 Bin1 = <<F:Offs,Bin0/binary,F:Roffs>>, 2112 Sz = size(Bin0), 2113 <<_:Offs,Bin:Sz/binary,_:Roffs>> = id(Bin1), 2114 Bin. 2115 2116id(I) -> I. 2117 2118 2119%% Stress binary_to_term with different initial reductions 2120binary_to_term_stress(Bin) -> 2121 binary_to_term_stress(Bin, no_opts). 2122 2123binary_to_term_stress(Bin, Opts) -> 2124 Reds = get_reds(), 2125 T = b2t(erlang:system_info(context_reductions), 2126 Bin, Opts, catch_binary_to_term(Bin, Opts)), 2127 set_reds(Reds), 2128 T = case Opts of 2129 no_opts -> binary_to_term(Bin); 2130 _ -> binary_to_term(Bin,Opts) 2131 end. 2132 2133catch_binary_to_term(Bin, no_opts) -> 2134 try binary_to_term(Bin) 2135 catch 2136 error:badarg -> binary_to_term_throws_badarg 2137 end; 2138catch_binary_to_term(Bin, Opts) -> 2139 try binary_to_term(Bin, Opts) 2140 catch 2141 error:badarg -> binary_to_term_throws_badarg 2142 end. 2143 2144b2t(0, _Bin, _Opts, Term) -> 2145 Term; 2146b2t(Reds, Bin, Opts, Term) -> 2147 set_reds(Reds), 2148 Term = catch_binary_to_term(Bin,Opts), 2149 b2t(Reds div 3, Bin, Opts, Term). 2150 2151set_reds(Reds) -> 2152 try erts_debug:set_internal_state(reds_left, Reds) 2153 catch 2154 error:undef -> 2155 erts_debug:set_internal_state(available_internal_state, true), 2156 set_reds(Reds) 2157 end. 2158 2159get_reds() -> 2160 try erts_debug:get_internal_state(reds_left) 2161 catch 2162 error:undef -> 2163 erts_debug:set_internal_state(available_internal_state, true), 2164 get_reds() 2165 end. 2166 2167-define(LARGE_BIN, (512*1024+10)). 2168-define(LARGE_BIN_LIM, (1024*1024)). 2169 2170mk_list(0, Acc) -> 2171 Acc; 2172mk_list(Sz, Acc) -> 2173 mk_list(Sz-1, [$A+(Sz band 63) | Acc]). 2174 2175mk_list(Sz) when Sz >= ?LARGE_BIN_LIM -> 2176 SzLeft = Sz - ?LARGE_BIN, 2177 SzHd = SzLeft div 2, 2178 SzTl = SzLeft - SzHd, 2179 [mk_list(SzHd, []), erlang:list_to_binary(mk_list(?LARGE_BIN, [])), mk_list(SzTl, [])]; 2180mk_list(Sz) -> 2181 mk_list(Sz, []). 2182 2183mk_list_lb(Sz) when Sz >= ?LARGE_BIN_LIM -> 2184 SzLeft = Sz - ?LARGE_BIN, 2185 SzHd = SzLeft div 2, 2186 SzTl = SzLeft - SzHd, 2187 [mk_list(SzHd, []), erlang:list_to_binary(mk_list(?LARGE_BIN, [])), mk_list(SzTl, [])]; 2188mk_list_lb(Sz) -> 2189 mk_list(Sz, []). 2190 2191 2192list2iolist(List) -> 2193 list2iolist(List, []). 2194 2195list2iolist([], Acc) -> 2196 Acc; 2197list2iolist([X0, X1, X2, X3, X4, X5 | Xs], Acc) when is_integer(X0), 0 =< X0, X0 < 256, 2198 is_integer(X1), 0 =< X1, X1 < 256, 2199 is_integer(X2), 0 =< X2, X2 < 256, 2200 is_integer(X3), 0 =< X3, X3 < 256, 2201 is_integer(X4), 0 =< X4, X4 < 256, 2202 is_integer(X5), 0 =< X5, X5 < 256 -> 2203 NewAcc = case (X0+X1+X2+X3+X4+X5) band 3 of 2204 0 -> 2205 [Acc, [[[[[[[[[[[[X0,[],<<"">>,X1]]]]]]]]],[X2,X3]],[],[],[],[],X4],X5]]; 2206 1 -> 2207 [Acc, [], erlang:list_to_binary([X0, X1, X2, X3, X4, X5])]; 2208 2 -> 2209 [Acc, [[[[X0|erlang:list_to_binary([X1])],[X2|erlang:list_to_binary([X3])],[X4|erlang:list_to_binary([X5])]]]|<<"">>]]; 2210 3 -> 2211 [Acc, X0, X1, X2, <<"">>, [], X3, X4 | erlang:list_to_binary([X5])] 2212 end, 2213 list2iolist(Xs, NewAcc); 2214list2iolist([X | Xs], Acc) -> 2215 list2iolist(Xs, [Acc,X]). 2216 2217list2bitstrlist(List) -> 2218 [list2bitstrlist(List, []), <<4:7>>]. 2219 2220list2bitstrlist([], Acc) -> 2221 Acc; 2222list2bitstrlist([X0, X1, X2, X3, X4, X5 | Xs], Acc) when is_integer(X0), 0 =< X0, X0 < 256, 2223 is_integer(X1), 0 =< X1, X1 < 256, 2224 is_integer(X2), 0 =< X2, X2 < 256, 2225 is_integer(X3), 0 =< X3, X3 < 256, 2226 is_integer(X4), 0 =< X4, X4 < 256, 2227 is_integer(X5), 0 =< X5, X5 < 256 -> 2228 NewAcc = case (X0+X1+X2+X3+X4+X5) band 3 of 2229 0 -> 2230 [Acc, [[[[[[[[[[[[X0,[],<<"">>,X1]]]]]]]]],[X2,X3]],[],[],[],[],X4],X5]]; 2231 1 -> 2232 [Acc, [], <<X0:X1>>, <<X2:X3>>, <<X4:X5>>]; 2233 2 -> 2234 [Acc, [[[[X0|<<X1:X2>>],X3]],[X4|erlang:list_to_binary([X5])]|<<"">>]]; 2235 3 -> 2236 [Acc, X0, X1, X2, <<"">>, [], X3, X4 | erlang:list_to_binary([X5])] 2237 end, 2238 list2bitstrlist(Xs, NewAcc); 2239list2bitstrlist([X | Xs], Acc) -> 2240 list2bitstrlist(Xs, [Acc,X]). 2241