1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2005-2018. 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(bif_SUITE).
22
23-include_lib("common_test/include/ct.hrl").
24-include_lib("kernel/include/file.hrl").
25
26-export([all/0, suite/0,
27	 display/1, display_huge/0, display_string/1,
28	 erl_bif_types/1,guard_bifs_in_erl_bif_types/1,
29	 shadow_comments/1,list_to_utf8_atom/1,
30	 specs/1,improper_bif_stubs/1,auto_imports/1,
31	 t_list_to_existing_atom/1,os_env/1,otp_7526/1,
32	 binary_to_atom/1,binary_to_existing_atom/1,
33	 atom_to_binary/1,min_max/1, erlang_halt/1,
34         erl_crash_dump_bytes/1,
35	 is_builtin/1, error_stacktrace/1,
36	 error_stacktrace_during_call_trace/1,
37         group_leader_prio/1, group_leader_prio_dirty/1,
38         is_process_alive/1,
39         process_info_blast/1,
40         os_env_case_sensitivity/1]).
41
42suite() ->
43    [{ct_hooks,[ts_install_cth]},
44     {timetrap, {minutes, 1}}].
45
46all() ->
47    [erl_bif_types, guard_bifs_in_erl_bif_types, shadow_comments,
48     specs, improper_bif_stubs, auto_imports,
49     t_list_to_existing_atom, os_env, otp_7526,
50     display, display_string, list_to_utf8_atom,
51     atom_to_binary, binary_to_atom, binary_to_existing_atom,
52     erl_crash_dump_bytes, min_max, erlang_halt, is_builtin,
53     error_stacktrace, error_stacktrace_during_call_trace,
54     group_leader_prio, group_leader_prio_dirty,
55     is_process_alive, process_info_blast, os_env_case_sensitivity].
56
57%% Uses erlang:display to test that erts_printf does not do deep recursion
58display(Config) when is_list(Config) ->
59    Pa = filename:dirname(code:which(?MODULE)),
60    {ok, Node} = test_server:start_node(display_huge_term,peer,
61					[{args, "-pa \""++Pa++"\""}]),
62    true = rpc:call(Node,?MODULE,display_huge,[]),
63    test_server:stop_node(Node),
64    ok.
65
66display_huge() ->
67    erlang:display(deeep(100000)).
68
69deeep(0,Acc) ->
70    Acc;
71deeep(N,Acc) ->
72    deeep(N-1,[Acc|[]]).
73
74deeep(N) ->
75    deeep(N,[hello]).
76
77display_string(Config) when is_list(Config) ->
78    true = erlang:display_string("hej"),
79    true = erlang:display_string(""),
80    true = erlang:display_string("hopp"),
81    true = erlang:display_string("\n"),
82    true = erlang:display_string(lists:seq(1100,1200)),
83    {error,badarg} = try
84                         erlang:display_string(atom),
85                         ok
86                     catch
87                         T0:E0 ->
88                             {T0, E0}
89                     end,
90    {error,badarg} = try
91                         erlang:display_string(make_ref()),
92                         ok
93                     catch
94                         T1:E1 ->
95                             {T1, E1}
96                     end,
97    ok.
98
99erl_bif_types(Config) when is_list(Config) ->
100    ensure_erl_bif_types_compiled(),
101
102    List0 = erlang:system_info(snifs),
103
104    %% Ignore missing type information for hipe BIFs.
105    List = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs],
106
107    KnownTypes = [MFA || MFA <- List, known_types(MFA)],
108    io:format("There are ~p BIFs with type information in erl_bif_types.",
109	      [length(KnownTypes)]),
110    erl_bif_types_2(KnownTypes).
111
112erl_bif_types_2(List) ->
113    BadArity = [MFA || {M,F,A}=MFA <- List,
114		       begin
115			   Types = erl_bif_types:arg_types(M, F, A),
116			   length(Types) =/= A
117		       end],
118    case BadArity of
119	[] ->
120	    erl_bif_types_3(List);
121	[_|_] ->
122	    io:put_chars("Bifs with bad arity\n"),
123	    io:format("~p\n", [BadArity]),
124	    ct:fail({length(BadArity),bad_arity})
125    end.
126
127erl_bif_types_3(List) ->
128    BadSmokeTest = [MFA || {M,F,A}=MFA <- List,
129			   begin
130			       try erl_bif_types:type(M, F, A) of
131				   Type ->
132				       %% Test that type is returned.
133				       not erl_types:is_erl_type(Type)
134			       catch
135				   Class:Error ->
136				       io:format("~p: ~p ~p\n",
137						 [MFA,Class,Error]),
138				       true
139			       end
140			   end],
141    case BadSmokeTest of
142	[] ->
143	    ok;
144	[_|_] ->
145	    io:put_chars("Bifs with failing calls to erlang_bif_types:type/3 "
146			 "(or with bogus return values):\n"),
147	    io:format("~p\n", [BadSmokeTest]),
148	    ct:fail({length(BadSmokeTest),bad_smoke_test})
149    end.
150
151guard_bifs_in_erl_bif_types(_Config) ->
152    ensure_erl_bif_types_compiled(),
153
154    List0 = erlang:system_info(snifs),
155    List = [{F,A} || {erlang,F,A} <- List0,
156		     erl_internal:guard_bif(F, A)],
157    Not = [FA || {F,A}=FA <- List,
158		 not erl_bif_types:is_known(erlang, F, A)],
159    case Not of
160	[] ->
161	    ok;
162	[_|_] ->
163	    io:put_chars(
164	      ["Dialyzer requires that all guard BIFs "
165	       "have type information in erl_bif_types.\n\n"
166	       "The following guard BIFs have no type information "
167	       "in erl_bif_types:\n\n",
168	       [io_lib:format("  ~p/~p\n", [F,A]) || {F,A} <- Not]]),
169	    ct:fail(erl_bif_types)
170    end.
171
172shadow_comments(_Config) ->
173    ensure_erl_bif_types_compiled(),
174
175    ErlangList = [{erlang,F,A} || {F,A} <- erlang:module_info(exports),
176				  not is_operator(F,A)],
177    List0 = erlang:system_info(snifs),
178    List1 = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs, M =/= erlang],
179    List = List1 ++ ErlangList,
180    HasTypes = [MFA || {M,F,A}=MFA <- List,
181		       erl_bif_types:is_known(M, F, A)],
182    Path = get_code_path(),
183    BifRel = sofs:relation(HasTypes, [{m,f,a}]),
184    BifModules = sofs:to_external(sofs:projection(1, BifRel)),
185    AbstrByModule = [extract_abstract(Mod, Path) || Mod <- BifModules],
186    Specs0 = [extract_specs(Mod, Abstr) ||
187		 {Mod,Abstr} <- AbstrByModule],
188    Specs = lists:append(Specs0),
189    SpecFuns0 = [F || {F,_} <- Specs],
190    SpecFuns = sofs:relation(SpecFuns0, [{m,f,a}]),
191    HasTypesAndSpecs = sofs:intersection(BifRel, SpecFuns),
192    Commented0 = lists:append([extract_comments(Mod, Path) ||
193				  Mod <- BifModules]),
194    Commented = sofs:relation(Commented0, [{m,f,a}]),
195    {NoComments0,_,NoBifSpecs0} =
196	sofs:symmetric_partition(HasTypesAndSpecs, Commented),
197    NoComments = sofs:to_external(NoComments0),
198    NoBifSpecs = sofs:to_external(NoBifSpecs0),
199
200    case NoComments of
201	[] ->
202	    ok;
203	[_|_] ->
204	    io:put_chars(
205	      ["If a BIF stub has both a spec and has type information in "
206	       "erl_bif_types, there *must*\n"
207	       "be a comment in the source file to make that immediately "
208	       "obvious.\n\nThe following comments are missing:\n\n",
209	       [io_lib:format("%% Shadowed by erl_bif_types: ~p:~p/~p\n",
210			      [M,F,A]) || {M,F,A} <- NoComments]]),
211	    ct:fail(bif_stub)
212    end,
213
214    case NoBifSpecs of
215	[] ->
216	    ok;
217	[_|_] ->
218	    io:put_chars(
219	      ["The following functions have \"shadowed\" comments "
220	       "claiming that there is type information in erl_bif_types,\n"
221	       "but actually there is no such type information.\n\n"
222	       "Therefore, the following comments should be removed:\n\n",
223	       [io_lib:format("%% Shadowed by erl_bif_types: ~p:~p/~p\n",
224			      [M,F,A]) || {M,F,A} <- NoBifSpecs]]),
225	    ct:fail(erl_bif_types)
226    end.
227
228extract_comments(Mod, Path) ->
229    Beam = which(Mod, Path),
230    SrcDir = filename:join(filename:dirname(filename:dirname(Beam)), "src"),
231    Src = filename:join(SrcDir, atom_to_list(Mod) ++ ".erl"),
232    {ok,Bin} = file:read_file(Src),
233    Lines0 = binary:split(Bin, <<"\n">>, [global]),
234    Lines1 = [T || <<"%% Shadowed by erl_bif_types: ",T/binary>> <- Lines0],
235    {ok,ReMFA} = re:compile("([^:]*):([^/]*)/(\\d*)"),
236    Lines = [L || L <- Lines1, re:run(L, ReMFA, [{capture,[]}]) =:= match],
237    [begin
238	 {match,[M,F,A]} = re:run(L, ReMFA, [{capture,all_but_first,list}]),
239	 {list_to_atom(M),list_to_atom(F),list_to_integer(A)}
240     end || L <- Lines].
241
242ensure_erl_bif_types_compiled() ->
243    c:l(erl_bif_types),
244    case erlang:function_exported(erl_bif_types, module_info, 0) of
245	false ->
246	    %% Fail cleanly.
247	    ct:fail("erl_bif_types not compiled");
248	true ->
249	    ok
250    end.
251
252known_types({M,F,A}) ->
253    erl_bif_types:is_known(M, F, A).
254
255specs(_) ->
256    List0 = erlang:system_info(snifs),
257
258    %% Ignore missing type information for hipe BIFs.
259    List1 = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs],
260
261    %% Ignore all operators.
262    List = [MFA || MFA <- List1, not is_operator(MFA)],
263
264    %% Extract specs from the abstract code for all BIFs.
265    Path = get_code_path(),
266    BifRel = sofs:relation(List, [{m,f,a}]),
267    BifModules = sofs:to_external(sofs:projection(1, BifRel)),
268    AbstrByModule = [extract_abstract(Mod, Path) || Mod <- BifModules],
269    Specs0 = [extract_specs(Mod, Abstr) ||
270		 {Mod,Abstr} <- AbstrByModule],
271    Specs = lists:append(Specs0),
272    BifSet = sofs:set(List, [function]),
273    SpecRel0 = sofs:relation(Specs, [{function,spec}]),
274    SpecRel = sofs:restriction(SpecRel0, BifSet),
275
276    %% Find BIFs without specs.
277    NoSpecs0 = sofs:difference(BifSet, sofs:domain(SpecRel)),
278    NoSpecs = sofs:to_external(NoSpecs0),
279    case NoSpecs of
280	[] ->
281	    ok;
282	[_|_] ->
283	    io:put_chars("The following BIFs don't have specs:\n"),
284	    [print_mfa(MFA) || MFA <- NoSpecs],
285	    ct:fail(no_spec)
286    end.
287
288is_operator({erlang,F,A}) ->
289    is_operator(F,A);
290is_operator(_) -> false.
291
292is_operator(F,A) ->
293    erl_internal:arith_op(F, A) orelse
294	erl_internal:bool_op(F, A) orelse
295	erl_internal:comp_op(F, A) orelse
296	erl_internal:list_op(F, A) orelse
297	erl_internal:send_op(F, A).
298
299extract_specs(M, Abstr) ->
300    [{make_mfa(M, Name),Spec} || {attribute,_,spec,{Name,Spec}} <- Abstr].
301
302make_mfa(M, {F,A}) -> {M,F,A};
303make_mfa(M, {M,_,_}=MFA) -> MFA.
304
305improper_bif_stubs(_) ->
306    Bifs0 = erlang:system_info(snifs),
307    Bifs = [MFA || {M,_,_}=MFA <- Bifs0, M =/= hipe_bifs],
308    Path = get_code_path(),
309    BifRel = sofs:relation(Bifs, [{m,f,a}]),
310    BifModules = sofs:to_external(sofs:projection(1, BifRel)),
311    AbstrByModule = [extract_abstract(Mod, Path) || Mod <- BifModules],
312    Funcs0 = [extract_functions(Mod, Abstr) ||
313		 {Mod,Abstr} <- AbstrByModule],
314    Funcs = lists:append(Funcs0),
315    BifSet = sofs:set(Bifs, [function]),
316    FuncRel0 = sofs:relation(Funcs, [{function,code}]),
317    FuncRel = sofs:restriction(FuncRel0, BifSet),
318    [check_stub(MFA, Body) || {MFA,Body} <- sofs:to_external(FuncRel)],
319    ok.
320
321auto_imports(_Config) ->
322    Path = get_code_path(),
323    {erlang,Abstr} = extract_abstract(erlang, Path),
324    SpecFuns = [Name || {attribute,_,spec,{Name,_}} <- Abstr],
325    auto_imports(SpecFuns, 0).
326
327auto_imports([{F,A}|T], Errors) ->
328    case erl_internal:bif(F, A) of
329	false ->
330	    io:format("~p/~p: not auto-imported, but spec claims it "
331		      "is auto-imported", [F,A]),
332	    auto_imports(T, Errors+1);
333	true ->
334	    auto_imports(T, Errors)
335    end;
336auto_imports([{erlang,F,A}|T], Errors) ->
337    case erl_internal:bif(F, A) of
338	false ->
339	    auto_imports(T, Errors);
340	true ->
341	    io:format("~p/~p: auto-imported, but "
342		      "spec claims it is *not* auto-imported", [F,A]),
343	    auto_imports(T, Errors+1)
344    end;
345auto_imports([], 0) ->
346    ok;
347auto_imports([], Errors) ->
348    ct:fail({Errors,inconsistencies}).
349
350extract_functions(M, Abstr) ->
351    [{{M,F,A},Body} || {function,_,F,A,Body} <- Abstr].
352
353check_stub({erlang,apply,3}, _) ->
354    ok;
355check_stub({_,F,A}, B) ->
356    try
357	[{clause,_,Args,[],Body}] = B,
358	A = length(Args),
359	[{call,_,{remote,_,{atom,_,erlang},{atom,_,nif_error}},[_]}] = Body
360    catch
361	_:_ ->
362	    io:put_chars("Invalid body for the following BIF stub:\n"),
363	    Func = {function,0,F,A,B},
364	    io:put_chars(erl_pp:function(Func)),
365	    io:nl(),
366	    io:put_chars("The body should be: erlang:nif_error(undef)"),
367	    ct:fail(invalid_body)
368    end.
369
370list_to_utf8_atom(Config) when is_list(Config) ->
371    'hello' = atom_roundtrip("hello"),
372    'こんにちは' = atom_roundtrip("こんにちは"),
373
374    %% Test all edge cases.
375    _ = atom_roundtrip([16#80]),
376    _ = atom_roundtrip([16#7F]),
377    _ = atom_roundtrip([16#FF]),
378    _ = atom_roundtrip([16#100]),
379    _ = atom_roundtrip([16#7FF]),
380    _ = atom_roundtrip([16#800]),
381    _ = atom_roundtrip([16#D7FF]),
382    atom_badarg([16#D800]),
383    atom_badarg([16#DFFF]),
384    _ = atom_roundtrip([16#E000]),
385    _ = atom_roundtrip([16#FFFF]),
386    _ = atom_roundtrip([16#1000]),
387    _ = atom_roundtrip([16#10FFFF]),
388    atom_badarg([16#110000]),
389    ok.
390
391atom_roundtrip(String) ->
392    Atom = list_to_atom(String),
393    Atom = list_to_existing_atom(String),
394    String = atom_to_list(Atom),
395    Atom.
396
397atom_badarg(String) ->
398    {'EXIT',{badarg,_}} = (catch list_to_atom(String)),
399    {'EXIT',{badarg,_}} = (catch list_to_existing_atom(String)),
400    ok.
401
402t_list_to_existing_atom(Config) when is_list(Config) ->
403    all = list_to_existing_atom("all"),
404    ?MODULE = list_to_existing_atom(?MODULE_STRING),
405    UnlikelyStr = "dsfj923874390867er869fds9864y97jhg3973qerueoru",
406    try
407	list_to_existing_atom(UnlikelyStr),
408	ct:fail(atom_exists)
409    catch
410	error:badarg -> ok
411    end,
412
413    %% The compiler has become smarter! We need the call to id/1 in
414    %% the next line.
415    UnlikelyAtom = list_to_atom(id(UnlikelyStr)),
416    UnlikelyAtom = list_to_existing_atom(UnlikelyStr),
417    ok.
418
419os_env(Config) when is_list(Config) ->
420    EnvVar1 = "MjhgvFDrresdCghN mnjkUYg vfrD",
421    false = os:getenv(EnvVar1),
422    true = os:putenv(EnvVar1, "mors"),
423    "mors" = os:getenv(EnvVar1),
424    true = os:putenv(EnvVar1, ""),
425    case os:getenv(EnvVar1) of
426	      "" -> ok;
427	      false -> ok;
428	      BadVal -> ct:fail(BadVal)
429	  end,
430    true = os:putenv(EnvVar1, "mors"),
431    true = os:unsetenv(EnvVar1),
432    false = os:getenv(EnvVar1),
433    true = os:unsetenv(EnvVar1), % unset unset variable
434    %% os:putenv, os:getenv and os:unsetenv currently use a temp
435    %% buffer of size 1024 for storing key+value
436    os_env_long(1010, 1030, "hej hopp").
437
438os_env_long(Min, Max, _Value) when Min > Max ->
439    ok;
440os_env_long(Min, Max, Value) ->
441    EnvVar = lists:duplicate(Min, $X),
442    true = os:putenv(EnvVar, Value),
443    Value = os:getenv(EnvVar),
444    true = os:unsetenv(EnvVar),
445    os_env_long(Min+1, Max, Value).
446
447os_env_case_sensitivity(Config) when is_list(Config) ->
448    %% The keys in os:getenv/putenv must be case-insensitive on Windows, and
449    %% case-sensitive elsewhere.
450    true = os:putenv("os_env_gurka", "gaffel"),
451    Expected = case os:type() of
452                   {win32, _} -> "gaffel";
453                   _ -> false
454               end,
455    Expected = os:getenv("OS_ENV_GURKA"),
456    ok.
457
458%% Test that string:to_integer does not Halloc in wrong order.
459otp_7526(Config) when is_list(Config) ->
460    ok = test_7526(256).
461
462iterate_7526(0, Acc) -> Acc;
463iterate_7526(N, Acc) ->
464    iterate_7526(N - 1,
465		 [case string:to_integer("9223372036854775808,\n") of
466		      {Int, _Foo} -> Int
467		  end | Acc]).
468
469do_test_7526(N,M) ->
470    {Self, Ref} = {self(), make_ref()},
471    T = erlang:make_tuple(M,0),
472    spawn_opt(fun()->
473                      L = iterate_7526(N, []),
474                      BadList = [X || X <- L, X =/= 9223372036854775808],
475                      BadLen = length(BadList),
476                      M = length(tuple_to_list(T)),
477                      %%io:format("~b bad conversions: ~p~n", [BadLen, BadList]),
478                      Self ! {done, Ref, BadLen}
479              end,
480              [link,{fullsweep_after,0}]),
481    receive {done, Ref, Len} -> Len end.
482
483
484test_7526(0) ->
485    ok;
486test_7526(N) ->
487    case do_test_7526(1000,N) of
488	0 -> test_7526(N-1);
489	Other ->
490	    {error,N,Other}
491    end.
492
493-define(BADARG(E), {'EXIT',{badarg,_}} = (catch E)).
494-define(SYS_LIMIT(E), {'EXIT',{system_limit,_}} = (catch E)).
495
496binary_to_atom(Config) when is_list(Config) ->
497    HalfLong = lists:seq(0, 127),
498    HalfLongAtom = list_to_atom(HalfLong),
499    HalfLongBin = list_to_binary(HalfLong),
500    Long = lists:seq(0, 254),
501    LongAtom = list_to_atom(Long),
502    LongBin = list_to_binary(Long),
503    UnicodeLongAtom = list_to_atom([$é || _ <- lists:seq(0, 254)]),
504    UnicodeLongBin = << <<"é"/utf8>> || _ <- lists:seq(0, 254)>>,
505
506    %% latin1
507    '' = test_binary_to_atom(<<>>, latin1),
508    '\377' = test_binary_to_atom(<<255>>, latin1),
509    HalfLongAtom = test_binary_to_atom(HalfLongBin, latin1),
510    LongAtom = test_binary_to_atom(LongBin, latin1),
511
512    %% utf8
513    '' = test_binary_to_atom(<<>>, utf8),
514    HalfLongAtom = test_binary_to_atom(HalfLongBin, utf8),
515    HalfLongAtom = test_binary_to_atom(HalfLongBin, unicode),
516    UnicodeLongAtom = test_binary_to_atom(UnicodeLongBin, utf8),
517    UnicodeLongAtom = test_binary_to_atom(UnicodeLongBin, unicode),
518    [] = [C || C <- lists:seq(128, 255),
519		     begin
520			 list_to_atom([C]) =/=
521			     test_binary_to_atom(<<C/utf8>>, utf8)
522		     end],
523
524    <<"こんにちは"/utf8>> =
525	atom_to_binary(test_binary_to_atom(<<"こんにちは"/utf8>>, utf8), utf8),
526
527    %% badarg failures.
528    fail_binary_to_atom(atom),
529    fail_binary_to_atom(42),
530    fail_binary_to_atom({a,b,c}),
531    fail_binary_to_atom([1,2,3]),
532    fail_binary_to_atom([]),
533    fail_binary_to_atom(42.0),
534    fail_binary_to_atom(self()),
535    fail_binary_to_atom(make_ref()),
536    fail_binary_to_atom(<<0:7>>),
537    fail_binary_to_atom(<<42:13>>),
538    ?BADARG(binary_to_atom(id(<<>>), blurf)),
539    ?BADARG(binary_to_atom(id(<<>>), [])),
540
541    %% Bad UTF8 sequences.
542    ?BADARG(binary_to_atom(id(<<255>>), utf8)),
543    ?BADARG(binary_to_atom(id(<<255,0>>), utf8)),
544    ?BADARG(binary_to_atom(id(<<16#C0,16#80>>), utf8)), %Overlong 0.
545    <<B:1/binary, _/binary>> = id(<<194, 163>>), %Truncated character ERL-474
546    ?BADARG(binary_to_atom(B, utf8)),
547
548    %% system_limit failures.
549    ?SYS_LIMIT(binary_to_atom(id(<<0:512/unit:8,255>>), utf8)),
550    ?SYS_LIMIT(binary_to_atom(id(<<0:512/unit:8,255,0>>), utf8)),
551    ?SYS_LIMIT(binary_to_atom(<<0:256/unit:8>>, latin1)),
552    ?SYS_LIMIT(binary_to_atom(<<0:257/unit:8>>, latin1)),
553    ?SYS_LIMIT(binary_to_atom(<<0:512/unit:8>>, latin1)),
554    ?SYS_LIMIT(binary_to_atom(<<0:256/unit:8>>, utf8)),
555    ?SYS_LIMIT(binary_to_atom(<<0:257/unit:8>>, utf8)),
556    ?SYS_LIMIT(binary_to_atom(<<0:512/unit:8>>, utf8)),
557    ok.
558
559test_binary_to_atom(Bin0, Encoding) ->
560    Res = binary_to_atom(Bin0, Encoding),
561    Res = binary_to_existing_atom(Bin0, Encoding),
562    Bin1 = id(<<7:3,Bin0/binary,32:5>>),
563    Sz = byte_size(Bin0),
564    <<_:3,UnalignedBin:Sz/binary,_:5>> = Bin1,
565    Res = binary_to_atom(UnalignedBin, Encoding).
566
567fail_binary_to_atom(Bin) ->
568    try
569        binary_to_atom(Bin, latin1)
570    catch
571        error:badarg ->
572            ok
573    end,
574    try
575        binary_to_atom(Bin, utf8)
576    catch
577        error:badarg ->
578            ok
579    end,
580    try
581        binary_to_existing_atom(Bin, latin1)
582    catch
583        error:badarg ->
584            ok
585    end,
586    try
587        binary_to_existing_atom(Bin, utf8)
588    catch
589        error:badarg ->
590            ok
591    end.
592
593
594binary_to_existing_atom(Config) when is_list(Config) ->
595    UnlikelyBin = <<"ou0897979655678dsfj923874390867er869fds973qerueoru">>,
596    try
597	binary_to_existing_atom(UnlikelyBin, latin1),
598	ct:fail(atom_exists)
599    catch
600	error:badarg -> ok
601    end,
602
603    try
604	binary_to_existing_atom(UnlikelyBin, utf8),
605	ct:fail(atom_exists)
606    catch
607	error:badarg -> ok
608    end,
609
610    UnlikelyAtom = binary_to_atom(id(UnlikelyBin), latin1),
611    UnlikelyAtom = binary_to_existing_atom(UnlikelyBin, latin1),
612
613    %% ERL-944; a binary that was too large would overflow the latin1-to-utf8
614    %% conversion buffer.
615    OverflowAtom = <<0:511/unit:8,
616                     196, 133, 196, 133, 196, 133, 196, 133, 196, 133,
617                     196, 133, 196, 133, 196, 133, 196, 133, 196, 133,
618                     196, 133, 196, 133, 196, 133, 196, 133, 196, 133,
619                     196, 133, 196, 133, 196, 133, 196, 133, 196, 133>>,
620    {'EXIT', _} = (catch binary_to_existing_atom(OverflowAtom, latin1)),
621
622    ok.
623
624
625atom_to_binary(Config) when is_list(Config) ->
626    HalfLong = lists:seq(0, 127),
627    HalfLongAtom = list_to_atom(HalfLong),
628    HalfLongBin = list_to_binary(HalfLong),
629    Long = lists:seq(0, 254),
630    LongAtom = list_to_atom(Long),
631    LongBin = list_to_binary(Long),
632
633    %% latin1
634    <<>> = atom_to_binary('', latin1),
635    <<"abc">> = atom_to_binary(abc, latin1),
636    <<127>> = atom_to_binary('\177', latin1),
637    HalfLongBin = atom_to_binary(HalfLongAtom, latin1),
638    LongBin = atom_to_binary(LongAtom, latin1),
639
640    %% utf8.
641    <<>> = atom_to_binary('', utf8),
642    <<>> = atom_to_binary('', unicode),
643    <<127>> = atom_to_binary('\177', utf8),
644    <<"abcdef">> = atom_to_binary(abcdef, utf8),
645    HalfLongBin = atom_to_binary(HalfLongAtom, utf8),
646    LongAtomBin = atom_to_binary(LongAtom, utf8),
647    verify_long_atom_bin(LongAtomBin, 0),
648
649    %% Failing cases.
650    fail_atom_to_binary(<<1>>),
651    fail_atom_to_binary(42),
652    fail_atom_to_binary({a,b,c}),
653    fail_atom_to_binary([1,2,3]),
654    fail_atom_to_binary([]),
655    fail_atom_to_binary(42.0),
656    fail_atom_to_binary(self()),
657    fail_atom_to_binary(make_ref()),
658    ?BADARG(atom_to_binary(id(a), blurf)),
659    ?BADARG(atom_to_binary(id(b), [])),
660    ok.
661
662verify_long_atom_bin(<<I/utf8,T/binary>>, I) ->
663    verify_long_atom_bin(T, I+1);
664verify_long_atom_bin(<<>>, 255) -> ok.
665
666fail_atom_to_binary(Term) ->
667    try
668        atom_to_binary(Term, latin1)
669    catch
670        error:badarg ->
671            ok
672    end,
673    try
674        atom_to_binary(Term, utf8)
675    catch
676        error:badarg ->
677            ok
678    end.
679
680min_max(Config) when is_list(Config) ->
681    a = erlang:min(id(a), a),
682    a = erlang:min(id(a), b),
683    a = erlang:min(id(b), a),
684    b = erlang:min(id(b), b),
685    a = erlang:max(id(a), a),
686    b = erlang:max(id(a), b),
687    b = erlang:max(id(b), a),
688    b = erlang:max(id(b), b),
689
690    42.0 = erlang:min(42.0, 42),
691    42.0 = erlang:max(42.0, 42),
692    %% And now (R14) they are also autoimported!
693    a = min(id(a), a),
694    a = min(id(a), b),
695    a = min(id(b), a),
696    b = min(id(b), b),
697    a = max(id(a), a),
698    b = max(id(a), b),
699    b = max(id(b), a),
700    b = max(id(b), b),
701
702    42.0 = min(42.0, 42),
703    42.0 = max(42.0, 42),
704    ok.
705
706
707
708erlang_halt(Config) when is_list(Config) ->
709    try erlang:halt(undefined) of
710	_-> ct:fail({erlang,halt,{undefined}})
711    catch error:badarg -> ok end,
712    try halt(undefined) of
713	_-> ct:fail({halt,{undefined}})
714    catch error:badarg -> ok end,
715    try erlang:halt(undefined, []) of
716	_-> ct:fail({erlang,halt,{undefined,[]}})
717    catch error:badarg -> ok end,
718    try halt(undefined, []) of
719	_-> ct:fail({halt,{undefined,[]}})
720    catch error:badarg -> ok end,
721    try halt(0, undefined) of
722	_-> ct:fail({halt,{0,undefined}})
723    catch error:badarg -> ok end,
724    try halt(0, [undefined]) of
725	_-> ct:fail({halt,{0,[undefined]}})
726    catch error:badarg -> ok end,
727    try halt(0, [{undefined,true}]) of
728	_-> ct:fail({halt,{0,[{undefined,true}]}})
729    catch error:badarg -> ok end,
730    try halt(0, [{flush,undefined}]) of
731	_-> ct:fail({halt,{0,[{flush,undefined}]}})
732    catch error:badarg -> ok end,
733    try halt(0, [{flush,true,undefined}]) of
734	_-> ct:fail({halt,{0,[{flush,true,undefined}]}})
735    catch error:badarg -> ok end,
736    H = hostname(),
737    {ok,N1} = slave:start(H, halt_node1),
738    {badrpc,nodedown} = rpc:call(N1, erlang, halt, []),
739    {ok,N2} = slave:start(H, halt_node2),
740    {badrpc,nodedown} = rpc:call(N2, erlang, halt, [0]),
741    {ok,N3} = slave:start(H, halt_node3),
742    {badrpc,nodedown} = rpc:call(N3, erlang, halt, [0,[]]),
743    {ok,N4} = slave:start(H, halt_node4),
744    {badrpc,nodedown} = rpc:call(N4, erlang, halt, [lists:duplicate(300,$x)]),
745    %% Test unicode slogan
746    {ok,N4} = slave:start(H, halt_node4),
747    {badrpc,nodedown} = rpc:call(N4, erlang, halt, [[339,338,254,230,198,295,167,223,32,12507,12531,12480]]),
748
749    % This test triggers a segfault when dumping a crash dump
750    % to make sure that we can handle it properly.
751    {ok,N4} = slave:start(H, halt_node4),
752    CrashDump = filename:join(proplists:get_value(priv_dir,Config),
753                              "segfault_erl_crash.dump"),
754    true = rpc:call(N4, os, putenv, ["ERL_CRASH_DUMP",CrashDump]),
755    false = rpc:call(N4, erts_debug, set_internal_state,
756                     [available_internal_state, true]),
757    {badrpc,nodedown} = rpc:call(N4, erts_debug, set_internal_state,
758                                 [broken_halt, "Validate correct crash dump"]),
759    {ok,_} = wait_until_stable_size(CrashDump,-1),
760    {ok, Bin} = file:read_file(CrashDump),
761    case {string:find(Bin, <<"\n=end\n">>),
762          string:find(Bin, <<"\r\n=end\r\n">>)} of
763        {nomatch,nomatch} ->
764            ct:fail("Could not find end marker in crash dump");
765        {_,_} ->
766            ok
767    end.
768
769wait_until_stable_size(_File,-10) ->
770    {error,enoent};
771wait_until_stable_size(File,PrevSz) ->
772    timer:sleep(250),
773    case file:read_file_info(File) of
774        {error,enoent} ->
775            wait_until_stable_size(File,PrevSz-1);
776        {ok,#file_info{size = PrevSz }} when PrevSz /= -1 ->
777            io:format("Crashdump file size was: ~p (~s)~n",[PrevSz,File]),
778            {ok,PrevSz};
779        {ok,#file_info{size = NewSz }} ->
780            wait_until_stable_size(File,NewSz)
781    end.
782
783% Test erlang:halt with ERL_CRASH_DUMP_BYTES
784erl_crash_dump_bytes(Config) when is_list(Config) ->
785    Bytes = 1000,
786    CrashDump = do_limited_crash_dump(Config, Bytes),
787    {ok,ActualBytes} = wait_until_stable_size(CrashDump,-1),
788    true = ActualBytes < (Bytes + 100),
789
790    NoDump = do_limited_crash_dump(Config,0),
791    {error,enoent} = wait_until_stable_size(NoDump,-8),
792    ok.
793
794do_limited_crash_dump(Config, Bytes) ->
795    H = hostname(),
796    {ok,N} = slave:start(H, halt_node),
797    BytesStr = integer_to_list(Bytes),
798    CrashDump = filename:join(proplists:get_value(priv_dir,Config),
799                              "erl_crash." ++ BytesStr ++ ".dump"),
800    true = rpc:call(N, os, putenv, ["ERL_CRASH_DUMP",CrashDump]),
801    true = rpc:call(N, os, putenv, ["ERL_CRASH_DUMP_BYTES",BytesStr]),
802    {badrpc,nodedown} = rpc:call(N, erlang, halt, ["Testing ERL_CRASH_DUMP_BYTES"]),
803    CrashDump.
804
805
806is_builtin(_Config) ->
807    Exp0 = [{M,F,A} || {M,_} <- code:all_loaded(),
808		       {F,A} <- M:module_info(exports)],
809    Exp = ordsets:from_list(Exp0),
810
811    %% Built-ins implemented as special instructions.
812    Instructions = [{erlang,apply,2},{erlang,apply,3},{erlang,yield,0}],
813
814    Builtins0 = Instructions ++ erlang:system_info(snifs),
815    Builtins = ordsets:from_list(Builtins0),
816
817    Fakes = [{M,F,42} || {M,F,_} <- Instructions],
818    All = ordsets:from_list(Fakes ++ Exp),
819    NotBuiltin = ordsets:subtract(All, Builtins),
820
821    _ = [{true,_} = {erlang:is_builtin(M, F, A),MFA} ||
822            {M,F,A}=MFA <- Builtins],
823    _ = [{false,_} = {erlang:is_builtin(M, F, A),MFA} ||
824            {M,F,A}=MFA <- NotBuiltin],
825
826    ok.
827
828error_stacktrace(Config) when is_list(Config) ->
829    error_stacktrace_test().
830
831error_stacktrace_during_call_trace(Config) when is_list(Config) ->
832    Tracer = spawn_link(fun () ->
833				receive after infinity -> ok end
834			end),
835    Mprog = [{'_',[],[{exception_trace}]}],
836    erlang:trace_pattern({?MODULE,'_','_'}, Mprog, [local]),
837    1 = erlang:trace_pattern({erlang,error,2}, Mprog, [local]),
838    1 = erlang:trace_pattern({erlang,error,1}, Mprog, [local]),
839    erlang:trace(all, true, [call,return_to,timestamp,{tracer, Tracer}]),
840    try
841	error_stacktrace_test()
842    after
843	erlang:trace(all, false, [call,return_to,timestamp,{tracer, Tracer}]),
844	erlang:trace_pattern({erlang,error,2}, false, [local]),
845	erlang:trace_pattern({erlang,error,1}, false, [local]),
846	erlang:trace_pattern({?MODULE,'_','_'}, false, [local]),
847	unlink(Tracer),
848	exit(Tracer, kill),
849	Mon = erlang:monitor(process, Tracer),
850	receive
851	    {'DOWN', Mon, process, Tracer, _} -> ok
852	end
853    end,
854    ok.
855
856error_stacktrace_test() ->
857    Types = [apply_const_last, apply_const, apply_last,
858	     apply, double_apply_const_last, double_apply_const,
859	     double_apply_last, double_apply, multi_apply_const_last,
860	     multi_apply_const, multi_apply_last, multi_apply,
861	     call_const_last, call_last, call_const, call],
862    lists:foreach(fun (Type) ->
863			  {Pid, Mon} = spawn_monitor(
864					 fun () ->
865						 stk([a,b,c,d], Type, error_2)
866					 end),
867			  receive
868			      {'DOWN', Mon, process, Pid, Reason} ->
869				  {oops, Stack} = Reason,
870%%				  io:format("Type: ~p Stack: ~p~n",
871%%					    [Type, Stack]),
872				  [{?MODULE, do_error_2, [Type], _},
873				   {?MODULE, stk, 3, _},
874				   {?MODULE, stk, 3, _}] = Stack
875			  end
876		  end,
877		  Types),
878    lists:foreach(fun (Type) ->
879			  {Pid, Mon} = spawn_monitor(
880					 fun () ->
881						 stk([a,b,c,d], Type, error_1)
882					 end),
883			  receive
884			      {'DOWN', Mon, process, Pid, Reason} ->
885				  {oops, Stack} = Reason,
886%%				  io:format("Type: ~p Stack: ~p~n",
887%%					    [Type, Stack]),
888				  [{?MODULE, do_error_1, 1, _},
889				   {?MODULE, stk, 3, _},
890				   {?MODULE, stk, 3, _}] = Stack
891			  end
892		  end,
893		  Types),
894    ok.
895
896stk([], Type, Func) ->
897    tail(Type, Func, jump),
898    ok;
899stk([_|L], Type, Func) ->
900    stk(L, Type, Func),
901    ok.
902
903tail(Type, Func, jump) ->
904    tail(Type, Func, do);
905tail(Type, error_1, do) ->
906    do_error_1(Type);
907tail(Type, error_2, do) ->
908    do_error_2(Type).
909
910do_error_2(apply_const_last) ->
911    erlang:apply(erlang, error, [oops, [apply_const_last]]);
912do_error_2(apply_const) ->
913    erlang:apply(erlang, error, [oops, [apply_const]]),
914    ok;
915do_error_2(apply_last) ->
916    erlang:apply(id(erlang), id(error), id([oops, [apply_last]]));
917do_error_2(apply) ->
918    erlang:apply(id(erlang), id(error), id([oops, [apply]])),
919    ok;
920do_error_2(double_apply_const_last) ->
921    erlang:apply(erlang, apply, [erlang, error, [oops, [double_apply_const_last]]]);
922do_error_2(double_apply_const) ->
923    erlang:apply(erlang, apply, [erlang, error, [oops, [double_apply_const]]]),
924    ok;
925do_error_2(double_apply_last) ->
926    erlang:apply(id(erlang), id(apply), [id(erlang), id(error), id([oops, [double_apply_last]])]);
927do_error_2(double_apply) ->
928    erlang:apply(id(erlang), id(apply), [id(erlang), id(error), id([oops, [double_apply]])]),
929    ok;
930do_error_2(multi_apply_const_last) ->
931    erlang:apply(erlang, apply, [erlang, apply, [erlang, apply, [erlang, error, [oops, [multi_apply_const_last]]]]]);
932do_error_2(multi_apply_const) ->
933    erlang:apply(erlang, apply, [erlang, apply, [erlang, apply, [erlang, error, [oops, [multi_apply_const]]]]]),
934    ok;
935do_error_2(multi_apply_last) ->
936    erlang:apply(id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(error), id([oops, [multi_apply_last]])]]]);
937do_error_2(multi_apply) ->
938    erlang:apply(id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(error), id([oops, [multi_apply]])]]]),
939    ok;
940do_error_2(call_const_last) ->
941    erlang:error(oops, [call_const_last]);
942do_error_2(call_last) ->
943    erlang:error(id(oops), id([call_last]));
944do_error_2(call_const) ->
945    erlang:error(oops, [call_const]),
946    ok;
947do_error_2(call) ->
948    erlang:error(id(oops), id([call])).
949
950
951do_error_1(apply_const_last) ->
952    erlang:apply(erlang, error, [oops]);
953do_error_1(apply_const) ->
954    erlang:apply(erlang, error, [oops]),
955    ok;
956do_error_1(apply_last) ->
957    erlang:apply(id(erlang), id(error), id([oops]));
958do_error_1(apply) ->
959    erlang:apply(id(erlang), id(error), id([oops])),
960    ok;
961do_error_1(double_apply_const_last) ->
962    erlang:apply(erlang, apply, [erlang, error, [oops]]);
963do_error_1(double_apply_const) ->
964    erlang:apply(erlang, apply, [erlang, error, [oops]]),
965    ok;
966do_error_1(double_apply_last) ->
967    erlang:apply(id(erlang), id(apply), [id(erlang), id(error), id([oops])]);
968do_error_1(double_apply) ->
969    erlang:apply(id(erlang), id(apply), [id(erlang), id(error), id([oops])]),
970    ok;
971do_error_1(multi_apply_const_last) ->
972    erlang:apply(erlang, apply, [erlang, apply, [erlang, apply, [erlang, error, [oops]]]]);
973do_error_1(multi_apply_const) ->
974    erlang:apply(erlang, apply, [erlang, apply, [erlang, apply, [erlang, error, [oops]]]]),
975    ok;
976do_error_1(multi_apply_last) ->
977    erlang:apply(id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(error), id([oops])]]]);
978do_error_1(multi_apply) ->
979    erlang:apply(id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(error), id([oops])]]]),
980    ok;
981do_error_1(call_const_last) ->
982    erlang:error(oops);
983do_error_1(call_last) ->
984    erlang:error(id(oops));
985do_error_1(call_const) ->
986    erlang:error(oops),
987    ok;
988do_error_1(call) ->
989    erlang:error(id(oops)).
990
991
992group_leader_prio(Config) when is_list(Config) ->
993    group_leader_prio_test(false).
994
995group_leader_prio_dirty(Config) when is_list(Config) ->
996    group_leader_prio_test(true).
997
998group_leader_prio_test(Dirty) ->
999    %%
1000    %% Unfortunately back in the days node local group_leader/2 was not
1001    %% implemented as sending an asynchronous signal to the process to change
1002    %% group leader for. Instead it has always been synchronously changed, and
1003    %% nothing in the documentation have hinted otherwise... Therefore I do not
1004    %% dare the change this.
1005    %%
1006    %% In order to prevent priority inversion, the priority of the receiver of
1007    %% the group leader signal is elevated while handling incoming signals if
1008    %% the sender has a higher priority than the receiver. This test tests that
1009    %% the priority elevation actually works...
1010    %%
1011    Tester = self(),
1012    Init = erlang:whereis(init),
1013    GL = erlang:group_leader(),
1014    process_flag(priority, max),
1015    {TestProcFun, NTestProcs}
1016        = case Dirty of
1017              false ->
1018                  %% These processes will handle all incoming signals
1019                  %% by them selves...
1020                  {fun () ->
1021                           Tester ! {alive, self()},
1022                           receive after infinity -> ok end
1023                   end,
1024                   100};
1025              true ->
1026                  %% These processes wont handle incoming signals by
1027                  %% them selves since they are stuck on dirty schedulers
1028                  %% when we try to change group leader. A dirty process
1029                  %% signal handler process (system process) will be notified
1030                  %% of the need to handle incoming signals for these processes,
1031                  %% and will instead handle the signal for these processes...
1032                  {fun () ->
1033                           %% The following sends the message '{alive, self()}'
1034                           %% to Tester once on a dirty io scheduler, then wait
1035                           %% there until the process terminates...
1036                           erts_debug:dirty_io(alive_waitexiting, Tester)
1037                   end,
1038                   erlang:system_info(dirty_io_schedulers)}
1039          end,
1040    TPs = lists:map(fun (_) ->
1041                            spawn_opt(TestProcFun,
1042                                      [link, {priority, normal}])
1043                    end, lists:seq(1, NTestProcs)),
1044    lists:foreach(fun (TP) -> receive {alive, TP} -> ok end end, TPs),
1045    TLs = lists:map(fun (_) ->
1046                            spawn_opt(fun () -> tok_loop() end,
1047                                      [link, {priority, high}])
1048                    end,
1049                    lists:seq(1, 2*erlang:system_info(schedulers))),
1050    %% Wait to ensure distribution of high prio processes over schedulers...
1051    receive after 1000 -> ok end,
1052    %%
1053    %% Test that we can get group-leader signals through to normal prio
1054    %% processes from a max prio process even though all schedulers are filled
1055    %% with executing high prio processes.
1056    %%
1057    lists:foreach(fun (_) ->
1058                          lists:foreach(fun (TP) ->
1059                                                erlang:yield(),
1060                                                %% whitebox -- Enqueue some signals on it
1061                                                %% preventing us from hogging its main lock
1062                                                %% and set group-leader directly....
1063                                                erlang:demonitor(erlang:monitor(process, TP)),
1064                                                true = erlang:group_leader(Init, TP),
1065                                                {group_leader, Init} = process_info(TP, group_leader),
1066                                                erlang:demonitor(erlang:monitor(process, TP)),
1067                                                true = erlang:group_leader(GL, TP),
1068                                                {group_leader, GL} = process_info(TP, group_leader)
1069                                        end,
1070                                        TPs)
1071                  end,
1072                  lists:seq(1,100)),
1073    %%
1074    %% Also test when it is exiting...
1075    %%
1076    lists:foreach(fun (TP) ->
1077                          erlang:yield(),
1078                          M = erlang:monitor(process, TP),
1079                          unlink(TP),
1080                          exit(TP, bang),
1081                          badarg = try
1082                                       true = erlang:group_leader(Init, TP)
1083                                   catch
1084                                       error : What -> What
1085                                   end,
1086                          receive
1087                              {'DOWN', M, process, TP, Reason} ->
1088                                  bang = Reason
1089                          end
1090                  end,
1091                  TPs),
1092    lists:foreach(fun (TL) ->
1093                          M = erlang:monitor(process, TL),
1094                          unlink(TL),
1095                          exit(TL, bang),
1096                          receive
1097                              {'DOWN', M, process, TL, Reason} ->
1098                                  bang = Reason
1099                          end
1100                  end,
1101                  TLs),
1102    ok.
1103
1104is_process_alive(Config) when is_list(Config) ->
1105    process_flag(priority, max),
1106    Ps = lists:map(fun (_) ->
1107                           spawn_opt(fun () -> tok_loop() end,
1108                                     [{priority, high}, link])
1109                   end,
1110                   lists:seq(1, 2*erlang:system_info(schedulers))),
1111    receive after 1000 -> ok end, %% Wait for load to spread
1112    lists:foreach(fun (P) ->
1113                          %% Ensure that signal order is preserved
1114                          %% and that we are not starved due to
1115                          %% priority inversion
1116                          true = erlang:is_process_alive(P),
1117                          unlink(P),
1118                          true = erlang:is_process_alive(P),
1119                          exit(P, kill),
1120                          false = erlang:is_process_alive(P)
1121                  end,
1122                  Ps),
1123    ok.
1124
1125process_info_blast(Config) when is_list(Config) ->
1126    Tester = self(),
1127    NoAttackers = 1000,
1128    NoAL = lists:seq(1, NoAttackers),
1129    Consume = make_ref(),
1130    Victim = spawn_link(fun () ->
1131                                receive
1132                                    Consume ->
1133                                        ok
1134                                end,
1135                                consume_msgs()
1136                        end),
1137    AFun = fun () ->
1138                   Victim ! hej,
1139                   Res = process_info(Victim, message_queue_len),
1140                   Tester ! {self(), Res}
1141           end,
1142    Attackers0 = lists:map(fun (_) ->
1143                                   spawn_link(AFun)
1144                           end,
1145                           NoAL),
1146    lists:foreach(fun (A) ->
1147                          receive
1148                              {A, Res} ->
1149                                  case Res of
1150                                      {message_queue_len, Len} when Len > 0, Len =< NoAttackers ->
1151                                          Len;
1152                                      Error ->
1153                                          exit({unexpected, Error})
1154                                  end
1155                          end
1156                  end,
1157                  Attackers0),
1158    Attackers1 = lists:map(fun (_) ->
1159                                   spawn_link(AFun)
1160                           end,
1161                           NoAL),
1162    Victim ! Consume,
1163    lists:foreach(fun (A) ->
1164                          receive
1165                              {A, Res} ->
1166                                  case Res of
1167                                      {message_queue_len, Len} when Len >= 0, Len =< 2*NoAttackers+1 ->
1168                                          ok;
1169                                      undefined ->
1170                                          ok;
1171                                      Error ->
1172                                          exit({unexpected, Error})
1173                                  end
1174                          end
1175                  end,
1176                  Attackers1),
1177    KillFun = fun (P) ->
1178                      unlink(P),
1179                      exit(P, kill),
1180                      false = erlang:is_process_alive(P)
1181              end,
1182    lists:foreach(fun (A) -> KillFun(A) end, Attackers0),
1183    lists:foreach(fun (A) -> KillFun(A) end, Attackers1),
1184    KillFun(Victim),
1185    ok.
1186
1187consume_msgs() ->
1188    receive
1189        _ ->
1190            consume_msgs()
1191    after 0 ->
1192              ok
1193    end.
1194
1195%% helpers
1196
1197id(I) -> I.
1198
1199%% Get code path, including the path for the erts application.
1200get_code_path() ->
1201    case code:lib_dir(erts) of
1202	{error,bad_name} ->
1203	    Erts = filename:join([code:root_dir(),"erts","preloaded","ebin"]),
1204	    [Erts|code:get_path()];
1205	_ ->
1206	    code:get_path()
1207    end.
1208
1209which(Mod, Path) ->
1210    which_1(atom_to_list(Mod) ++ ".beam", Path).
1211
1212which_1(Base, [D|Ds]) ->
1213    Path = filename:join(D, Base),
1214    case filelib:is_regular(Path) of
1215	true -> Path;
1216	false -> which_1(Base, Ds)
1217    end.
1218print_mfa({M,F,A}) ->
1219    io:format("~p:~p/~p", [M,F,A]).
1220
1221extract_abstract(Mod, Path) ->
1222    Beam = which(Mod, Path),
1223    {ok,{Mod,[{abstract_code,{raw_abstract_v1,Abstr}}]}} =
1224	beam_lib:chunks(Beam, [abstract_code]),
1225    {Mod,Abstr}.
1226
1227
1228hostname() ->
1229    hostname(atom_to_list(node())).
1230
1231hostname([$@ | Hostname]) ->
1232    list_to_atom(Hostname);
1233hostname([_C | Cs]) ->
1234    hostname(Cs).
1235
1236tok_loop() ->
1237    tok_loop(hej).
1238
1239tok_loop(hej) ->
1240    tok_loop(hopp);
1241tok_loop(hopp) ->
1242    tok_loop(hej).
1243