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