1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1999-2012. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: %% Purpose : Common utilities used by several optimization passes. 20: %% 21: 22: -module(bs_construct_no_opt_SUITE). 23: 24: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 25: init_per_group/2,end_per_group/2, 26: test1/1, test2/1, test3/1, test4/1, test5/1, testf/1, 27: not_used/1, in_guard/1, 28: mem_leak/1, coerce_to_float/1, bjorn/1, 29: huge_float_field/1, huge_binary/1, system_limit/1, badarg/1, 30: copy_writable_binary/1, kostis/1, dynamic/1, bs_add/1, 31: otp_7422/1, zero_width/1, bad_append/1]). 32: 33: -include_lib("test_server/include/test_server.hrl"). 34: 35: suite() -> [{ct_hooks,[ts_install_cth]}]. 36: 37: all() -> 38: [test1, test2, test3, test4, test5, testf, not_used, 39: in_guard, mem_leak, coerce_to_float, bjorn, 40: huge_float_field, huge_binary, system_limit, badarg, 41: copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width, 42: bad_append]. 43: 44: groups() -> 45: []. 46: 47: init_per_suite(Config) -> 48: Config. 49: 50: end_per_suite(_Config) -> 51: ok. 52: 53: init_per_group(_GroupName, Config) -> 54: Config. 55: 56: end_per_group(_GroupName, Config) -> 57: Config. 58: 59: big(1) -> 60: 57285702734876389752897683. 61: 62: i(X) -> X. 63: 64: r(L) -> 65: lists:reverse(L). 66: 67: -define(T(B, L), {B, ??B, L}). 68: -define(N(B), {B, ??B, unknown}). 69: 70: -define(FAIL(Expr), ?line fail_check(catch Expr, ??Expr, [])). 71: 72: -define(FAIL_VARS(Expr, Vars), ?line fail_check(catch Expr, ??Expr, Vars)). 73: 74: l(I_13, I_big1) -> 75: [ 76: ?T(<<-43>>, 77: [256-43]), 78: ?T(<<56>>, 79: [56]), 80: ?T(<<1,2>>, 81: [1, 2]), 82: ?T(<<4:4, 7:4>>, 83: [4*16+7]), 84: ?T(<<777:16/big>>, 85: [3, 9]), 86: ?T(<<777:16/little>>, 87: [9, 3]), 88: ?T(<<0.0:32/float>>, 89: [0,0,0,0]), 90: ?T(<<0.125:32/float>>, 91: [62,0,0,0]), 92: ?T(<<0.125:32/little-float>>, 93: [0,0,0,62]), 94: ?T(<<I_big1:32>>, 95: [138, 99, 0, 147]), 96: ?T(<<57285702734876389752897684:32>>, 97: [138, 99, 0, 148]), 98: ?T(<<I_big1:32/little>>, 99: r([138, 99, 0, 147])), 100: ?T(<<-1:17/unit:8>>, 101: lists:duplicate(17, 255)), 102: 103: ?T(<<I_13>>, 104: [13]), 105: 106: ?T(<<4:8/unit:2,5:2/unit:8>>, 107: [0, 4, 0, 5]), 108: 109: ?T(<<1:1, 0:6, 1:1>>, 110: [129]), 111: ?T(<<1:1/little, 0:6/little, 1:1/little>>, 112: [129]), 113: 114: ?T(<<<<1,2>>/binary>>, 115: [1, 2]), 116: ?T(<<<<1,2>>:1/binary>>, 117: [1]), 118: ?T(<<4,3,<<1,2>>:1/binary>>, 119: [4,3,1]), 120: 121: ?T(<<(256*45+47)>>, 122: [47]), 123: 124: ?T(<<57:0>>, 125: []), 126: 127: ?T(<<"apa">>, 128: "apa"), 129: 130: ?T(<<1:3,"string",9:5>>, 131: [46,110,142,77,45,204,233]), 132: 133: ?T(<<>>, 134: []), 135: 136: ?T(<<37.98:64/native-float>>, 137: native_3798()), 138: 139: ?T(<<32978297842987249827298387697777669766334937:128/native-integer>>, 140: native_bignum()), 141: 142: %% Unit tests. 143: ?T(<<<<5:3>>/bitstring>>, <<5:3>>), 144: ?T(<<42,<<7:4>>/binary-unit:4>>, <<42,7:4>>), 145: ?T(<<<<344:17>>/binary-unit:17>>, <<344:17>>), 146: ?T(<<<<42,3,7656:16>>/binary-unit:16>>, <<42,3,7656:16>>) 147: 148: ]. 149: 150: native_3798() -> 151: case <<1:16/native>> of 152: <<0,1>> -> [64,66,253,112,163,215,10,61]; 153: <<1,0>> -> [61,10,215,163,112,253,66,64] 154: end. 155: 156: native_bignum() -> 157: case <<1:16/native>> of 158: <<0,1>> -> [129,205,18,177,1,213,170,101,39,231,109,128,176,11,73,217]; 159: <<1,0>> -> [217,73,11,176,128,109,231,39,101,170,213,1,177,18,205,129] 160: end. 161: 162: evaluate(Str, Vars) -> 163: {ok,Tokens,_} = 164: erl_scan:string(Str ++ " . "), 165: {ok, [Expr]} = erl_parse:parse_exprs(Tokens), 166: case erl_eval:expr(Expr, Vars) of 167: {value, Result, _} -> 168: Result 169: end. 170: 171: eval_list([], _Vars) -> 172: []; 173: eval_list([{C_bin, Str, Bytes} | Rest], Vars) -> 174: case catch evaluate(Str, Vars) of 175: {'EXIT', Error} -> 176: io:format("Evaluation error: ~p, ~p, ~p~n", [Str, Vars, Error]), 177: exit(Error); 178: E_bin -> 179: [{C_bin, E_bin, Str, Bytes} | eval_list(Rest, Vars)] 180: end. 181: 182: one_test({C_bin, E_bin, Str, Bytes}) when is_list(Bytes) -> 183: io:format(" ~s, ~p~n", [Str, Bytes]), 184: Bin = list_to_binary(Bytes), 185: if 186: C_bin == Bin -> 187: ok; 188: true -> 189: io:format("ERROR: Compiled: ~p. Expected ~p. Got ~p.~n", 190: [Str, Bytes, binary_to_list(C_bin)]), 191: test_server:fail(comp) 192: end, 193: if 194: E_bin == Bin -> 195: ok; 196: true -> 197: io:format("ERROR: Interpreted: ~p. Expected ~p. Got ~p.~n", 198: [Str, Bytes, binary_to_list(E_bin)]), 199: test_server:fail(comp) 200: end; 201: one_test({C_bin, E_bin, Str, Result}) -> 202: io:format(" ~s ~p~n", [Str, C_bin]), 203: if 204: C_bin == E_bin -> 205: ok; 206: true -> 207: Arbitrary = case Result of 208: unknown -> 209: size(C_bin); 210: _ -> 211: Result 212: end, 213: case equal_lists(binary_to_list(C_bin), 214: binary_to_list(E_bin), 215: Arbitrary) of 216: false -> 217: io:format("ERROR: Compiled not equal to interpreted:" 218: "~n ~p, ~p.~n", 219: [binary_to_list(C_bin), binary_to_list(E_bin)]), 220: test_server:fail(comp); 221: 0 -> 222: ok; 223: %% For situations where the final bits may not matter, like 224: %% for floats: 225: N when is_integer(N) -> 226: io:format("Info: compiled and interpreted differ in the" 227: " last bytes:~n ~p, ~p.~n", 228: [binary_to_list(C_bin), binary_to_list(E_bin)]), 229: ok 230: end 231: end. 232: 233: equal_lists([], [], _) -> 234: 0; 235: equal_lists([], _, _) -> 236: false; 237: equal_lists(_, [], _) -> 238: false; 239: equal_lists([A|AR], [A|BR], R) -> 240: equal_lists(AR, BR, R); 241: equal_lists(A, B, R) -> 242: if 243: length(A) /= length(B) -> 244: false; 245: length(A) =< R -> 246: R; 247: true -> 248: false 249: end. 250: 251: fail_check({'EXIT',{badarg,_}}, Str, Vars) -> 252: try evaluate(Str, Vars) of 253: Res -> 254: io:format("Interpreted result: ~p", [Res]), 255: ?t:fail(did_not_fail_in_intepreted_code) 256: catch 257: error:badarg -> 258: ok 259: end; 260: fail_check(Res, _, _) -> 261: io:format("Compiled result: ~p", [Res]), 262: ?t:fail(did_not_fail_in_compiled_code). 263: 264: %%% Simple working cases 265: test1(suite) -> []; 266: test1(Config) when is_list(Config) -> 267: ?line I_13 = i(13), 268: ?line I_big1 = big(1), 269: ?line Vars = [{'I_13', I_13}, 270: {'I_big1', I_big1}], 271: ?line lists:foreach(fun one_test/1, eval_list(l(I_13, I_big1), Vars)). 272: 273: %%% Misc 274: 275: %%% <<A:S, A:(N-S)>> 276: comp(N, A, S) -> 277: M1 = (1 bsl S) - 1, 278: M2 = (1 bsl (N-S)) - 1, 279: [((A band M1) bsl (N-S)) bor (A band M2)]. 280: 281: gen(N, S, A) -> 282: [?T(<<A:S, A:(N-S)>>, comp(N, A, S))]. 283: 284: gen_l(N, S, A) -> 285: [?T(<<A:S/little, A:(N-S)/little>>, comp(N, A, S))]. 286: 287: test2(suite) -> []; 288: test2(Config) when is_list(Config) -> 289: ?line test2(0, 8, 2#10101010101010101), 290: ?line test2(0, 8, 2#1111111111). 291: 292: test2(End, End, _) -> 293: ok; 294: test2(I, End, A) -> 295: test2(I, A), 296: test2(I+1, End, A). 297: 298: test2(S, A) -> 299: N = 8, 300: Vars = [{'A',A}, {'N',N}, {'S',S}], 301: io:format("Vars: ~p\n", [Vars]), 302: lists:foreach(fun one_test/1, eval_list(gen(N, S, A), Vars)), 303: lists:foreach(fun one_test/1, eval_list(gen_l(N, S, A), Vars)). 304: 305: %%% Tests without facit 306: 307: t3() -> 308: [?N(<<4711:13, 9876:13, 3:6>>), 309: ?N(<<4.57:64/float>>), 310: ?N(<<4.57:32/float>>), 311: 312: ?N(<<>>) 313: ]. 314: 315: test3(suite) -> []; 316: test3(Config) when is_list(Config) -> 317: ?line Vars = [], 318: ?line lists:foreach(fun one_test/1, eval_list(t3(), Vars)). 319: 320: gen_u(N, S, A) -> 321: [?N(<<A:S, A:(N-S)>>)]. 322: 323: gen_u_l(N, S, A) -> 324: [?N(<<A:S/little, A:(N-S)/little>>)]. 325: 326: test4(suite) -> []; 327: test4(Config) when is_list(Config) -> 328: ?line test4(0, 16, 2#10101010101010101), 329: ?line test4(0, 16, 2#1111111111). 330: 331: test4(End, End, _) -> 332: ok; 333: test4(I, End, A) -> 334: test4(I, A), 335: test4(I+1, End, A). 336: 337: test4(S, A) -> 338: N = 16, 339: Vars = [{'A', A}, {'N', 16}, {'S', S}], 340: lists:foreach(fun one_test/1, eval_list(gen_u(N, S, A), Vars)), 341: lists:foreach(fun one_test/1, eval_list(gen_u_l(N, S, A), Vars)). 342: 343: gen_b(N, S, A) -> 344: [?T(<<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>, 345: binary_to_list(<<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>))]. 346: 347: test5(suite) -> []; 348: test5(doc) -> ["OTP-3995"]; 349: test5(Config) when is_list(Config) -> 350: ?line test5(0, 8, <<73>>), 351: ?line test5(0, 8, <<68>>). 352: 353: test5(End, End, _) -> 354: ok; 355: test5(I, End, A) -> 356: test5(I, A), 357: test5(I+1, End, A). 358: 359: test5(S, A) -> 360: N = 8, 361: Vars = [{'A', A}, {'N', 8}, {'S', S}], 362: lists:foreach(fun one_test/1, eval_list(gen_b(N, S, A), Vars)). 363: 364: %%% Failure cases 365: testf(suite) -> []; 366: testf(Config) when is_list(Config) -> 367: ?line ?FAIL(<<3.14>>), 368: ?line ?FAIL(<<<<1,2>>>>), 369: 370: ?line ?FAIL(<<2.71/binary>>), 371: ?line ?FAIL(<<24334/binary>>), 372: ?line ?FAIL(<<24334344294788947129487129487219847/binary>>), 373: BigInt = id(24334344294788947129487129487219847), 374: ?line ?FAIL_VARS(<<BigInt/binary>>, [{'BigInt',BigInt}]), 375: ?line ?FAIL_VARS(<<42,BigInt/binary>>, [{'BigInt',BigInt}]), 376: ?line ?FAIL_VARS(<<BigInt:2/binary>>, [{'BigInt',BigInt}]), 377: 378: %% One negative field size, but the sum of field sizes will be 1 byte. 379: %% Make sure that we reject that properly. 380: I_minus_777 = id(-777), 381: I_minus_2047 = id(-2047), 382: ?line ?FAIL_VARS(<<I_minus_777:2048/unit:8,57:I_minus_2047/unit:8>>, 383: ordsets:from_list([{'I_minus_777',I_minus_777}, 384: {'I_minus_2047',I_minus_2047}])), 385: ?line ?FAIL(<<<<1,2,3>>/float>>), 386: 387: %% Negative field widths. 388: ?line testf_1(-8, <<1,2,3,4,5>>), 389: ?line ?FAIL(<<0:(-(1 bsl 100))>>), 390: 391: ?line ?FAIL(<<42:(-16)>>), 392: ?line ?FAIL(<<3.14:(-8)/float>>), 393: ?line ?FAIL(<<<<23,56,0,2>>:(-16)/binary>>), 394: ?line ?FAIL(<<<<23,56,0,2>>:(2.5)/binary>>), 395: ?line ?FAIL(<<<<23,56,0,2>>:(anka)>>), 396: ?line ?FAIL(<<<<23,56,0,2>>:(anka)>>), 397: 398: %% Unit failures. 399: ?line ?FAIL(<<<<1:1>>/binary>>), 400: Sz = id(1), 401: ?line ?FAIL_VARS(<<<<1:Sz>>/binary>>, [{'Sz',Sz}]), 402: ?line {'EXIT',{badarg,_}} = (catch <<<<1:(id(1))>>/binary>>), 403: ?line ?FAIL(<<<<7,8,9>>/binary-unit:16>>), 404: ?line ?FAIL(<<<<7,8,9,3:7>>/binary-unit:16>>), 405: ?line ?FAIL(<<<<7,8,9,3:7>>/binary-unit:17>>), 406: 407: ok. 408: 409: testf_1(W, B) -> 410: Vars = [{'W',W}], 411: ?FAIL_VARS(<<42:W>>, Vars), 412: ?FAIL_VARS(<<3.14:W/float>>, Vars), 413: ?FAIL_VARS(<<B:W/binary>>, [{'B',B}|Vars]). 414: 415: not_used(doc) -> 416: "Test that constructed binaries that are not used will still give an exception."; 417: not_used(Config) when is_list(Config) -> 418: ?line ok = not_used1(3, <<"dum">>), 419: ?line {'EXIT',{badarg,_}} = (catch not_used1(3, "dum")), 420: ?line {'EXIT',{badarg,_}} = (catch not_used2(444, -2)), 421: ?line {'EXIT',{badarg,_}} = (catch not_used2(444, anka)), 422: ?line {'EXIT',{badarg,_}} = (catch not_used3(444)), 423: ok. 424: 425: not_used1(I, BinString) -> 426: <<I:32,BinString/binary>>, 427: ok. 428: 429: not_used2(I, Sz) -> 430: <<I:Sz>>, 431: ok. 432: 433: not_used3(I) -> 434: <<I:(-8)>>, 435: ok. 436: 437: in_guard(Config) when is_list(Config) -> 438: ?line 1 = in_guard(<<16#74ad:16>>, 16#e95, 5), 439: ?line 2 = in_guard(<<16#3A,16#F7,"hello">>, 16#3AF7, <<"hello">>), 440: ?line 3 = in_guard(<<16#FBCD:14,3.1415/float,3:2>>, 16#FBCD, 3.1415), 441: ?line 3 = in_guard(<<16#FBCD:14,3/float,3:2>>, 16#FBCD, 3), 442: ?line 3 = in_guard(<<16#FBCD:14,(2 bsl 226)/float,3:2>>, 16#FBCD, 2 bsl 226), 443: nope = in_guard(<<1>>, 42, b), 444: nope = in_guard(<<1>>, a, b), 445: nope = in_guard(<<1,2>>, 1, 1), 446: nope = in_guard(<<4,5>>, 1, 2.71), 447: nope = in_guard(<<4,5>>, 1, <<12,13>>), 448: ok. 449: 450: in_guard(Bin, A, B) when <<A:13,B:3>> == Bin -> 1; 451: in_guard(Bin, A, B) when <<A:16,B/binary>> == Bin -> 2; 452: in_guard(Bin, A, B) when <<A:14,B/float,3:2>> == Bin -> 3; 453: in_guard(Bin, A, B) when {a,b,<<A:14,B/float,3:2>>} == Bin -> cant_happen; 454: in_guard(_, _, _) -> nope. 455: 456: mem_leak(doc) -> "Make sure that construction has no memory leak"; 457: mem_leak(Config) when is_list(Config) -> 458: ?line B = make_bin(16, <<0>>), 459: ?line mem_leak(1024, B), 460: ok. 461: 462: mem_leak(0, _) -> ok; 463: mem_leak(N, B) -> 464: ?line big_bin(B, <<23>>), 465: ?line {'EXIT',{badarg,_}} = (catch big_bin(B, bad)), 466: mem_leak(N-1, B). 467: 468: big_bin(B1, B2) -> 469: <<B1/binary,B1/binary,B1/binary,B1/binary, 470: B1/binary,B1/binary,B1/binary,B1/binary, 471: B1/binary,B1/binary,B1/binary,B1/binary, 472: B1/binary,B1/binary,B1/binary,B1/binary, 473: B2/binary>>. 474: 475: make_bin(0, Acc) -> Acc; 476: make_bin(N, Acc) -> make_bin(N-1, <<Acc/binary,Acc/binary>>). 477: 478: -define(COF(Int0), 479: ?line (fun(Int) -> 480: true = <<Int:32/float>> =:= <<(float(Int)):32/float>>, 481: true = <<Int:64/float>> =:= <<(float(Int)):64/float>> 482: end)(nonliteral(Int0)), 483: ?line true = <<Int0:32/float>> =:= <<(float(Int0)):32/float>>, 484: ?line true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>). 485: 486: -define(COF64(Int0), 487: ?line (fun(Int) -> 488: true = <<Int:64/float>> =:= <<(float(Int)):64/float>> 489: end)(nonliteral(Int0)), 490: ?line true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>). 491: 492: nonliteral(X) -> X. 493: 494: coerce_to_float(Config) when is_list(Config) -> 495: ?COF(0), 496: ?COF(-1), 497: ?COF(1), 498: ?COF(42), 499: ?COF(255), 500: ?COF(-255), 501: ?COF(38474), 502: ?COF(387498738948729893849444444443), 503: ?COF(-37489378937773899999999999999993), 504: ?COF64(298748888888888888888888888883478264866528467367364766666666666666663), 505: ?COF64(-367546729879999999999947826486652846736736476555566666663), 506: ok. 507: 508: bjorn(Config) when is_list(Config) -> 509: ?line error = bjorn_1(), 510: ok. 511: 512: bjorn_1() -> 513: Bitstr = <<7:13>>, 514: try 515: do_something() 516: catch 517: throw:blurf -> 518: ignore 519: end, 520: do_more(Bitstr, 13). 521: 522: do_more(Bin, Sz) -> 523: %% Previous bug in the bs_bits_to_bytes instruction: The exeption code 524: %% was not set - the previous exception (throw:blurf) would be used, 525: %% causing the catch to slip. 526: try <<Bin:Sz/binary>> of 527: _V -> ok 528: catch 529: error:_ -> 530: error 531: end. 532: 533: do_something() -> 534: throw(blurf). 535: 536: huge_float_field(Config) when is_list(Config) -> 537: ?line {'EXIT',{badarg,_}} = (catch <<0.0:9/float-unit:8>>), 538: ?line huge_float_check(catch <<0.0:67108865/float-unit:64>>), 539: ?line huge_float_check(catch <<0.0:((1 bsl 26)+1)/float-unit:64>>), 540: ?line huge_float_check(catch <<0.0:(id(67108865))/float-unit:64>>), 541: %% ?line huge_float_check(catch <<0.0:((1 bsl 60)+1)/float-unit:64>>), 542: ?line huge_float_check(catch <<3839739387439387383739387987347983:((1 bsl 26)+1)/float-unit:64>>), 543: %% ?line huge_float_check(catch <<3839739387439387383739387987347983:((1 bsl 60)+1)/float-unit:64>>), 544: ok. 545: 546: huge_float_check({'EXIT',{system_limit,_}}) -> ok; 547: huge_float_check({'EXIT',{badarg,_}}) -> ok. 548: 549: huge_binary(Config) when is_list(Config) -> 550: ?line 16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>), 551: ?line garbage_collect(), 552: {Shift,Return} = case free_mem() of 553: undefined -> {32,ok}; 554: Mb when Mb > 600 -> {32,ok}; 555: Mb when Mb > 300 -> {31,"Limit huge binaries to 256 Mb"}; 556: _ -> {30,"Limit huge binary to 128 Mb"} 557: end, 558: ?line garbage_collect(), 559: ?line id(<<0:((1 bsl Shift)-1)>>), 560: ?line garbage_collect(), 561: ?line id(<<0:(id((1 bsl Shift)-1))>>), 562: ?line garbage_collect(), 563: case Return of 564: ok -> ok; 565: Comment -> {comment, Comment} 566: end. 567: 568: free_mem() -> 569: Cmd = "uname; free", 570: Output = string:tokens(os:cmd(Cmd), "\n"), 571: io:format("Output from command ~p\n~p\n",[Cmd,Output]), 572: case Output of 573: [OS, ColumnNames, Values | _] -> 574: case string:str(OS,"Linux") of 575: 0 -> 576: io:format("Unknown OS\n",[]), 577: undefined; 578: _ -> 579: case {string:tokens(ColumnNames, " \t"), 580: string:tokens(Values, " \t")} of 581: {[_,_,"free"|_],["Mem:",_,_,FreeKb|_]} -> 582: list_to_integer(FreeKb) div 1024; 583: _ -> 584: io:format("Failed to parse output from 'free':\n",[]), 585: undefined 586: end 587: end; 588: _ -> 589: io:format("Too few lines in output\n",[]), 590: undefined 591: end. 592: 593: 594: system_limit(Config) when is_list(Config) -> 595: WordSize = erlang:system_info(wordsize), 596: BitsPerWord = WordSize * 8, 597: ?line {'EXIT',{system_limit,_}} = 598: (catch <<0:(id(0)),42:(id(1 bsl BitsPerWord))>>), 599: ?line {'EXIT',{system_limit,_}} = 600: (catch <<42:(id(1 bsl BitsPerWord)),0:(id(0))>>), 601: ?line {'EXIT',{system_limit,_}} = 602: (catch <<(id(<<>>))/binary,0:(id(1 bsl 100))>>), 603: 604: %% Would fail to load. 605: ?line {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 67)>>), 606: ?line {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 64)+1)>>), 607: 608: case WordSize of 609: 4 -> 610: system_limit_32(); 611: 8 -> 612: ok 613: end. 614: 615: system_limit_32() -> 616: ?line {'EXIT',{badarg,_}} = (catch <<42:(-1)>>), 617: ?line {'EXIT',{badarg,_}} = (catch <<42:(id(-1))>>), 618: ?line {'EXIT',{badarg,_}} = (catch <<42:(id(-389739873536870912))/unit:8>>), 619: ?line {'EXIT',{system_limit,_}} = (catch <<42:536870912/unit:8>>), 620: ?line {'EXIT',{system_limit,_}} = (catch <<42:(id(536870912))/unit:8>>), 621: ?line {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:536870912/unit:8>>), 622: ?line {'EXIT',{system_limit,_}} = 623: (catch <<0:(id(8)),42:(id(536870912))/unit:8>>), 624: 625: %% The size would be silently truncated, resulting in a crash. 626: ?line {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 35)>>), 627: ?line {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 32)+1)>>), 628: 629: %% Would fail to load. 630: ?line {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 43)>>), 631: ?line {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 40)+1)>>), 632: ok. 633: 634: badarg(Config) when is_list(Config) -> 635: ?line {'EXIT',{badarg,_}} = 636: (catch <<0:(id(1 bsl 100)),0:(id(-1))>>), 637: ?line {'EXIT',{badarg,_}} = 638: (catch <<0:(id(1 bsl 100)),0:(id(-(1 bsl 70)))>>), 639: ?line {'EXIT',{badarg,_}} = 640: (catch <<0:(id(-(1 bsl 70))),0:(id(1 bsl 100))>>), 641: 642: ?line {'EXIT',{badarg,_}} = 643: (catch <<(id(<<>>))/binary,0:(id(-(1 bsl 100)))>>), 644: 645: ok. 646: 647: copy_writable_binary(Config) when is_list(Config) -> 648: ?line [copy_writable_binary_1(I) || I <- lists:seq(0, 256)], 649: ok. 650: 651: copy_writable_binary_1(_) -> 652: ?line Bin0 = <<(id(<<>>))/binary,0,1,2,3,4,5,6,7>>, 653: ?line SubBin = make_sub_bin(Bin0), 654: ?line id(<<42,34,55,Bin0/binary>>), %Make reallocation likelier. 655: ?line Pid = spawn(fun() -> 656: copy_writable_binary_holder(Bin0, SubBin) 657: end), 658: ?line Tab = ets:new(holder, []), 659: ?line ets:insert(Tab, {17,Bin0}), 660: ?line ets:insert(Tab, {42,SubBin}), 661: ?line id(<<Bin0/binary,0:(64*1024*8)>>), 662: ?line Pid ! self(), 663: ?line [{17,Bin0}] = ets:lookup(Tab, 17), 664: ?line [{42,Bin0}] = ets:lookup(Tab, 42), 665: receive 666: {Pid,Bin0,Bin0} -> ok; 667: Other -> 668: io:format("Unexpected message: ~p", [Other]), 669: ?line ?t:fail() 670: end, 671: ok. 672: 673: copy_writable_binary_holder(Bin, SubBin) -> 674: receive 675: Pid -> 676: Pid ! {self(),Bin,SubBin} 677: end. 678: 679: make_sub_bin(Bin0) -> 680: N = bit_size(Bin0), 681: <<_:17,Bin:N/bitstring,_:5>> = <<(-1):17,Bin0/bitstring,(-1):5>>, 682: Bin = Bin0, %Assertion. 683: Bin. 684: 685: %% Make sure that bit syntax expression with huge field size are 686: %% not constructed at compile time. 687: 688: kostis(Config) when is_list(Config) -> 689: case have_250_terabytes_of_ram() of 690: true -> 691: Bin = <<0:800000000000>>, 692: EmbeddedBin = <<0,(<<0:99999999999>>)/bitstring,1>>, 693: Bin0 = list_to_binary([Bin,Bin,Bin,Bin,Bin]), 694: Bin1 = list_to_binary([Bin0,Bin0,Bin0,Bin0,Bin0,Bin0]), 695: Bin2 = list_to_binary([Bin1,Bin1]), 696: id({EmbeddedBin,Bin0,Bin1,Bin2}); 697: false -> 698: ok 699: end. 700: 701: %% I'm not even certain how much 250 TB really is... 702: %% but I'm sure I don't have it :-) 703: 704: have_250_terabytes_of_ram() -> false. 705: 706: %% Test that different ways of using bit syntax instructions 707: %% give the same result. 708: 709: dynamic(Config) when is_list(Config) -> 710: ?line dynamic_1(fun dynamic_big/5), 711: ?line dynamic_1(fun dynamic_little/5), 712: ok. 713: 714: dynamic_1(Dynamic) -> 715: <<Lpad:128>> = erlang:md5([0]), 716: <<Rpad:128>> = erlang:md5([1]), 717: <<Int:128>> = erlang:md5([2]), 718: 8385 = dynamic_2(0, {Int,Lpad,Rpad,Dynamic}, 0). 719: 720: dynamic_2(129, _, Count) -> Count; 721: dynamic_2(Bef, Data, Count0) -> 722: Count = dynamic_3(Bef, 128-Bef, Data, Count0), 723: dynamic_2(Bef+1, Data, Count). 724: 725: dynamic_3(_, -1, _, Count) -> Count; 726: dynamic_3(Bef, N, {Int0,Lpad,Rpad,Dynamic}=Data, Count) -> 727: Int1 = Int0 band ((1 bsl (N+3))-1), 728: Dynamic(Bef, N, Int1, Lpad, Rpad), 729: Dynamic(Bef, N, -Int1, Lpad, Rpad), 730: 731: %% OTP-7085: Test a small number in a wide field. 732: Int2 = Int0 band 16#FFFFFF, 733: Dynamic(Bef, N, Int2, Lpad, Rpad), 734: Dynamic(Bef, N, -Int2, Lpad, Rpad), 735: dynamic_3(Bef, N-1, Data, Count+1). 736: 737: dynamic_big(Bef, N, Int, Lpad, Rpad) -> 738: NumBin = id(<<Int:N>>), 739: MaskedInt = Int band ((1 bsl N) - 1), 740: <<MaskedInt:N>> = NumBin, 741: 742: %% Construct the binary in two different ways. 743: Bin = id(<<Lpad:Bef,NumBin/bitstring,Rpad:(128-Bef-N)>>), 744: Bin = <<Lpad:Bef,Int:N,Rpad:(128-Bef-N)>>, 745: 746: %% Further verify the result by matching. 747: LpadMasked = Lpad band ((1 bsl Bef) - 1), 748: RpadMasked = Rpad band ((1 bsl (128-Bef-N)) - 1), 749: Rbits = (128-Bef-N), 750: <<LpadMasked:Bef,MaskedInt:N,RpadMasked:Rbits>> = id(Bin), 751: ok. 752: 753: dynamic_little(Bef, N, Int, Lpad, Rpad) -> 754: NumBin = id(<<Int:N/little>>), 755: MaskedInt = Int band ((1 bsl N) - 1), 756: <<MaskedInt:N/little>> = NumBin, 757: 758: %% Construct the binary in two different ways. 759: Bin = id(<<Lpad:Bef/little,NumBin/bitstring,Rpad:(128-Bef-N)/little>>), 760: Bin = <<Lpad:Bef/little,Int:N/little,Rpad:(128-Bef-N)/little>>, 761: 762: %% Further verify the result by matching. 763: LpadMasked = Lpad band ((1 bsl Bef) - 1), 764: RpadMasked = Rpad band ((1 bsl (128-Bef-N)) - 1), 765: Rbits = (128-Bef-N), 766: <<LpadMasked:Bef/little,MaskedInt:N/little,RpadMasked:Rbits/little>> = id(Bin), 767: ok. 768: 769: %% Test that the bs_add/5 instruction handles big numbers correctly. 770: bs_add(Config) when is_list(Config) -> 771: Mod = bs_construct_bs_add, 772: N = 2000, 773: Code = [{module, Mod}, 774: {exports, [{bs_add,2}]}, 775: {labels, 2}, 776: 777: %% bs_add(Number, -SmallestBig) -> Number + N 778: {function, bs_add, 2, 2}, 779: {label,1}, 780: {func_info,{atom,Mod},{atom,bs_add},2}, 781: 782: {label,2}, 783: {move,{x,0},{x,2}}] ++ 784: lists:duplicate(N-1, {bs_add,{f,0},[{x,2},{integer,1},1],{x,2}}) ++ 785: [{gc_bif,abs,{f,0},3,[{x,1}],{x,4}}, %Force GC, ignore result. 786: {gc_bif,'+',{f,0},3,[{x,2},{integer,1}],{x,0}}, %Safe result in {x,0} 787: return], 788: 789: %% Write assembly file and assemble it. 790: ?line PrivDir = ?config(priv_dir, Config), 791: ?line RootName = filename:join(PrivDir, atom_to_list(Mod)), 792: ?line AsmFile = RootName ++ ".S", 793: ?line {ok,Fd} = file:open(AsmFile, [write]), 794: ?line [io:format(Fd, "~p. \n", [T]) || T <- Code], 795: ?line ok = file:close(Fd), 796: ?line {ok,Mod} = compile:file(AsmFile, [from_asm,report,{outdir,PrivDir}]), 797: ?line LoadRc = code:load_abs(RootName), 798: ?line {module,_Module} = LoadRc, 799: 800: %% Find smallest positive bignum. 801: ?line SmallestBig = smallest_big(), 802: ?line io:format("~p\n", [SmallestBig]), 803: ?line Expected = SmallestBig + N, 804: DoTest = fun() -> 805: exit(Mod:bs_add(SmallestBig, -SmallestBig)) 806: end, 807: ?line {Pid,Mref} = spawn_monitor(DoTest), 808: receive 809: {'DOWN',Mref,process,Pid,Res} -> ok 810: end, 811: ?line Expected = Res, 812: 813: %% Clean up. 814: ?line ok = file:delete(AsmFile), 815: ?line ok = file:delete(code:which(Mod)), 816: ok. 817: 818: 819: smallest_big() -> 820: smallest_big_1(1 bsl 24). 821: 822: smallest_big_1(N) -> 823: case erts_debug:flat_size(N) of 824: 0 -> smallest_big_1(N+N); 825: _ -> N 826: end. 827: 828: otp_7422(Config) when is_list(Config) -> 829: otp_7422_int(0), 830: otp_7422_bin(0). 831: 832: otp_7422_int(N) when N < 512 -> 833: T = erlang:make_tuple(N, []), 834: spawn_link(fun() -> 835: id(T), 836: %% A size of field 0 would write one byte beyond 837: %% the current position in the binary. It could 838: %% overwrite the continuation pointer stored on 839: %% the stack if HTOP was equal to E (the stack pointer). 840: id(<<0:(id(0))>>) 841: end), 842: otp_7422_int(N+1); 843: otp_7422_int(_) -> ok. 844: 845: otp_7422_bin(N) when N < 512 -> 846: T = erlang:make_tuple(N, []), 847: Z = id(<<>>), 848: spawn_link(fun() -> 849: id(T), 850: id(<<Z:(id(0))/bits>>) 851: end), 852: otp_7422_bin(N+1); 853: otp_7422_bin(_) -> ok. 854: 855: zero_width(Config) when is_list(Config) -> 856: ?line Z = id(0), 857: Small = id(42), 858: Big = id(1 bsl 128), 859: ?line <<>> = <<Small:Z>>, 860: ?line <<>> = <<Small:0>>, 861: ?line <<>> = <<Big:Z>>, 862: ?line <<>> = <<Big:0>>, 863: 864: ?line {'EXIT',{badarg,_}} = (catch <<not_a_number:0>>), 865: ?line {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):Z>>), 866: ?line {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):0>>), 867: 868: ok. 869: 870: bad_append(_) -> 871: do_bad_append(<<127:1>>, fun append_unit_3/1), 872: do_bad_append(<<127:2>>, fun append_unit_3/1), 873: do_bad_append(<<127:17>>, fun append_unit_3/1), 874: 875: do_bad_append(<<127:3>>, fun append_unit_4/1), 876: do_bad_append(<<127:5>>, fun append_unit_4/1), 877: do_bad_append(<<127:7>>, fun append_unit_4/1), 878: do_bad_append(<<127:199>>, fun append_unit_4/1), 879: 880: do_bad_append(<<127:7>>, fun append_unit_8/1), 881: do_bad_append(<<127:9>>, fun append_unit_8/1), 882: 883: do_bad_append(<<0:8>>, fun append_unit_16/1), 884: do_bad_append(<<0:15>>, fun append_unit_16/1), 885: do_bad_append(<<0:17>>, fun append_unit_16/1), 886: ok. 887: 888: do_bad_append(Bin0, Appender) -> 889: {'EXIT',{badarg,_}} = (catch Appender(Bin0)), 890: 891: Bin1 = id(<<0:3,Bin0/bitstring>>), 892: <<_:3,Bin2/bitstring>> = Bin1, 893: {'EXIT',{badarg,_}} = (catch Appender(Bin2)), 894: 895: %% Create a writable binary. 896: Empty = id(<<>>), 897: Bin3 = <<Empty/bitstring,Bin0/bitstring>>, 898: {'EXIT',{badarg,_}} = (catch Appender(Bin3)), 899: ok. 900: 901: append_unit_3(Bin) -> 902: <<Bin/binary-unit:3,0:1>>. 903: 904: append_unit_4(Bin) -> 905: <<Bin/binary-unit:4,0:1>>. 906: 907: append_unit_8(Bin) -> 908: <<Bin/binary,0:1>>. 909: 910: append_unit_16(Bin) -> 911: <<Bin/binary-unit:16,0:1>>. 912: 913: 914: id(I) -> I.