1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2016. 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(bs_construct_SUITE).
22
23%% Copied from bs_construct_SUITE in the emulator test suite.
24%% The following test cases have been omitted since they don't
25%% make much sense for the debugger:
26%%  bs_add
27%%  kostis
28
29-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
30	 init_per_testcase/2,end_per_testcase/2,
31	 init_per_suite/1,end_per_suite/1,
32	 test1/1, test2/1, test3/1, test4/1, test5/1, testf/1,
33	 not_used/1, in_guard/1,
34	 mem_leak/1, coerce_to_float/1, bjorn/1,
35	 huge_float_field/1, huge_binary/1, system_limit/1, badarg/1,
36	 copy_writable_binary/1, dynamic/1,
37	 otp_7422/1, zero_width/1]).
38
39-include_lib("common_test/include/ct.hrl").
40
41suite() ->
42    [{ct_hooks,[ts_install_cth]},
43     {timetrap,{minutes,15}}].
44
45all() ->
46    [test1, test2, test3, test4, test5, testf, not_used,
47     in_guard, mem_leak, coerce_to_float, bjorn,
48     huge_float_field, huge_binary, system_limit, badarg,
49     copy_writable_binary, dynamic, otp_7422, zero_width].
50
51groups() ->
52    [].
53
54init_per_group(_GroupName, Config) ->
55    Config.
56
57end_per_group(_GroupName, Config) ->
58    Config.
59
60init_per_testcase(_Case, Config) ->
61    test_lib:interpret(?MODULE),
62    Config.
63
64end_per_testcase(_Case, _Config) ->
65    ok.
66
67init_per_suite(Config) when is_list(Config) ->
68    test_lib:interpret(?MODULE),
69    true = lists:member(?MODULE, int:interpreted()),
70    Config.
71
72end_per_suite(Config) when is_list(Config) ->
73    ok.
74
75big(1) ->
76    57285702734876389752897683.
77
78i(X) -> X.
79
80r(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), fail_check(catch Expr, ??Expr, [])).
87
88-define(FAIL_VARS(Expr, Vars), fail_check(catch Expr, ??Expr, Vars)).
89
90l(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
166native_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
172native_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
178evaluate(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
187eval_list([], _Vars) ->
188    [];
189eval_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
198one_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	    ct: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	    ct:fail(comp)
216    end;
217one_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		    ct: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
249equal_lists([], [], _) ->
250    0;
251equal_lists([], _, _) ->
252    false;
253equal_lists(_, [], _) ->
254    false;
255equal_lists([A|AR], [A|BR], R) ->
256    equal_lists(AR, BR, R);
257equal_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
267fail_check({'EXIT',{badarg,_}}, Str, Vars) ->
268    try	evaluate(Str, Vars) of
269	Res ->
270	    io:format("Interpreted result: ~p", [Res]),
271	    ct:fail(did_not_fail_in_intepreted_code)
272    catch
273	error:badarg ->
274	    ok
275    end;
276fail_check(Res, _, _) ->
277    io:format("Compiled result: ~p", [Res]),
278    ct:fail(did_not_fail_in_compiled_code).
279
280%%% Simple working cases
281test1(Config) when is_list(Config) ->
282    I_13 = i(13),
283    I_big1 = big(1),
284    Vars = [{'I_13', I_13},
285	    {'I_big1', I_big1}],
286    lists:foreach(fun one_test/1, eval_list(l(I_13, I_big1), Vars)).
287
288%%% Misc
289
290%%% <<A:S, A:(N-S)>>
291comp(N, A, S) ->
292    M1 = (1 bsl S) - 1,
293    M2 = (1 bsl (N-S)) - 1,
294    [((A band M1) bsl (N-S)) bor (A band M2)].
295
296gen(N, S, A) ->
297    [?T(<<A:S, A:(N-S)>>, comp(N, A, S))].
298
299gen_l(N, S, A) ->
300    [?T(<<A:S/little, A:(N-S)/little>>, comp(N, A, S))].
301
302test2(Config) when is_list(Config) ->
303    test2(0, 8, 2#10101010101010101),
304    test2(0, 8, 2#1111111111).
305
306test2(End, End, _) ->
307    ok;
308test2(I, End, A) ->
309    test2(I, A),
310    test2(I+1, End, A).
311
312test2(S, A) ->
313    N = 8,
314    Vars = [{'A',A}, {'N',N}, {'S',S}],
315    io:format("Vars: ~p\n", [Vars]),
316    lists:foreach(fun one_test/1, eval_list(gen(N, S, A), Vars)),
317    lists:foreach(fun one_test/1, eval_list(gen_l(N, S, A), Vars)).
318
319%%% Tests without facit
320
321t3() ->
322    [?N(<<4711:13, 9876:13, 3:6>>),
323     ?N(<<4.57:64/float>>),
324     ?N(<<4.57:32/float>>),
325
326     ?N(<<>>)
327    ].
328
329test3(Config) when is_list(Config) ->
330    Vars = [],
331    lists:foreach(fun one_test/1, eval_list(t3(), Vars)).
332
333gen_u(N, S, A) ->
334    [?N(<<A:S, A:(N-S)>>)].
335
336gen_u_l(N, S, A) ->
337    [?N(<<A:S/little, A:(N-S)/little>>)].
338
339test4(Config) when is_list(Config) ->
340    test4(0, 16, 2#10101010101010101),
341    test4(0, 16, 2#1111111111).
342
343test4(End, End, _) ->
344    ok;
345test4(I, End, A) ->
346    test4(I, A),
347    test4(I+1, End, A).
348
349test4(S, A) ->
350    N = 16,
351    Vars = [{'A', A}, {'N', 16}, {'S', S}],
352    lists:foreach(fun one_test/1, eval_list(gen_u(N, S, A), Vars)),
353    lists:foreach(fun one_test/1, eval_list(gen_u_l(N, S, A), Vars)).
354
355gen_b(N, S, A) ->
356    [?T(<<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>,
357	binary_to_list(<<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>))].
358
359%% OTP-3995.
360test5(Config) when is_list(Config) ->
361    test5(0, 8, <<73>>),
362    test5(0, 8, <<68>>).
363
364test5(End, End, _) ->
365    ok;
366test5(I, End, A) ->
367    test5(I, A),
368    test5(I+1, End, A).
369
370test5(S, A) ->
371    N = 8,
372    Vars = [{'A', A}, {'N', 8}, {'S', S}],
373    lists:foreach(fun one_test/1, eval_list(gen_b(N, S, A), Vars)).
374
375%%% Failure cases
376testf(Config) when is_list(Config) ->
377    ?FAIL(<<3.14>>),
378    ?FAIL(<<<<1,2>>>>),
379
380    ?FAIL(<<2.71/binary>>),
381    ?FAIL(<<24334/binary>>),
382    ?FAIL(<<24334344294788947129487129487219847/binary>>),
383    BigInt = id(24334344294788947129487129487219847),
384    ?FAIL_VARS(<<BigInt/binary>>, [{'BigInt',BigInt}]),
385    ?FAIL_VARS(<<42,BigInt/binary>>, [{'BigInt',BigInt}]),
386    ?FAIL_VARS(<<BigInt:2/binary>>, [{'BigInt',BigInt}]),
387
388    %% One negative field size, but the sum of field sizes will be 1 byte.
389    %% Make sure that we reject that properly.
390    I_minus_777 = id(-777),
391    I_minus_2047 = id(-2047),
392    ?FAIL_VARS(<<I_minus_777:2048/unit:8,57:I_minus_2047/unit:8>>,
393	       ordsets:from_list([{'I_minus_777',I_minus_777},
394				  {'I_minus_2047',I_minus_2047}])),
395    ?FAIL(<<<<1,2,3>>/float>>),
396
397    %% Negative field widths.
398    testf_1(-8, <<1,2,3,4,5>>),
399    ?FAIL(<<0:(-(1 bsl 100))>>),
400
401    ?FAIL(<<42:(-16)>>),
402    ?FAIL(<<3.14:(-8)/float>>),
403    ?FAIL(<<<<23,56,0,2>>:(-16)/binary>>),
404    ?FAIL(<<<<23,56,0,2>>:(2.5)/binary>>),
405    ?FAIL(<<<<23,56,0,2>>:(anka)>>),
406    ?FAIL(<<<<23,56,0,2>>:(anka)>>),
407
408    %% Unit failures.
409    ?FAIL(<<<<1:1>>/binary>>),
410    Sz = id(1),
411    ?FAIL_VARS(<<<<1:Sz>>/binary>>, [{'Sz',Sz}]),
412    {'EXIT',{badarg,_}} = (catch <<<<1:(id(1))>>/binary>>),
413    ?FAIL(<<<<7,8,9>>/binary-unit:16>>),
414    ?FAIL(<<<<7,8,9,3:7>>/binary-unit:16>>),
415    ?FAIL(<<<<7,8,9,3:7>>/binary-unit:17>>),
416
417    ok.
418
419testf_1(W, B) ->
420    Vars = [{'W',W}],
421    ?FAIL_VARS(<<42:W>>, Vars),
422    ?FAIL_VARS(<<3.14:W/float>>, Vars),
423    ?FAIL_VARS(<<B:W/binary>>, [{'B',B}|Vars]).
424
425%% Test that constructed binaries that are not used will still give an exception.
426not_used(Config) when is_list(Config) ->
427    ok = not_used1(3, <<"dum">>),
428    {'EXIT',{badarg,_}} = (catch not_used1(3, "dum")),
429    {'EXIT',{badarg,_}} = (catch not_used2(444, -2)),
430    {'EXIT',{badarg,_}} = (catch not_used2(444, anka)),
431    {'EXIT',{badarg,_}} = (catch not_used3(444)),
432    ok.
433
434not_used1(I, BinString) ->
435    <<I:32,BinString/binary>>,
436    ok.
437
438not_used2(I, Sz) ->
439    <<I:Sz>>,
440    ok.
441
442not_used3(I) ->
443    <<I:(-8)>>,
444    ok.
445
446in_guard(Config) when is_list(Config) ->
447    1 = in_guard(<<16#74ad:16>>, 16#e95, 5),
448    2 = in_guard(<<16#3A,16#F7,"hello">>, 16#3AF7, <<"hello">>),
449    3 = in_guard(<<16#FBCD:14,3.1415/float,3:2>>, 16#FBCD, 3.1415),
450    3 = in_guard(<<16#FBCD:14,3/float,3:2>>, 16#FBCD, 3),
451    3 = in_guard(<<16#FBCD:14,(2 bsl 226)/float,3:2>>, 16#FBCD, 2 bsl 226),
452    nope = in_guard(<<1>>, 42, b),
453    nope = in_guard(<<1>>, a, b),
454    nope = in_guard(<<1,2>>, 1, 1),
455    nope = in_guard(<<4,5>>, 1, 2.71),
456    nope = in_guard(<<4,5>>, 1, <<12,13>>),
457    ok.
458
459in_guard(Bin, A, B) when <<A:13,B:3>> == Bin -> 1;
460in_guard(Bin, A, B) when <<A:16,B/binary>> == Bin -> 2;
461in_guard(Bin, A, B) when <<A:14,B/float,3:2>> == Bin -> 3;
462in_guard(Bin, A, B) when {a,b,<<A:14,B/float,3:2>>} == Bin -> cant_happen;
463in_guard(_, _, _) -> nope.
464
465%% Make sure that construction has no memory leak.
466mem_leak(Config) when is_list(Config) ->
467    B = make_bin(16, <<0>>),
468    mem_leak(1024, B),
469    ok.
470
471mem_leak(0, _) -> ok;
472mem_leak(N, B) ->
473    big_bin(B, <<23>>),
474    {'EXIT',{badarg,_}} = (catch big_bin(B, bad)),
475    mem_leak(N-1, B).
476
477big_bin(B1, B2) ->
478    <<B1/binary,B1/binary,B1/binary,B1/binary,
479      B1/binary,B1/binary,B1/binary,B1/binary,
480      B1/binary,B1/binary,B1/binary,B1/binary,
481      B1/binary,B1/binary,B1/binary,B1/binary,
482      B2/binary>>.
483
484make_bin(0, Acc) -> Acc;
485make_bin(N, Acc) -> make_bin(N-1, <<Acc/binary,Acc/binary>>).
486
487-define(COF(Int0),
488	(fun(Int) ->
489		 true = <<Int:32/float>> =:= <<(float(Int)):32/float>>,
490		 true = <<Int:64/float>> =:= <<(float(Int)):64/float>>
491	 end)(nonliteral(Int0)),
492	true = <<Int0:32/float>> =:= <<(float(Int0)):32/float>>,
493	true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>).
494
495-define(COF64(Int0),
496	(fun(Int) ->
497		 true = <<Int:64/float>> =:= <<(float(Int)):64/float>>
498	 end)(nonliteral(Int0)),
499	true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>).
500
501nonliteral(X) -> X.
502
503coerce_to_float(Config) when is_list(Config) ->
504    ?COF(0),
505    ?COF(-1),
506    ?COF(1),
507    ?COF(42),
508    ?COF(255),
509    ?COF(-255),
510    ?COF(38474),
511    ?COF(387498738948729893849444444443),
512    ?COF(-37489378937773899999999999999993),
513    ?COF64(298748888888888888888888888883478264866528467367364766666666666666663),
514    ?COF64(-367546729879999999999947826486652846736736476555566666663),
515    ok.
516
517bjorn(Config) when is_list(Config) ->
518    error = bjorn_1(),
519    ok.
520
521bjorn_1() ->
522    Bitstr = <<7:13>>,
523    try
524	do_something()
525    catch
526	throw:blurf ->
527	    ignore
528    end,
529    do_more(Bitstr, 13).
530
531do_more(Bin, Sz) ->
532    %% Previous bug in the bs_bits_to_bytes instruction: The exeption code
533    %% was not set - the previous exception (throw:blurf) would be used,
534    %% causing the catch to slip.
535    try <<Bin:Sz/binary>> of
536	_V -> ok
537    catch
538	error:_ ->
539	    error
540    end.
541
542do_something() ->
543    throw(blurf).
544
545huge_float_field(Config) when is_list(Config) ->
546    {'EXIT',{badarg,_}} = (catch <<0.0:9/float-unit:8>>),
547    huge_float_check(catch <<0.0:67108865/float-unit:64>>),
548    huge_float_check(catch <<0.0:((1 bsl 26)+1)/float-unit:64>>),
549    huge_float_check(catch <<0.0:(id(67108865))/float-unit:64>>),
550    %%  huge_float_check(catch <<0.0:((1 bsl 60)+1)/float-unit:64>>),
551    huge_float_check(catch <<3839739387439387383739387987347983:((1 bsl 26)+1)/float-unit:64>>),
552    %%  huge_float_check(catch <<3839739387439387383739387987347983:((1 bsl 60)+1)/float-unit:64>>),
553    ok.
554
555huge_float_check({'EXIT',{system_limit,_}}) -> ok;
556huge_float_check({'EXIT',{badarg,_}}) -> ok.
557
558huge_binary(Config) when is_list(Config) ->
559    16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>),
560    ok.
561
562system_limit(Config) when is_list(Config) ->
563    WordSize = erlang:system_info(wordsize),
564    BitsPerWord = WordSize * 8,
565    {'EXIT',{system_limit,_}} =
566	(catch <<0:(id(0)),42:(id(1 bsl BitsPerWord))>>),
567    {'EXIT',{system_limit,_}} =
568	(catch <<42:(id(1 bsl BitsPerWord)),0:(id(0))>>),
569    {'EXIT',{system_limit,_}} =
570	(catch <<(id(<<>>))/binary,0:(id(1 bsl 100))>>),
571
572    case WordSize of
573	4 ->
574	    system_limit_32();
575	8 ->
576	    ok
577    end.
578
579system_limit_32() ->
580    {'EXIT',{badarg,_}} = (catch <<42:(-1)>>),
581    {'EXIT',{badarg,_}} = (catch <<42:(id(-1))>>),
582    {'EXIT',{badarg,_}} = (catch <<42:(id(-389739873536870912))/unit:8>>),
583    {'EXIT',{system_limit,_}} = (catch <<42:536870912/unit:8>>),
584    {'EXIT',{system_limit,_}} = (catch <<42:(id(536870912))/unit:8>>),
585    {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:536870912/unit:8>>),
586    {'EXIT',{system_limit,_}} =
587	(catch <<0:(id(8)),42:(id(536870912))/unit:8>>),
588    ok.
589
590badarg(Config) when is_list(Config) ->
591    %% BEAM will generate a badarg exception for:
592    %%   <<0:(id(1 bsl 100)),0:(id(-1))>>
593    %% but the debugger will generate a system_limit exception.
594    %% It does not seems worthwhile to fix the debugger.
595
596    {'EXIT',{badarg,_}} =
597	(catch <<(id(<<>>))/binary,0:(id(-(1 bsl 100)))>>),
598
599    ok.
600
601copy_writable_binary(Config) when is_list(Config) ->
602    [copy_writable_binary_1(I) || I <- lists:seq(0, 256)],
603    ok.
604
605copy_writable_binary_1(_) ->
606    Bin0 = <<(id(<<>>))/binary,0,1,2,3,4,5,6,7>>,
607    SubBin = make_sub_bin(Bin0),
608    id(<<42,34,55,Bin0/binary>>),		%Make reallocation likelier.
609    Pid = spawn(fun() ->
610			copy_writable_binary_holder(Bin0, SubBin)
611		end),
612    Tab = ets:new(holder, []),
613    ets:insert(Tab, {17,Bin0}),
614    ets:insert(Tab, {42,SubBin}),
615    id(<<Bin0/binary,0:(64*1024*8)>>),
616    Pid ! self(),
617    [{17,Bin0}] = ets:lookup(Tab, 17),
618    [{42,Bin0}] = ets:lookup(Tab, 42),
619    receive
620	{Pid,Bin0,Bin0} -> ok;
621	Other ->
622	    io:format("Unexpected message: ~p", [Other]),
623	    ct:fail(failed)
624    end,
625    ok.
626
627copy_writable_binary_holder(Bin, SubBin) ->
628    receive
629	Pid ->
630	    Pid ! {self(),Bin,SubBin}
631    end.
632
633make_sub_bin(Bin0) ->
634    N = bit_size(Bin0),
635    <<_:17,Bin:N/bitstring,_:5>> = <<(-1):17,Bin0/bitstring,(-1):5>>,
636    Bin = Bin0,					%Assertion.
637    Bin.
638
639%% Test that different ways of using bit syntax instructions
640%% give the same result.
641
642dynamic(Config) when is_list(Config) ->
643    Ps = [spawn_monitor(fun() ->
644				dynamic_1(Fun)
645			end) || Fun <- [fun dynamic_big/5,
646					fun dynamic_little/5]],
647    [receive
648	 {'DOWN',Ref,process,Pid,normal} ->
649	     ok;
650	 {'DOWN',Ref,process,Pid,Exit} ->
651	     ct:fail({Pid,Exit})
652     end || {Pid,Ref} <- Ps],
653    ok.
654
655dynamic_1(Dynamic) ->
656    <<Lpad:64,_/binary>> = erlang:md5([0]),
657    <<Rpad:64,_/binary>> = erlang:md5([1]),
658    <<Int:64,_/binary>> = erlang:md5([2]),
659    2145 = dynamic_2(0, {Int,Lpad,Rpad,Dynamic}, 0).
660
661dynamic_2(64+1, _, Count) -> Count;
662dynamic_2(Bef, Data, Count0) ->
663    Count = dynamic_3(Bef, 64-Bef, Data, Count0),
664    dynamic_2(Bef+1, Data, Count).
665
666dynamic_3(_, -1, _, Count) -> Count;
667dynamic_3(Bef, N, {Int0,Lpad,Rpad,Dynamic}=Data, Count) ->
668    Int1 = Int0 band ((1 bsl (N+3))-1),
669    Dynamic(Bef, N, Int1, Lpad, Rpad),
670    Dynamic(Bef, N, -Int1, Lpad, Rpad),
671
672    %% OTP-7085: Test a small number in a wide field.
673    Int2 = Int0 band 16#FFFFFF,
674    Dynamic(Bef, N, Int2, Lpad, Rpad),
675    Dynamic(Bef, N, -Int2, Lpad, Rpad),
676    dynamic_3(Bef, N-1, Data, Count+1).
677
678dynamic_big(Bef, N, Int, Lpad, Rpad) ->
679    NumBin = id(<<Int:N>>),
680    MaskedInt = Int band ((1 bsl N) - 1),
681    <<MaskedInt:N>> = NumBin,
682
683    %% Construct the binary in two different ways.
684    Bin = id(<<Lpad:Bef,NumBin/bitstring,Rpad:(64-Bef-N)>>),
685    Bin = <<Lpad:Bef,Int:N,Rpad:(64-Bef-N)>>,
686
687    %% Further verify the result by matching.
688    LpadMasked = Lpad band ((1 bsl Bef) - 1),
689    RpadMasked = Rpad band ((1 bsl (64-Bef-N)) - 1),
690    Rbits = (64-Bef-N),
691    <<LpadMasked:Bef,MaskedInt:N,RpadMasked:Rbits>> = id(Bin),
692    ok.
693
694dynamic_little(Bef, N, Int, Lpad, Rpad) ->
695    NumBin = id(<<Int:N/little>>),
696    MaskedInt = Int band ((1 bsl N) - 1),
697    <<MaskedInt:N/little>> = NumBin,
698
699    %% Construct the binary in two different ways.
700    Bin = id(<<Lpad:Bef/little,NumBin/bitstring,Rpad:(64-Bef-N)/little>>),
701    Bin = <<Lpad:Bef/little,Int:N/little,Rpad:(64-Bef-N)/little>>,
702
703    %% Further verify the result by matching.
704    LpadMasked = Lpad band ((1 bsl Bef) - 1),
705    RpadMasked = Rpad band ((1 bsl (64-Bef-N)) - 1),
706    Rbits = (64-Bef-N),
707    <<LpadMasked:Bef/little,MaskedInt:N/little,RpadMasked:Rbits/little>> = id(Bin),
708    ok.
709
710otp_7422(Config) when is_list(Config) ->
711    otp_7422_int(0),
712    otp_7422_bin(0).
713
714otp_7422_int(N) when N < 512 ->
715    T = erlang:make_tuple(N, []),
716    spawn_link(fun() ->
717		       id(T),
718		       %% A size of field 0 would write one byte beyond
719		       %% the current position in the binary. It could
720		       %% overwrite the continuation pointer stored on
721		       %% the stack if HTOP was equal to E (the stack pointer).
722		       id(<<0:(id(0))>>)
723	       end),
724    otp_7422_int(N+1);
725otp_7422_int(_) -> ok.
726
727otp_7422_bin(N) when N < 512 ->
728    T = erlang:make_tuple(N, []),
729    Z = id(<<>>),
730    spawn_link(fun() ->
731		       id(T),
732		       id(<<Z:(id(0))/bits>>)
733	       end),
734    otp_7422_bin(N+1);
735otp_7422_bin(_) -> ok.
736
737zero_width(Config) when is_list(Config) ->
738    Z = id(0),
739    Small = id(42),
740    Big = id(1 bsl 128),
741    <<>> = <<Small:Z>>,
742    <<>> = <<Small:0>>,
743    <<>> = <<Big:Z>>,
744    <<>> = <<Big:0>>,
745
746    {'EXIT',{badarg,_}} = (catch <<not_a_number:0>>),
747    {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):Z>>),
748    {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):0>>),
749
750    ok.
751
752id(I) -> I.
753