1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2015-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-module(beam_utils_SUITE). 21 22-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1, 23 init_per_group/2,end_per_group/2, 24 apply_fun/1,apply_mf/1,bs_init/1,bs_save/1, 25 is_not_killed/1,is_not_used_at/1, 26 select/1,y_catch/1,otp_8949_b/1,liveopt/1,coverage/1, 27 y_registers/1,user_predef/1,scan_f/1,cafu/1, 28 receive_label/1,read_size_file_version/1,not_used/1, 29 is_used_fr/1,unsafe_is_function/1]). 30-export([id/1]). 31 32suite() -> [{ct_hooks,[ts_install_cth]}]. 33 34all() -> 35 [{group,p}]. 36 37groups() -> 38 [{p,[parallel], 39 [apply_fun, 40 apply_mf, 41 bs_init, 42 bs_save, 43 is_not_killed, 44 is_not_used_at, 45 select, 46 y_catch, 47 otp_8949_b, 48 liveopt, 49 coverage, 50 y_registers, 51 user_predef, 52 scan_f, 53 cafu, 54 read_size_file_version, 55 not_used, 56 is_used_fr, 57 unsafe_is_function 58 ]}]. 59 60init_per_suite(Config) -> 61 test_lib:recompile(?MODULE), 62 Config. 63 64end_per_suite(_Config) -> 65 ok. 66 67init_per_group(_GroupName, Config) -> 68 Config. 69 70end_per_group(_GroupName, Config) -> 71 Config. 72 73apply_fun(_Config) -> 74 3 = do_apply_fun(false, false), 75 3 = do_apply_fun(false, true), 76 3 = do_apply_fun(true, false), 77 2 = do_apply_fun(true, true), 78 ok. 79 80do_apply_fun(X, Y) -> 81 F = fun(I) -> I+1 end, 82 Arg = case X andalso id(Y) of 83 true -> 1; 84 false -> 2 85 end, 86 F(Arg). 87 88apply_mf(_Config) -> 89 ok = do_apply_mf_used({a,b}, ?MODULE, id), 90 error = do_apply_mf_used([a], ?MODULE, id), 91 {'EXIT',{{case_clause,{[],b}},_}} = (catch do_apply_mf_used({[],b}, ?MODULE, id)), 92 93 error = do_apply_mf_killed({error,[a]}, ?MODULE, id), 94 ok = do_apply_mf_killed([b], ?MODULE, id), 95 {'EXIT',{{case_clause,{a,[b]}},_}} = (catch do_apply_mf_killed({a,[b]}, ?MODULE, id)), 96 {'EXIT',{{case_clause,{error,[]}},_}} = (catch do_apply_mf_killed({error,[]}, ?MODULE, id)), 97 98 ok. 99 100do_apply_mf_used(Arg, Mod, Func) -> 101 Res = case id(Arg) of 102 {Decoded,_} when Decoded =/= [] -> 103 ok; 104 List when is_list(List) -> 105 error 106 end, 107 Mod:Func(Res). 108 109do_apply_mf_killed(Arg, Mod, Func) -> 110 Res = case id(Arg) of 111 {Tag,Decoded} when Decoded =/= [], Tag =:= error -> 112 error; 113 List when is_list(List) -> 114 ok 115 end, 116 Mod:Func(Res). 117 118bs_init(_Config) -> 119 <<7>> = do_bs_init_1([?MODULE], 7), 120 error = do_bs_init_1([?MODULE], 0.0), 121 error = do_bs_init_1([?MODULE], -43), 122 error = do_bs_init_1([?MODULE], 42), 123 124 <<>> = do_bs_init_2([]), 125 <<0:32,((1 bsl 32)-1):32>> = do_bs_init_2([0,(1 bsl 32)-1]), 126 {'EXIT',{badarg,_}} = (catch do_bs_init_2([0.5])), 127 {'EXIT',{badarg,_}} = (catch do_bs_init_2([-1])), 128 {'EXIT',{badarg,_}} = (catch do_bs_init_2([1 bsl 32])), 129 130 <<>> = do_bs_init_3({tag,0}, 0, 0), 131 <<0>> = do_bs_init_3({tag,0}, 2, 1), 132 133 <<"_build/shared">> = do_bs_init_4([], false), 134 <<"abc/shared">> = do_bs_init_4(<<"abc">>, false), 135 <<"foo/foo">> = do_bs_init_4(<<"foo">>, true), 136 error = do_bs_init_4([], not_boolean), 137 138 Id = 17575, 139 Domain = -8798798, 140 [<<10,1:16,Id:16/signed>>,<<8,2:16,Domain:32/signed>>] = 141 do_bs_init_5(#{tag=>value,id=>Id,domain=>Domain}), 142 {'EXIT',{{required,id},[_|_]}} = 143 (catch do_bs_init_5(#{tag=>value,id=>nil,domain=>Domain})), 144 {'EXIT',{{required,domain},[_|_]}} = 145 (catch do_bs_init_5(#{tag=>value,id=>Id,domain=>nil})), 146 147 ok. 148 149do_bs_init_1([?MODULE], Sz) -> 150 if 151 is_integer(Sz), Sz >= -42, Sz < 42 -> 152 id(<<Sz:8>>); 153 true -> 154 error 155 end. 156 157do_bs_init_2(SigNos) -> 158 << <<SigNo:32>> || 159 SigNo <- SigNos, 160 (is_integer(SigNo) andalso SigNo >= 0 andalso SigNo < (1 bsl 32)) orelse 161 erlang:error(badarg) 162 >>. 163 164do_bs_init_3({tag,Pos}, Offset, Len) -> 165 N0 = Offset - Pos, 166 N = if N0 > Len -> Len; 167 true -> N0 168 end, 169 <<0:N/unit:8>>. 170 171do_bs_init_4(Arg1, Arg2) -> 172 Build = 173 case id(Arg1) of 174 X when X =:= [] orelse X =:= false -> <<"_build">>; 175 X -> X 176 end, 177 case id(Arg2) of 178 true -> 179 id(<<case Build of 180 Rewrite when is_binary(Rewrite) -> 181 Rewrite; 182 Rewrite -> 183 id(Rewrite) 184 end/binary, 185 "/", 186 case id(<<"foo">>) of 187 Rewrite when is_binary(Rewrite) -> 188 Rewrite; 189 Rewrite -> 190 id(Rewrite) 191 end/binary>>); 192 false -> 193 id(<<case Build of 194 Rewrite when is_binary(Rewrite) -> 195 Rewrite; 196 Rewrite -> 197 id(Rewrite) 198 end/binary, 199 "/shared">>); 200 _Other -> 201 error 202 end. 203 204do_bs_init_5(#{tag := value, id := Id, domain := Domain}) -> 205 [case Id of 206 nil -> 207 error(id({required, id})); 208 _ -> 209 <<10, 1:16/signed, Id:16/signed>> 210 end, 211 case Domain of 212 nil -> 213 error(id({required, domain})); 214 _ -> 215 <<8, 2:16/signed, Domain:32/signed>> 216 end]. 217 218bs_save(_Config) -> 219 {a,30,<<>>} = do_bs_save(<<1:1,30:5>>), 220 {b,127,<<>>} = do_bs_save(<<1:1,31:5,0:1,127:7>>), 221 {c,127,<<>>} = do_bs_save(<<1:1,31:5,1:1,127:7>>), 222 {c,127,<<>>} = do_bs_save(<<0:1,31:5,1:1,127:7>>), 223 {d,1024,<<>>} = do_bs_save(<<0:1,31:5>>), 224 ok. 225 226do_bs_save(<<_:1, Tag:5, T/binary>>) when Tag < 31 -> 227 {a,Tag,T}; 228do_bs_save(<<1:1, 31:5, 0:1, Tag:7, T/binary>>) -> 229 {b,Tag,T}; 230do_bs_save(<<_:1, 31:5, 1:1, Tag:7, T/binary>>) -> 231 {c,Tag,T}; 232do_bs_save(<<_:1, 31:5, T/binary>>) -> 233 {d,1024,T}. 234 235is_not_killed(_Config) -> 236 {Pid,Ref} = spawn_monitor(fun() -> exit(banan) end), 237 receive 238 {'DOWN', Ref, process, Pid, banan} -> 239 ok 240 end, 241 receive after 0 -> ok end. 242 243is_not_used_at(_Config) -> 244 {a,b} = do_is_not_used_at(a, [{a,b}]), 245 {a,b} = do_is_not_used_at(a, [x,{a,b}]), 246 {a,b} = do_is_not_used_at(a, [{x,y},{a,b}]), 247 none = do_is_not_used_at(z, [{a,b}]), 248 none = do_is_not_used_at(a, [x]), 249 none = do_is_not_used_at(a, [{x,y}]), 250 ok. 251 252do_is_not_used_at(Key, [P|Ps]) -> 253 if 254 tuple_size(P) >= 1, element(1, P) =:= Key -> 255 P; 256 true -> 257 do_is_not_used_at(Key, Ps) 258 end; 259do_is_not_used_at(_Key, []) -> none. 260 261-record(select, {fixed=false}). 262 263select(_Config) -> 264 a = do_select(#select{}, 0, 0), 265 b = do_select(#select{}, 0, 1), 266 c = do_select(#select{fixed=true}, 0, 0), 267 c = do_select(#select{fixed=true}, 0, 1), 268 ok. 269 270do_select(Head, OldSize, BSize) -> 271 Overwrite0 = 272 if 273 OldSize =:= BSize -> same; 274 true -> true 275 end, 276 Overwrite = 277 if 278 Head#select.fixed =/= false -> 279 false; 280 true -> 281 Overwrite0 282 end, 283 if 284 Overwrite =:= same -> 285 a; 286 Overwrite -> 287 b; 288 true -> 289 c 290 end. 291 292y_catch(_Config) -> 293 ok = try 294 do_y_catch(<<"<?xmlX">>, {state}), 295 failed 296 catch 297 throw:{<<"<?xmlX">>,{state}} -> 298 ok 299 end. 300 301do_y_catch(<<"<?xml",Rest0/binary>> = Bytes, State0) -> 302 {Rest1,State1} = 303 case do_y_catch_1(Rest0, State0) of 304 false -> 305 {Bytes,State0}; 306 true -> 307 {_XmlAttributes, R, S} = do_y_catch_2(Rest0), 308 {R,S} 309 end, 310 case catch id({Rest1,State1}) of 311 Other -> 312 throw(Other) 313 end. 314 315do_y_catch_1(<<_,_/binary>>, _) -> 316 false. 317 318do_y_catch_2(_) -> {a,b,c}. 319 320otp_8949_b(_Config) -> 321 self() ! something, 322 value = otp_8949_b([], false), 323 {'EXIT',_} = (catch otp_8949_b([], true)), 324 ok. 325 326%% Would cause an endless loop in beam_utils. 327otp_8949_b(A, B) -> 328 Var = id(value), 329 if 330 A == [], B == false -> 331 ok 332 end, 333 receive 334 something -> 335 id(Var) 336 end. 337 338-record(alarmInfo, {type,cause,origin}). 339 340liveopt(_Config) -> 341 F = liveopt_fun(42, pebkac, user), 342 void = F(42, #alarmInfo{type=sctp,cause=pebkac,origin=user}), 343 344 345 A = {#alarmInfo{cause = {abc, def}}, ghi}, 346 A = liveopt_guard_bif(A), 347 348 B = {#alarmInfo{cause = {abc}}, def}, 349 {#alarmInfo{cause = {{abc}}}, def} = liveopt_guard_bif(B), 350 351 ok. 352 353liveopt_fun(Peer, Cause, Origin) -> 354 fun(PeerNo, AlarmInfo) 355 when PeerNo == Peer andalso 356 AlarmInfo == #alarmInfo{type=sctp, 357 cause=Cause, 358 origin=Origin} -> 359 void 360 end. 361 362liveopt_guard_bif({#alarmInfo{cause=F}=R, X}=A) -> 363 %% ERIERL-48 364 if 365 is_tuple(F), tuple_size(F) == 2 -> A; 366 true -> 367 R2 = R#alarmInfo{cause={F}}, 368 {R2,X} 369 end. 370 371%% Thanks to QuickCheck. 372coverage(_Config) -> 373 42+7 = merchant([[],7,false]), 374 375 {'EXIT',{{try_clause,0},_}} = (catch resulting([0], stone)), 376 0.0 = resulting([true], stone), 377 378 {'EXIT',{if_clause,_}} = (catch clinic(false)), 379 {'EXIT',{{try_clause,"trials"},_}} = (catch clinic(true)), 380 381 {'EXIT',{function_clause,_}} = (catch town(overall, {{abc},alcohol})), 382 383 self() ! junk_message, 384 {"url",#{true:="url"}} = appointment(#{"resolution" => "url"}), 385 386 ok. 387 388%% Cover check_liveness/3. 389merchant([Merchant, Laws, Electric]) -> 390 id(42), 391 oklahoma([[] || 0 <- Merchant], 392 if true; Electric -> Laws end) + 42. 393oklahoma([], Int) -> Int. 394 395town(overall, {{If}, Healing = alcohol}) 396 when Healing#{[] => Healing}; include -> 397 [If || Healing <- awareness]. 398 399%% Cover is_reg_used_at/3. 400resulting([Conservation], stone) -> 401 try 0 of 402 Conservation when Conservation -> Conservation; 403 _ when Conservation; 0 -> 0.0 404 after 405 Conservation 406 end. 407 408%% Cover is_reg_used_at_1/3. 409clinic(Damage) -> 410 if 411 Damage -> 412 try "trials" of Damage when Damage -> Damage catch true -> [] end 413 end, 414 carefully. 415 416y_registers(_Config) -> 417 {'EXIT',{{badfun,0},_}} = (catch economic(0.0, jim)), 418 {'EXIT',{{badmatch,apartments},_}} = (catch louisiana()), 419 {a,b} = (boxes(true))({a,b}), 420 {'EXIT',{{case_clause,webmaster},_}} = (catch yellow(true)), 421 ok. 422 423economic(0.0 = Serves, Existence) -> 424 case Serves of 425 Serves -> 0 426 end, 427 Existence = jim, 428 0(), 429 Serves, 430 Existence. 431 432louisiana() -> 433 {catch necessarily, 434 try 435 [] == reg, 436 true = apartments 437 catch [] -> barbara 438 end}. 439 440boxes(Call) -> 441 case Call of 442 Call -> approval 443 end, 444 Call, 445 fun id/1. 446 447yellow(Hill) -> 448 case webmaster of 449 station -> eyes; Hill -> 450 "under" 451 end, 452 Hill, 453 id(42). 454 455do(A, B) -> {A,B}. 456appointment(#{"resolution" := Url}) -> 457 do(receive _ -> Url end, #{true => Url}). 458 459%% From epp.erl. 460user_predef(_Config) -> 461 #{key:="value"} = user_predef({key,"value"}, #{}), 462 #{key:="value"} = user_predef({key,"value"}, #{key=>defined}), 463 error = user_predef({key,"value"}, #{key=>[defined]}), 464 ok. 465 466user_predef({M,Val}, Ms) -> 467 case Ms of 468 #{M:=Defs} when is_list(Defs) -> 469 error; 470 _ -> 471 Ms#{M=>Val} 472 end. 473 474%% From disk_log_1.erl. 475scan_f(_Config) -> 476 {1,<<>>,[]} = scan_f(<<1:32>>, 1, []), 477 {1,<<>>,[<<156>>]} = scan_f(<<1:32,156,1:32>>, 1, []), 478 ok. 479 480scan_f(<<Size:32,Tail/binary>>, FSz, Acc) when Size =< FSz -> 481 case Tail of 482 <<BinTerm:Size/binary,Tail2/binary>> -> 483 scan_f(Tail2, FSz, [BinTerm | Acc]); 484 _ -> 485 {Size,Tail,Acc} 486 end. 487 488%% From file_io_server.erl. 489cafu(_Config) -> 490 error = cafu(<<42:32>>, -1, 0, {utf32,big}), 491 error = cafu(<<42:32>>, 10, 0, {utf32,big}), 492 error = cafu(<<42:32>>, -1, 0, {utf32,little}), 493 ok. 494 495cafu(<<_/big-utf32,Rest/binary>>, N, Count, {utf32,big}) when N < 0 -> 496 cafu(Rest, -1, Count+1, {utf32,big}); 497cafu(<<_/big-utf32,Rest/binary>>, N, Count, {utf32,big}) -> 498 cafu(Rest, N-1, Count+1, {utf32,big}); 499cafu(<<_/little-utf32,Rest/binary>>, N, Count, {utf32,little}) when N < 0 -> 500 cafu(Rest, -1, Count+1, {utf32,little}); 501cafu(_, _, _, _) -> 502 error. 503 504-record(rec_label, {bool}). 505 506receive_label(_Config) -> 507 Pid = spawn_link(fun() -> do_receive_label(#rec_label{bool=true}) end), 508 Msg = {a,b,c}, 509 Pid ! {self(),Msg}, 510 receive 511 {ok,Msg} -> 512 unlink(Pid), 513 exit(Pid, die), 514 ok 515 end. 516 517do_receive_label(Rec) -> 518 receive 519 {From,Message} when Rec#rec_label.bool -> 520 From ! {ok,Message}, 521 do_receive_label(Rec) 522 end. 523 524read_size_file_version(_Config) -> 525 ok = do_read_size_file_version({ok,<<42>>}), 526 {ok,7777} = do_read_size_file_version({ok,<<7777:32>>}), 527 ok. 528 529do_read_size_file_version(E) -> 530 case E of 531 {ok,<<Version>>} when Version =:= 42 -> 532 ok; 533 {ok,<<MaxFiles:32>>} -> 534 {ok,MaxFiles} 535 end. 536 537-record(s, { a, b }). 538-record(k, { v }). 539 540not_used(_Config) -> 541 [] = not_used_p(any, #s{b=true}, #k{}, ignored), 542 #k{v=42} = not_used_p(any, #s{b=false}, #k{v=42}, ignored), 543 #k{v=42} = not_used_p(any, #s{b=bad}, #k{v=42}, ignored), 544 ok. 545 546not_used_p(_C, S, K, L) when is_record(K, k) -> 547 if ((S#s.b) and 548 (S#s.b)) -> 549 []; 550 true -> 551 id(L), 552 id(K#k.v), 553 id(K) 554 end. 555 556is_used_fr(_Config) -> 557 1 = is_used_fr(self(), self()), 558 1 = is_used_fr(self(), other), 559 receive 1 -> ok end, 560 receive 1 -> ok end, 561 receive 1 -> ok end, 562 receive 1 -> ok end, 563 ok. 564 565is_used_fr(X, Y) -> 566 %% beam_utils:is_used({fr,R}, Code) would crash. 567 _ = 0 / (X ! 1), 568 _ = case Y of 569 X -> ok; 570 _ -> error 571 end, 572 X ! 1. 573 574%% ERL-778. 575unsafe_is_function(_Config) -> 576 {undefined,any} = unsafe_is_function(undefined, any), 577 {ok,any} = unsafe_is_function(fun() -> ok end, any), 578 {'EXIT',{{case_clause,_},_}} = (catch unsafe_is_function(fun(_) -> ok end, any)), 579 ok. 580 581unsafe_is_function(F, M) -> 582 %% There would be an internal consistency failure: 583 %% Instruction: {bif,is_function,{f,0},[{x,0},{integer,0}],{x,2}} 584 %% Error: {uninitialized_reg,{y,0}}: 585 586 NewValue = case is_function(F, 0) of 587 true -> F(); 588 false when F =:= undefined -> undefined 589 end, 590 {NewValue,M}. 591 592 593%% The identity function. 594id(I) -> I. 595