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.