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