1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2000-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: 20: -module(bs_construct_SUITE). 21: 22: %% Copied from bs_construct_SUITE in the emulator test suite. 23: %% The following test cases have been omitted since they don't 24: %% make much sense for the debugger: 25: %% bs_add 26: %% kostis 27: 28: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, 29: init_per_testcase/2,end_per_testcase/2, 30: init_per_suite/1,end_per_suite/1, 31: test1/1, test2/1, test3/1, test4/1, test5/1, testf/1, 32: not_used/1, in_guard/1, 33: mem_leak/1, coerce_to_float/1, bjorn/1, 34: huge_float_field/1, huge_binary/1, system_limit/1, badarg/1, 35: copy_writable_binary/1, dynamic/1, 36: otp_7422/1, zero_width/1]). 37: 38: -include_lib("test_server/include/test_server.hrl"). 39: 40: suite() -> [{ct_hooks,[ts_install_cth]}]. 41: 42: all() -> 43: [test1, test2, test3, test4, test5, testf, not_used, 44: in_guard, mem_leak, coerce_to_float, bjorn, 45: huge_float_field, huge_binary, system_limit, badarg, 46: copy_writable_binary, dynamic, otp_7422, zero_width]. 47: 48: groups() -> 49: []. 50: 51: init_per_group(_GroupName, Config) -> 52: Config. 53: 54: end_per_group(_GroupName, Config) -> 55: Config. 56: 57: init_per_testcase(_Case, Config) -> 58: test_lib:interpret(?MODULE), 59: Dog = test_server:timetrap(?t:minutes(15)), 60: [{watchdog,Dog}|Config]. 61: 62: end_per_testcase(_Case, Config) -> 63: Dog = ?config(watchdog, Config), 64: ?t:timetrap_cancel(Dog), 65: ok. 66: 67: init_per_suite(Config) when is_list(Config) -> 68: ?line test_lib:interpret(?MODULE), 69: ?line true = lists:member(?MODULE, int:interpreted()), 70: Config. 71: 72: end_per_suite(Config) when is_list(Config) -> 73: ok. 74: 75: big(1) -> 76: 57285702734876389752897683. 77: 78: i(X) -> X. 79: 80: r(L) -> 81: lists:reverse(L). 82: 83: -define(T(B, L), {B, ??B, L}). 84: -define(N(B), {B, ??B, unknown}). 85: 86: -define(FAIL(Expr), ?line fail_check(catch Expr, ??Expr, [])). 87: 88: -define(FAIL_VARS(Expr, Vars), ?line fail_check(catch Expr, ??Expr, Vars)). 89: 90: l(I_13, I_big1) -> 91: [ 92: ?T(<<-43>>, 93: [256-43]), 94: ?T(<<56>>, 95: [56]), 96: ?T(<<1,2>>, 97: [1, 2]), 98: ?T(<<4:4, 7:4>>, 99: [4*16+7]), 100: ?T(<<777:16/big>>, 101: [3, 9]), 102: ?T(<<777:16/little>>, 103: [9, 3]), 104: ?T(<<0.0:32/float>>, 105: [0,0,0,0]), 106: ?T(<<0.125:32/float>>, 107: [62,0,0,0]), 108: ?T(<<0.125:32/little-float>>, 109: [0,0,0,62]), 110: ?T(<<I_big1:32>>, 111: [138, 99, 0, 147]), 112: ?T(<<57285702734876389752897684:32>>, 113: [138, 99, 0, 148]), 114: ?T(<<I_big1:32/little>>, 115: r([138, 99, 0, 147])), 116: ?T(<<-1:17/unit:8>>, 117: lists:duplicate(17, 255)), 118: 119: ?T(<<I_13>>, 120: [13]), 121: 122: ?T(<<4:8/unit:2,5:2/unit:8>>, 123: [0, 4, 0, 5]), 124: 125: ?T(<<1:1, 0:6, 1:1>>, 126: [129]), 127: ?T(<<1:1/little, 0:6/little, 1:1/little>>, 128: [129]), 129: 130: ?T(<<<<1,2>>/binary>>, 131: [1, 2]), 132: ?T(<<<<1,2>>:1/binary>>, 133: [1]), 134: ?T(<<4,3,<<1,2>>:1/binary>>, 135: [4,3,1]), 136: 137: ?T(<<(256*45+47)>>, 138: [47]), 139: 140: ?T(<<57:0>>, 141: []), 142: 143: ?T(<<"apa">>, 144: "apa"), 145: 146: ?T(<<1:3,"string",9:5>>, 147: [46,110,142,77,45,204,233]), 148: 149: ?T(<<>>, 150: []), 151: 152: ?T(<<37.98:64/native-float>>, 153: native_3798()), 154: 155: ?T(<<32978297842987249827298387697777669766334937:128/native-integer>>, 156: native_bignum()), 157: 158: %% Unit tests. 159: ?T(<<<<5:3>>/bitstring>>, <<5:3>>), 160: ?T(<<42,<<7:4>>/binary-unit:4>>, <<42,7:4>>), 161: ?T(<<<<344:17>>/binary-unit:17>>, <<344:17>>), 162: ?T(<<<<42,3,7656:16>>/binary-unit:16>>, <<42,3,7656:16>>) 163: 164: ]. 165: 166: native_3798() -> 167: case <<1:16/native>> of 168: <<0,1>> -> [64,66,253,112,163,215,10,61]; 169: <<1,0>> -> [61,10,215,163,112,253,66,64] 170: end. 171: 172: native_bignum() -> 173: case <<1:16/native>> of 174: <<0,1>> -> [129,205,18,177,1,213,170,101,39,231,109,128,176,11,73,217]; 175: <<1,0>> -> [217,73,11,176,128,109,231,39,101,170,213,1,177,18,205,129] 176: end. 177: 178: evaluate(Str, Vars) -> 179: {ok,Tokens,_} = 180: erl_scan:string(Str ++ " . "), 181: {ok, [Expr]} = erl_parse:parse_exprs(Tokens), 182: case erl_eval:expr(Expr, Vars) of 183: {value, Result, _} -> 184: Result 185: end. 186: 187: eval_list([], _Vars) -> 188: []; 189: eval_list([{C_bin, Str, Bytes} | Rest], Vars) -> 190: case catch evaluate(Str, Vars) of 191: {'EXIT', Error} -> 192: io:format("Evaluation error: ~p, ~p, ~p~n", [Str, Vars, Error]), 193: exit(Error); 194: E_bin -> 195: [{C_bin, E_bin, Str, Bytes} | eval_list(Rest, Vars)] 196: end. 197: 198: one_test({C_bin, E_bin, Str, Bytes}) when is_list(Bytes) -> 199: io:format(" ~s, ~p~n", [Str, Bytes]), 200: Bin = list_to_binary(Bytes), 201: if 202: C_bin == Bin -> 203: ok; 204: true -> 205: io:format("ERROR: Compiled: ~p. Expected ~p. Got ~p.~n", 206: [Str, Bytes, binary_to_list(C_bin)]), 207: test_server:fail(comp) 208: end, 209: if 210: E_bin == Bin -> 211: ok; 212: true -> 213: io:format("ERROR: Interpreted: ~p. Expected ~p. Got ~p.~n", 214: [Str, Bytes, binary_to_list(E_bin)]), 215: test_server:fail(comp) 216: end; 217: one_test({C_bin, E_bin, Str, Result}) -> 218: io:format(" ~s ~p~n", [Str, C_bin]), 219: if 220: C_bin == E_bin -> 221: ok; 222: true -> 223: Arbitrary = case Result of 224: unknown -> 225: size(C_bin); 226: _ -> 227: Result 228: end, 229: case equal_lists(binary_to_list(C_bin), 230: binary_to_list(E_bin), 231: Arbitrary) of 232: false -> 233: io:format("ERROR: Compiled not equal to interpreted:" 234: "~n ~p, ~p.~n", 235: [binary_to_list(C_bin), binary_to_list(E_bin)]), 236: test_server:fail(comp); 237: 0 -> 238: ok; 239: %% For situations where the final bits may not matter, like 240: %% for floats: 241: N when is_integer(N) -> 242: io:format("Info: compiled and interpreted differ in the" 243: " last bytes:~n ~p, ~p.~n", 244: [binary_to_list(C_bin), binary_to_list(E_bin)]), 245: ok 246: end 247: end. 248: 249: equal_lists([], [], _) -> 250: 0; 251: equal_lists([], _, _) -> 252: false; 253: equal_lists(_, [], _) -> 254: false; 255: equal_lists([A|AR], [A|BR], R) -> 256: equal_lists(AR, BR, R); 257: equal_lists(A, B, R) -> 258: if 259: length(A) /= length(B) -> 260: false; 261: length(A) =< R -> 262: R; 263: true -> 264: false 265: end. 266: 267: fail_check({'EXIT',{badarg,_}}, Str, Vars) -> 268: try evaluate(Str, Vars) of 269: Res -> 270: io:format("Interpreted result: ~p", [Res]), 271: ?t:fail(did_not_fail_in_intepreted_code) 272: catch 273: error:badarg -> 274: ok 275: end; 276: fail_check(Res, _, _) -> 277: io:format("Compiled result: ~p", [Res]), 278: ?t:fail(did_not_fail_in_compiled_code). 279: 280: %%% Simple working cases 281: test1(suite) -> []; 282: test1(Config) when is_list(Config) -> 283: ?line I_13 = i(13), 284: ?line I_big1 = big(1), 285: ?line Vars = [{'I_13', I_13}, 286: {'I_big1', I_big1}], 287: ?line lists:foreach(fun one_test/1, eval_list(l(I_13, I_big1), Vars)). 288: 289: %%% Misc 290: 291: %%% <<A:S, A:(N-S)>> 292: comp(N, A, S) -> 293: M1 = (1 bsl S) - 1, 294: M2 = (1 bsl (N-S)) - 1, 295: [((A band M1) bsl (N-S)) bor (A band M2)]. 296: 297: gen(N, S, A) -> 298: [?T(<<A:S, A:(N-S)>>, comp(N, A, S))]. 299: 300: gen_l(N, S, A) -> 301: [?T(<<A:S/little, A:(N-S)/little>>, comp(N, A, S))]. 302: 303: test2(suite) -> []; 304: test2(Config) when is_list(Config) -> 305: ?line test2(0, 8, 2#10101010101010101), 306: ?line test2(0, 8, 2#1111111111). 307: 308: test2(End, End, _) -> 309: ok; 310: test2(I, End, A) -> 311: test2(I, A), 312: test2(I+1, End, A). 313: 314: test2(S, A) -> 315: N = 8, 316: Vars = [{'A',A}, {'N',N}, {'S',S}], 317: io:format("Vars: ~p\n", [Vars]), 318: lists:foreach(fun one_test/1, eval_list(gen(N, S, A), Vars)), 319: lists:foreach(fun one_test/1, eval_list(gen_l(N, S, A), Vars)). 320: 321: %%% Tests without facit 322: 323: t3() -> 324: [?N(<<4711:13, 9876:13, 3:6>>), 325: ?N(<<4.57:64/float>>), 326: ?N(<<4.57:32/float>>), 327: 328: ?N(<<>>) 329: ]. 330: 331: test3(suite) -> []; 332: test3(Config) when is_list(Config) -> 333: ?line Vars = [], 334: ?line lists:foreach(fun one_test/1, eval_list(t3(), Vars)). 335: 336: gen_u(N, S, A) -> 337: [?N(<<A:S, A:(N-S)>>)]. 338: 339: gen_u_l(N, S, A) -> 340: [?N(<<A:S/little, A:(N-S)/little>>)]. 341: 342: test4(suite) -> []; 343: test4(Config) when is_list(Config) -> 344: ?line test4(0, 16, 2#10101010101010101), 345: ?line test4(0, 16, 2#1111111111). 346: 347: test4(End, End, _) -> 348: ok; 349: test4(I, End, A) -> 350: test4(I, A), 351: test4(I+1, End, A). 352: 353: test4(S, A) -> 354: N = 16, 355: Vars = [{'A', A}, {'N', 16}, {'S', S}], 356: lists:foreach(fun one_test/1, eval_list(gen_u(N, S, A), Vars)), 357: lists:foreach(fun one_test/1, eval_list(gen_u_l(N, S, A), Vars)). 358: 359: gen_b(N, S, A) -> 360: [?T(<<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>, 361: binary_to_list(<<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>))]. 362: 363: test5(suite) -> []; 364: test5(doc) -> ["OTP-3995"]; 365: test5(Config) when is_list(Config) -> 366: ?line test5(0, 8, <<73>>), 367: ?line test5(0, 8, <<68>>). 368: 369: test5(End, End, _) -> 370: ok; 371: test5(I, End, A) -> 372: test5(I, A), 373: test5(I+1, End, A). 374: 375: test5(S, A) -> 376: N = 8, 377: Vars = [{'A', A}, {'N', 8}, {'S', S}], 378: lists:foreach(fun one_test/1, eval_list(gen_b(N, S, A), Vars)). 379: 380: %%% Failure cases 381: testf(suite) -> []; 382: testf(Config) when is_list(Config) -> 383: ?line ?FAIL(<<3.14>>), 384: ?line ?FAIL(<<<<1,2>>>>), 385: 386: ?line ?FAIL(<<2.71/binary>>), 387: ?line ?FAIL(<<24334/binary>>), 388: ?line ?FAIL(<<24334344294788947129487129487219847/binary>>), 389: BigInt = id(24334344294788947129487129487219847), 390: ?line ?FAIL_VARS(<<BigInt/binary>>, [{'BigInt',BigInt}]), 391: ?line ?FAIL_VARS(<<42,BigInt/binary>>, [{'BigInt',BigInt}]), 392: ?line ?FAIL_VARS(<<BigInt:2/binary>>, [{'BigInt',BigInt}]), 393: 394: %% One negative field size, but the sum of field sizes will be 1 byte. 395: %% Make sure that we reject that properly. 396: I_minus_777 = id(-777), 397: I_minus_2047 = id(-2047), 398: ?line ?FAIL_VARS(<<I_minus_777:2048/unit:8,57:I_minus_2047/unit:8>>, 399: ordsets:from_list([{'I_minus_777',I_minus_777}, 400: {'I_minus_2047',I_minus_2047}])), 401: ?line ?FAIL(<<<<1,2,3>>/float>>), 402: 403: %% Negative field widths. 404: ?line testf_1(-8, <<1,2,3,4,5>>), 405: ?line ?FAIL(<<0:(-(1 bsl 100))>>), 406: 407: ?line ?FAIL(<<42:(-16)>>), 408: ?line ?FAIL(<<3.14:(-8)/float>>), 409: ?line ?FAIL(<<<<23,56,0,2>>:(-16)/binary>>), 410: ?line ?FAIL(<<<<23,56,0,2>>:(2.5)/binary>>), 411: ?line ?FAIL(<<<<23,56,0,2>>:(anka)>>), 412: ?line ?FAIL(<<<<23,56,0,2>>:(anka)>>), 413: 414: %% Unit failures. 415: ?line ?FAIL(<<<<1:1>>/binary>>), 416: Sz = id(1), 417: ?line ?FAIL_VARS(<<<<1:Sz>>/binary>>, [{'Sz',Sz}]), 418: ?line {'EXIT',{badarg,_}} = (catch <<<<1:(id(1))>>/binary>>), 419: ?line ?FAIL(<<<<7,8,9>>/binary-unit:16>>), 420: ?line ?FAIL(<<<<7,8,9,3:7>>/binary-unit:16>>), 421: ?line ?FAIL(<<<<7,8,9,3:7>>/binary-unit:17>>), 422: 423: ok. 424: 425: testf_1(W, B) -> 426: Vars = [{'W',W}], 427: ?FAIL_VARS(<<42:W>>, Vars), 428: ?FAIL_VARS(<<3.14:W/float>>, Vars), 429: ?FAIL_VARS(<<B:W/binary>>, [{'B',B}|Vars]). 430: 431: not_used(doc) -> 432: "Test that constructed binaries that are not used will still give an exception."; 433: not_used(Config) when is_list(Config) -> 434: ?line ok = not_used1(3, <<"dum">>), 435: ?line {'EXIT',{badarg,_}} = (catch not_used1(3, "dum")), 436: ?line {'EXIT',{badarg,_}} = (catch not_used2(444, -2)), 437: ?line {'EXIT',{badarg,_}} = (catch not_used2(444, anka)), 438: ?line {'EXIT',{badarg,_}} = (catch not_used3(444)), 439: ok. 440: 441: not_used1(I, BinString) -> 442: <<I:32,BinString/binary>>, 443: ok. 444: 445: not_used2(I, Sz) -> 446: <<I:Sz>>, 447: ok. 448: 449: not_used3(I) -> 450: <<I:(-8)>>, 451: ok. 452: 453: in_guard(Config) when is_list(Config) -> 454: ?line 1 = in_guard(<<16#74ad:16>>, 16#e95, 5), 455: ?line 2 = in_guard(<<16#3A,16#F7,"hello">>, 16#3AF7, <<"hello">>), 456: ?line 3 = in_guard(<<16#FBCD:14,3.1415/float,3:2>>, 16#FBCD, 3.1415), 457: ?line 3 = in_guard(<<16#FBCD:14,3/float,3:2>>, 16#FBCD, 3), 458: ?line 3 = in_guard(<<16#FBCD:14,(2 bsl 226)/float,3:2>>, 16#FBCD, 2 bsl 226), 459: nope = in_guard(<<1>>, 42, b), 460: nope = in_guard(<<1>>, a, b), 461: nope = in_guard(<<1,2>>, 1, 1), 462: nope = in_guard(<<4,5>>, 1, 2.71), 463: nope = in_guard(<<4,5>>, 1, <<12,13>>), 464: ok. 465: 466: in_guard(Bin, A, B) when <<A:13,B:3>> == Bin -> 1; 467: in_guard(Bin, A, B) when <<A:16,B/binary>> == Bin -> 2; 468: in_guard(Bin, A, B) when <<A:14,B/float,3:2>> == Bin -> 3; 469: in_guard(Bin, A, B) when {a,b,<<A:14,B/float,3:2>>} == Bin -> cant_happen; 470: in_guard(_, _, _) -> nope. 471: 472: mem_leak(doc) -> "Make sure that construction has no memory leak"; 473: mem_leak(Config) when is_list(Config) -> 474: ?line B = make_bin(16, <<0>>), 475: ?line mem_leak(1024, B), 476: ok. 477: 478: mem_leak(0, _) -> ok; 479: mem_leak(N, B) -> 480: ?line big_bin(B, <<23>>), 481: ?line {'EXIT',{badarg,_}} = (catch big_bin(B, bad)), 482: mem_leak(N-1, B). 483: 484: big_bin(B1, B2) -> 485: <<B1/binary,B1/binary,B1/binary,B1/binary, 486: B1/binary,B1/binary,B1/binary,B1/binary, 487: B1/binary,B1/binary,B1/binary,B1/binary, 488: B1/binary,B1/binary,B1/binary,B1/binary, 489: B2/binary>>. 490: 491: make_bin(0, Acc) -> Acc; 492: make_bin(N, Acc) -> make_bin(N-1, <<Acc/binary,Acc/binary>>). 493: 494: -define(COF(Int0), 495: ?line (fun(Int) -> 496: true = <<Int:32/float>> =:= <<(float(Int)):32/float>>, 497: true = <<Int:64/float>> =:= <<(float(Int)):64/float>> 498: end)(nonliteral(Int0)), 499: ?line true = <<Int0:32/float>> =:= <<(float(Int0)):32/float>>, 500: ?line true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>). 501: 502: -define(COF64(Int0), 503: ?line (fun(Int) -> 504: true = <<Int:64/float>> =:= <<(float(Int)):64/float>> 505: end)(nonliteral(Int0)), 506: ?line true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>). 507: 508: nonliteral(X) -> X. 509: 510: coerce_to_float(Config) when is_list(Config) -> 511: ?COF(0), 512: ?COF(-1), 513: ?COF(1), 514: ?COF(42), 515: ?COF(255), 516: ?COF(-255), 517: ?COF(38474), 518: ?COF(387498738948729893849444444443), 519: ?COF(-37489378937773899999999999999993), 520: ?COF64(298748888888888888888888888883478264866528467367364766666666666666663), 521: ?COF64(-367546729879999999999947826486652846736736476555566666663), 522: ok. 523: 524: bjorn(Config) when is_list(Config) -> 525: ?line error = bjorn_1(), 526: ok. 527: 528: bjorn_1() -> 529: Bitstr = <<7:13>>, 530: try 531: do_something() 532: catch 533: throw:blurf -> 534: ignore 535: end, 536: do_more(Bitstr, 13). 537: 538: do_more(Bin, Sz) -> 539: %% Previous bug in the bs_bits_to_bytes instruction: The exeption code 540: %% was not set - the previous exception (throw:blurf) would be used, 541: %% causing the catch to slip. 542: try <<Bin:Sz/binary>> of 543: _V -> ok 544: catch 545: error:_ -> 546: error 547: end. 548: 549: do_something() -> 550: throw(blurf). 551: 552: huge_float_field(Config) when is_list(Config) -> 553: ?line {'EXIT',{badarg,_}} = (catch <<0.0:9/float-unit:8>>), 554: ?line huge_float_check(catch <<0.0:67108865/float-unit:64>>), 555: ?line huge_float_check(catch <<0.0:((1 bsl 26)+1)/float-unit:64>>), 556: ?line huge_float_check(catch <<0.0:(id(67108865))/float-unit:64>>), 557: %% ?line huge_float_check(catch <<0.0:((1 bsl 60)+1)/float-unit:64>>), 558: ?line huge_float_check(catch <<3839739387439387383739387987347983:((1 bsl 26)+1)/float-unit:64>>), 559: %% ?line huge_float_check(catch <<3839739387439387383739387987347983:((1 bsl 60)+1)/float-unit:64>>), 560: ok. 561: 562: huge_float_check({'EXIT',{system_limit,_}}) -> ok; 563: huge_float_check({'EXIT',{badarg,_}}) -> ok. 564: 565: huge_binary(Config) when is_list(Config) -> 566: ?line 16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>), 567: ok. 568: 569: system_limit(Config) when is_list(Config) -> 570: WordSize = erlang:system_info(wordsize), 571: BitsPerWord = WordSize * 8, 572: ?line {'EXIT',{system_limit,_}} = 573: (catch <<0:(id(0)),42:(id(1 bsl BitsPerWord))>>), 574: ?line {'EXIT',{system_limit,_}} = 575: (catch <<42:(id(1 bsl BitsPerWord)),0:(id(0))>>), 576: ?line {'EXIT',{system_limit,_}} = 577: (catch <<(id(<<>>))/binary,0:(id(1 bsl 100))>>), 578: 579: case WordSize of 580: 4 -> 581: system_limit_32(); 582: 8 -> 583: ok 584: end. 585: 586: system_limit_32() -> 587: ?line {'EXIT',{badarg,_}} = (catch <<42:(-1)>>), 588: ?line {'EXIT',{badarg,_}} = (catch <<42:(id(-1))>>), 589: ?line {'EXIT',{badarg,_}} = (catch <<42:(id(-389739873536870912))/unit:8>>), 590: ?line {'EXIT',{system_limit,_}} = (catch <<42:536870912/unit:8>>), 591: ?line {'EXIT',{system_limit,_}} = (catch <<42:(id(536870912))/unit:8>>), 592: ?line {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:536870912/unit:8>>), 593: ?line {'EXIT',{system_limit,_}} = 594: (catch <<0:(id(8)),42:(id(536870912))/unit:8>>), 595: ok. 596: 597: badarg(Config) when is_list(Config) -> 598: %% BEAM will generate a badarg exception for: 599: %% <<0:(id(1 bsl 100)),0:(id(-1))>> 600: %% but the debugger will generate a system_limit exception. 601: %% It does not seems worthwhile to fix the debugger. 602: 603: ?line {'EXIT',{badarg,_}} = 604: (catch <<(id(<<>>))/binary,0:(id(-(1 bsl 100)))>>), 605: 606: ok. 607: 608: copy_writable_binary(Config) when is_list(Config) -> 609: ?line [copy_writable_binary_1(I) || I <- lists:seq(0, 256)], 610: ok. 611: 612: copy_writable_binary_1(_) -> 613: ?line Bin0 = <<(id(<<>>))/binary,0,1,2,3,4,5,6,7>>, 614: ?line SubBin = make_sub_bin(Bin0), 615: ?line id(<<42,34,55,Bin0/binary>>), %Make reallocation likelier. 616: ?line Pid = spawn(fun() -> 617: copy_writable_binary_holder(Bin0, SubBin) 618: end), 619: ?line Tab = ets:new(holder, []), 620: ?line ets:insert(Tab, {17,Bin0}), 621: ?line ets:insert(Tab, {42,SubBin}), 622: ?line id(<<Bin0/binary,0:(64*1024*8)>>), 623: ?line Pid ! self(), 624: ?line [{17,Bin0}] = ets:lookup(Tab, 17), 625: ?line [{42,Bin0}] = ets:lookup(Tab, 42), 626: receive 627: {Pid,Bin0,Bin0} -> ok; 628: Other -> 629: io:format("Unexpected message: ~p", [Other]), 630: ?line ?t:fail() 631: end, 632: ok. 633: 634: copy_writable_binary_holder(Bin, SubBin) -> 635: receive 636: Pid -> 637: Pid ! {self(),Bin,SubBin} 638: end. 639: 640: make_sub_bin(Bin0) -> 641: N = bit_size(Bin0), 642: <<_:17,Bin:N/bitstring,_:5>> = <<(-1):17,Bin0/bitstring,(-1):5>>, 643: Bin = Bin0, %Assertion. 644: Bin. 645: 646: %% Test that different ways of using bit syntax instructions 647: %% give the same result. 648: 649: dynamic(Config) when is_list(Config) -> 650: ?line dynamic_1(fun dynamic_big/5), 651: ?line dynamic_1(fun dynamic_little/5), 652: ok. 653: 654: dynamic_1(Dynamic) -> 655: <<Lpad:128>> = erlang:md5([0]), 656: <<Rpad:128>> = erlang:md5([1]), 657: <<Int:128>> = erlang:md5([2]), 658: 8385 = dynamic_2(0, {Int,Lpad,Rpad,Dynamic}, 0). 659: 660: dynamic_2(129, _, Count) -> Count; 661: dynamic_2(Bef, Data, Count0) -> 662: Count = dynamic_3(Bef, 128-Bef, Data, Count0), 663: dynamic_2(Bef+1, Data, Count). 664: 665: dynamic_3(_, -1, _, Count) -> Count; 666: dynamic_3(Bef, N, {Int0,Lpad,Rpad,Dynamic}=Data, Count) -> 667: Int1 = Int0 band ((1 bsl (N+3))-1), 668: Dynamic(Bef, N, Int1, Lpad, Rpad), 669: Dynamic(Bef, N, -Int1, Lpad, Rpad), 670: 671: %% OTP-7085: Test a small number in a wide field. 672: Int2 = Int0 band 16#FFFFFF, 673: Dynamic(Bef, N, Int2, Lpad, Rpad), 674: Dynamic(Bef, N, -Int2, Lpad, Rpad), 675: dynamic_3(Bef, N-1, Data, Count+1). 676: 677: dynamic_big(Bef, N, Int, Lpad, Rpad) -> 678: NumBin = id(<<Int:N>>), 679: MaskedInt = Int band ((1 bsl N) - 1), 680: <<MaskedInt:N>> = NumBin, 681: 682: %% Construct the binary in two different ways. 683: Bin = id(<<Lpad:Bef,NumBin/bitstring,Rpad:(128-Bef-N)>>), 684: Bin = <<Lpad:Bef,Int:N,Rpad:(128-Bef-N)>>, 685: 686: %% Further verify the result by matching. 687: LpadMasked = Lpad band ((1 bsl Bef) - 1), 688: RpadMasked = Rpad band ((1 bsl (128-Bef-N)) - 1), 689: Rbits = (128-Bef-N), 690: <<LpadMasked:Bef,MaskedInt:N,RpadMasked:Rbits>> = id(Bin), 691: ok. 692: 693: dynamic_little(Bef, N, Int, Lpad, Rpad) -> 694: NumBin = id(<<Int:N/little>>), 695: MaskedInt = Int band ((1 bsl N) - 1), 696: <<MaskedInt:N/little>> = NumBin, 697: 698: %% Construct the binary in two different ways. 699: Bin = id(<<Lpad:Bef/little,NumBin/bitstring,Rpad:(128-Bef-N)/little>>), 700: Bin = <<Lpad:Bef/little,Int:N/little,Rpad:(128-Bef-N)/little>>, 701: 702: %% Further verify the result by matching. 703: LpadMasked = Lpad band ((1 bsl Bef) - 1), 704: RpadMasked = Rpad band ((1 bsl (128-Bef-N)) - 1), 705: Rbits = (128-Bef-N), 706: <<LpadMasked:Bef/little,MaskedInt:N/little,RpadMasked:Rbits/little>> = id(Bin), 707: ok. 708: 709: otp_7422(Config) when is_list(Config) -> 710: otp_7422_int(0), 711: otp_7422_bin(0). 712: 713: otp_7422_int(N) when N < 512 -> 714: T = erlang:make_tuple(N, []), 715: spawn_link(fun() -> 716: id(T), 717: %% A size of field 0 would write one byte beyond 718: %% the current position in the binary. It could 719: %% overwrite the continuation pointer stored on 720: %% the stack if HTOP was equal to E (the stack pointer). 721: id(<<0:(id(0))>>) 722: end), 723: otp_7422_int(N+1); 724: otp_7422_int(_) -> ok. 725: 726: otp_7422_bin(N) when N < 512 -> 727: T = erlang:make_tuple(N, []), 728: Z = id(<<>>), 729: spawn_link(fun() -> 730: id(T), 731: id(<<Z:(id(0))/bits>>) 732: end), 733: otp_7422_bin(N+1); 734: otp_7422_bin(_) -> ok. 735: 736: zero_width(Config) when is_list(Config) -> 737: ?line Z = id(0), 738: Small = id(42), 739: Big = id(1 bsl 128), 740: ?line <<>> = <<Small:Z>>, 741: ?line <<>> = <<Small:0>>, 742: ?line <<>> = <<Big:Z>>, 743: ?line <<>> = <<Big:0>>, 744: 745: ?line {'EXIT',{badarg,_}} = (catch <<not_a_number:0>>), 746: ?line {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):Z>>), 747: ?line {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):0>>), 748: 749: ok. 750: 751: id(I) -> I.