1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2004-2020. 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_validator_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 init_per_testcase/2,end_per_testcase/2, 25 compiler_bug/1,stupid_but_valid/1, 26 xrange/1,yrange/1,stack/1,call_last/1,merge_undefined/1, 27 uninit/1,unsafe_catch/1, 28 dead_code/1, 29 overwrite_catchtag/1,overwrite_trytag/1,accessing_tags/1,bad_catch_try/1, 30 cons_guard/1, 31 freg_range/1,freg_uninit/1, 32 bad_bin_match/1,bad_dsetel/1, 33 state_after_fault_in_catch/1,no_exception_in_catch/1, 34 undef_label/1,illegal_instruction/1,failing_gc_guard_bif/1, 35 map_field_lists/1,cover_bin_opt/1, 36 val_dsetel/1,bad_tuples/1,bad_try_catch_nesting/1, 37 receive_stacked/1,aliased_types/1,type_conflict/1, 38 infer_on_eq/1,infer_dead_value/1,infer_on_ne/1, 39 branch_to_try_handler/1,call_without_stack/1, 40 receive_marker/1,safe_instructions/1, 41 missing_return_type/1,will_bif_succeed/1, 42 bs_saved_position_units/1,parent_container/1]). 43 44-include_lib("common_test/include/ct.hrl"). 45 46init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> 47 Config. 48 49end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> 50 ok. 51 52suite() -> 53 [{ct_hooks,[ts_install_cth]}, 54 {timetrap,{minutes,10}}]. 55 56all() -> 57 [{group,p}]. 58 59groups() -> 60 [{p,test_lib:parallel(), 61 [compiler_bug,stupid_but_valid,xrange, 62 yrange,stack,call_last,merge_undefined,uninit, 63 unsafe_catch,dead_code, 64 overwrite_catchtag,overwrite_trytag,accessing_tags, 65 bad_catch_try,cons_guard,freg_range,freg_uninit, 66 bad_bin_match,bad_dsetel, 67 state_after_fault_in_catch,no_exception_in_catch, 68 undef_label,illegal_instruction,failing_gc_guard_bif, 69 map_field_lists,cover_bin_opt,val_dsetel, 70 bad_tuples,bad_try_catch_nesting, 71 receive_stacked,aliased_types,type_conflict, 72 infer_on_eq,infer_dead_value,infer_on_ne, 73 branch_to_try_handler,call_without_stack, 74 receive_marker,safe_instructions, 75 missing_return_type,will_bif_succeed, 76 bs_saved_position_units,parent_container]}]. 77 78init_per_suite(Config) -> 79 test_lib:recompile(?MODULE), 80 Config. 81 82end_per_suite(_Config) -> 83 ok. 84 85init_per_group(_GroupName, Config) -> 86 Config. 87 88end_per_group(_GroupName, Config) -> 89 Config. 90 91compiler_bug(Config) when is_list(Config) -> 92 %% Check that the compiler returns an error if we try to 93 %% assemble one of the bad '.S' files. 94 Data = proplists:get_value(data_dir, Config), 95 File = filename:join(Data, "compiler_bug"), 96 error = compile:file(File, [from_asm,report_errors,time]), 97 98 %% Make sure that the error was reported by 99 %% the beam_validator module. 100 {error, 101 [{"compiler_bug", 102 [{_Pos,beam_validator,_}]}], 103 []} = compile:file(File, [from_asm,return_errors,time]), 104 ok. 105 106%% The following code is stupid but it should compile. 107stupid_but_valid(Config) when is_list(Config) -> 108 AnAtom = nisse, 109 try setelement(5, setelement(6, AnAtom, value), another_value) of 110 Term -> ct:fail({what_happened,Term}) 111 catch 112 error:badarg -> ok 113 end, 114 ok. 115 116xrange(Config) when is_list(Config) -> 117 Errors = do_val(xrange, Config), 118 [{{t,sum_1,2}, 119 {{bif,'+',{f,0},[{x,-1},{x,1}],{x,0}},4, 120 {bad_register,{x,-1}}}}, 121 {{t,sum_2,2}, 122 {{bif,'+',{f,0},[{x,0},{x,1023}],{x,0}},4,limit}}, 123 {{t,sum_3,2}, 124 {{bif,'+',{f,0},[{x,0},{x,1}],{x,-1}},4, 125 {bad_register,{x,-1}}}}, 126 {{t,sum_4,2}, 127 {{bif,'+',{f,0},[{x,0},{x,1}],{x,1023}},4,limit}}] = Errors, 128 ok. 129 130yrange(Config) when is_list(Config) -> 131 Errors = do_val(yrange, Config), 132 [{{t,sum_1,2}, 133 {{move,{x,1},{y,-1}},5, 134 {bad_register,{y,-1}}}}, 135 {{t,sum_2,2}, 136 {{bif,'+',{f,0},[{x,0},{y,1024}],{x,0}},7, 137 limit}}, 138 {{t,sum_3,2}, 139 {{move,{x,1},{y,1024}},5,limit}}, 140 {{t,sum_4,2}, 141 {{move,{x,1},{y,-1}},5, 142 {bad_register,{y,-1}}}}] = Errors, 143 ok. 144 145stack(Config) when is_list(Config) -> 146 Errors = do_val(stack, Config), 147 [{{t,a,2},{return,9,{stack_frame,2}}}, 148 {{t,b,2},{{deallocate,2},4,{allocated,none}}}, 149 {{t,bad_1,0},{{allocate_zero,2,10},4,{{x,9},not_live}}}, 150 {{t,bad_2,0},{{move,{y,0},{x,0}},5,{unassigned,{y,0}}}}, 151 {{t,c,2},{{deallocate,2},10,{allocated,none}}}, 152 {{t,d,2}, 153 {{allocate,2,2},5,{existing_stack_frame,{size,2}}}}, 154 {{t,e,2},{{deallocate,5},6,{allocated,2}}}] = Errors, 155 ok. 156 157call_last(Config) when is_list(Config) -> 158 Errors = do_val(call_last, Config), 159 [{{t,a,1}, 160 {{call_last,1,{f,8},2},9,{allocated,1}}}, 161 {{t,b,1}, 162 {{call_ext_last,2,{extfunc,lists,seq,2},2},10,{allocated,1}}}, 163 {{t,baz,2}, 164 {{call_ext_only,2,{extfunc,erlang,put,2}},5,{allocated,0}}}, 165 {{t,biz,2}, 166 {{call_only,2,{f,10}},5,{allocated,0}}}] = Errors, 167 ok. 168 169call_without_stack(Config) when is_list(Config) -> 170 Errors = do_val(call_without_stack, Config), 171 [{{t,local,2}, 172 {{call,2,{f,2}},4,{allocated,none}}}, 173 {{t,remote,2}, 174 {{call_ext,2,{extfunc,lists,seq,2}},4,{allocated,none}}}] = Errors, 175 ok. 176 177merge_undefined(Config) when is_list(Config) -> 178 Errors = do_val(merge_undefined, Config), 179 [{{t,undecided,2}, 180 {{call_ext,2,{extfunc,debug,filter,2}}, 181 22, 182 {allocated,undecided}}}, 183 {{t,uninitialized,2}, 184 {{call_ext,2,{extfunc,io,format,2}}, 185 17, 186 {uninitialized_reg,{y,1}}}}] = Errors, 187 ok. 188 189uninit(Config) when is_list(Config) -> 190 Errors = do_val(uninit, Config), 191 [{{t,sum_1,2}, 192 {{move,{y,0},{x,0}},5,{uninitialized_reg,{y,0}}}}, 193 {{t,sum_2,2}, 194 {{call,1,{f,8}},5,{uninitialized_reg,{y,0}}}}, 195 {{t,sum_3,2}, 196 {{bif,'+',{f,0},[{x,0},{y,0}],{x,0}}, 197 6, 198 {unassigned,{y,0}}}}] = Errors, 199 ok. 200 201unsafe_catch(Config) when is_list(Config) -> 202 Errors = do_val(unsafe_catch, Config), 203 [{{t,small,2}, 204 {{bs_put_integer,{f,0},{integer,16},1, 205 {field_flags,[unsigned,big]},{y,0}}, 206 20, 207 {unassigned,{y,0}}}}] = Errors, 208 ok. 209 210dead_code(Config) when is_list(Config) -> 211 [] = do_val(dead_code, Config), 212 ok. 213 214overwrite_catchtag(Config) when is_list(Config) -> 215 Errors = do_val(overwrite_catchtag, Config), 216 [{{overwrite_catchtag,foo,1}, 217 {{move,{x,0},{y,0}},6,{catchtag,_}}}] = Errors, 218 ok. 219 220overwrite_trytag(Config) when is_list(Config) -> 221 Errors = do_val(overwrite_trytag, Config), 222 [{{overwrite_trytag,foo,1}, 223 {{kill,{y,2}},8,{trytag,_}}}] = Errors, 224 ok. 225 226accessing_tags(Config) when is_list(Config) -> 227 Errors = do_val(accessing_tags, Config), 228 [{{accessing_tags,bar,1}, 229 {{move,{y,0},{x,0}},6,{trytag,_}}}, 230 {{accessing_tags,foo,1}, 231 {{move,{y,0},{x,0}},6,{catchtag,_}}}] = Errors, 232 ok. 233 234bad_catch_try(Config) when is_list(Config) -> 235 Errors = do_val(bad_catch_try, Config), 236 [{{bad_catch_try,bad_1,1}, 237 {{'catch',{x,0},{f,3}}, 238 5,{invalid_tag_register,{x,0}}}}, 239 {{bad_catch_try,bad_2,1}, 240 {{catch_end,{x,9}}, 241 8,{invalid_tag_register,{x,9}}}}, 242 {{bad_catch_try,bad_3,1}, 243 {{catch_end,{y,1}},9,{invalid_tag,{y,1},{t_atom,[kalle]}}}}, 244 {{bad_catch_try,bad_4,1}, 245 {{'try',{x,0},{f,15}},5,{invalid_tag_register,{x,0}}}}, 246 {{bad_catch_try,bad_5,1}, 247 {{try_case,{y,1}},12,{invalid_tag,{y,1},any}}}, 248 {{bad_catch_try,bad_6,1}, 249 {{move,{integer,1},{y,1}},7, 250 {invalid_store,{y,1}}}}] = Errors, 251 ok. 252 253cons_guard(Config) when is_list(Config) -> 254 Errors = do_val(cons, Config), 255 [{{cons,foo,1}, 256 {{get_list,{x,0},{x,1},{x,2}}, 257 5, 258 {bad_type,{needed,{t_cons,any,any}},{actual,any}}}}] = Errors, 259 ok. 260 261freg_range(Config) when is_list(Config) -> 262 Errors = do_val(freg_range, Config), 263 [{{t,sum_1,2}, 264 {{bif,fadd,{f,0},[{fr,-1},{fr,1}],{fr,0}}, 265 4, 266 {bad_source,{fr,-1}}}}, 267 {{t,sum_2,2}, 268 {{bif,fadd,{f,0},[{fr,0},{fr,1024}],{fr,0}}, 269 5, 270 {uninitialized_reg,{fr,1024}}}}, 271 {{t,sum_3,2}, 272 {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,-1}}, 273 6, 274 {bad_register,{fr,-1}}}}, 275 {{t,sum_4,2}, 276 {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,1024}}, 277 6, 278 limit}}] = Errors, 279 ok. 280 281freg_uninit(Config) when is_list(Config) -> 282 Errors = do_val(freg_uninit, Config), 283 [{{t,sum_1,2}, 284 {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,0}}, 285 5, 286 {uninitialized_reg,{fr,1}}}}, 287 {{t,sum_2,2}, 288 {{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,0}}, 289 8, 290 {uninitialized_reg,{fr,0}}}}] = Errors, 291 ok. 292 293bad_bin_match(Config) when is_list(Config) -> 294 [{{t,t,1},{return,5,{match_context,{x,0}}}}] = 295 do_val(bad_bin_match, Config), 296 ok. 297 298bad_dsetel(Config) when is_list(Config) -> 299 Errors = do_val(bad_dsetel, Config), 300 [{{t,t,1}, 301 {{set_tuple_element,{x,1},{x,0},1}, 302 17, 303 illegal_context_for_set_tuple_element}}] = Errors, 304 ok. 305 306state_after_fault_in_catch(Config) when is_list(Config) -> 307 Errors = do_val(state_after_fault_in_catch, Config), 308 [{{state_after_fault_in_catch,badmatch,1}, 309 {{move,{x,1},{x,0}},9,{uninitialized_reg,{x,1}}}}, 310 {{state_after_fault_in_catch,case_end,1}, 311 {{move,{x,1},{x,0}},9,{uninitialized_reg,{x,1}}}}, 312 {{state_after_fault_in_catch,if_end,1}, 313 {{move,{x,1},{x,0}},9,{uninitialized_reg,{x,1}}}}, 314 {{t,foo,1}, 315 {{move,{x,1},{x,0}},10,{uninitialized_reg,{x,1}}}}] = Errors, 316 ok. 317 318no_exception_in_catch(Config) when is_list(Config) -> 319 Errors = do_val(no_exception_in_catch, Config), 320 [{{no_exception_in_catch,nested_of_1,4}, 321 {{try_case_end,{x,0}},180,ambiguous_catch_try_state}}] = Errors, 322 ok. 323 324undef_label(Config) when is_list(Config) -> 325 M = {undef_label, 326 [{t,1}], 327 [], 328 [{function,t,1,2, 329 [{label,1}, 330 {func_info,{atom,undef_label},{atom,t},1}, 331 {label,2}, 332 {test,is_eq_exact,{f,42},[{x,0},{atom,x}]}, 333 {move,{atom,ok},{x,0}}, 334 return]}, 335 {function,x,1,17, 336 [{label,3}, 337 {func_info,{atom,undef_label},{atom,x},1}, 338 {label,4}, 339 return]}], 340 5}, 341 Errors = beam_val(M), 342 [{{undef_label,t,1},{undef_labels,[42]}}, 343 {{undef_label,x,1},no_entry_label}] = Errors, 344 ok. 345 346illegal_instruction(Config) when is_list(Config) -> 347 M = {illegal_instruction, 348 [{t,1},{x,1},{y,0}], 349 [], 350 [{function,t,1,2, 351 [{label,1}, 352 {func_info,{atom,illegal_instruction},{atom,t},1}, 353 {label,2}, 354 {my_illegal_instruction,{x,0}}, 355 return]}, 356 {function,x,1,4, 357 [{label,3}, 358 bad_func_info, 359 {label,4}, 360 {my_illegal_instruction,{x,0}}, 361 return]}, 362 {function,y,0,17,[]}], 363 5}, 364 Errors = beam_val(M), 365 [{{illegal_instruction,t,1}, 366 {{my_illegal_instruction,{x,0}},4,unknown_instruction}}, 367 {{illegal_instruction,x,1},invalid_function_header}, 368 {{illegal_instruction,y,0},invalid_function_header}] = Errors, 369 ok. 370 371%% The beam_validator used to assume that a GC guard BIF could 372%% do a garbage collection even if it failed. That assumption 373%% is not correct, and will cause the beam_validator to reject 374%% valid programs such as this test case. 375%% 376%% (Thanks to Kiran Khaladkar.) 377%% 378failing_gc_guard_bif(Config) when is_list(Config) -> 379 ok = process_request(lists:seq(1, 36)), 380 error = process_request([]), 381 error = process_request(not_a_list), 382 ok. 383 384process_request(ConfId) -> 385 case process_request_foo(ConfId) of 386 false -> 387 if 388 length(ConfId) == 36 -> 389 Response = ok; 390 true -> 391 Response = error 392 end 393 end, 394 process_request_bar(self(), [Response]). 395 396process_request_foo(_) -> 397 false. 398 399process_request_bar(Pid, [Response]) when is_pid(Pid) -> 400 Response. 401 402map_field_lists(Config) -> 403 Errors = do_val(map_field_lists, Config), 404 [{{map_field_lists,x,1}, 405 {{test,has_map_fields,{f,1},{x,0},{list,[{atom,a},{atom,a}]}}, 406 6, 407 keys_not_unique}}, 408 {{map_field_lists,y,1}, 409 {{test,has_map_fields,{f,3},{x,0},{list,[]}}, 410 6, 411 empty_field_list}} 412 ] = Errors. 413 414%% Coverage and smoke test of beam_validator. 415cover_bin_opt(_Config) -> 416 Ms = [beam_utils_SUITE, 417 bs_match_SUITE, 418 bs_bincomp_SUITE, 419 bs_bit_binaries_SUITE, 420 bs_utf_SUITE], 421 test_lib:p_run(fun try_bin_opt/1, Ms), 422 ok. 423 424try_bin_opt(Mod) -> 425 try 426 do_bin_opt(Mod) 427 catch 428 Class:Error:Stk -> 429 io:format("~p: ~p ~p\n~p\n", 430 [Mod,Class,Error,Stk]), 431 error 432 end. 433 434do_bin_opt(Mod) -> 435 Beam = code:which(Mod), 436 {ok,{Mod,[{abstract_code, 437 {raw_abstract_v1,Abstr}}]}} = 438 beam_lib:chunks(Beam, [abstract_code]), 439 {ok,Mod,Asm} = compile:forms(Abstr, ['S']), 440 do_bin_opt(Mod, Asm). 441 442do_bin_opt(Mod, Asm) -> 443 do_bin_opt(fun enable_bin_opt/1, Mod, Asm), 444 do_bin_opt(fun remove_bs_start_match/1, Mod, Asm), 445 do_bin_opt(fun remove_bs_save/1, Mod, Asm), 446 do_bin_opt(fun destroy_ctxt/1, Mod, Asm), 447 do_bin_opt(fun destroy_save_point/1, Mod, Asm), 448 ok. 449 450do_bin_opt(Transform, Mod, Asm0) -> 451 Asm = Transform(Asm0), 452 case compile:forms(Asm, [from_asm,no_postopt,return]) of 453 {ok,Mod,Code,_Warnings} when is_binary(Code) -> 454 ok; 455 {error,Errors0,_} -> 456 %% beam_validator must return errors, not simply crash, 457 %% when illegal code is found. 458 ModString = atom_to_list(Mod), 459 [{ModString,Errors}] = Errors0, 460 _ = [verify_bin_opt_error(E) || E <- Errors], 461 ok 462 end. 463 464verify_bin_opt_error({beam_validator,_}) -> 465 ok. 466 467enable_bin_opt(Module) -> 468 transform_is(fun enable_bin_opt_body/1, Module). 469 470enable_bin_opt_body([_,{'%',{no_bin_opt,_Reason,_Anno}}|Is]) -> 471 enable_bin_opt_body(Is); 472enable_bin_opt_body([I|Is]) -> 473 [I|enable_bin_opt_body(Is)]; 474enable_bin_opt_body([]) -> 475 []. 476 477remove_bs_start_match(Module) -> 478 transform_remove(fun({test,bs_start_match2,_,_,_,_}) -> true; 479 (_) -> false 480 end, Module). 481 482remove_bs_save(Module) -> 483 transform_remove(fun({bs_save2,_,_}) -> true; 484 (_) -> false 485 end, Module). 486 487destroy_save_point(Module) -> 488 transform_i(fun do_destroy_save_point/1, Module). 489 490do_destroy_save_point({I,Ctx,_Point}) 491 when I =:= bs_save2; I =:= bs_restore2 -> 492 {I,Ctx,42}; 493do_destroy_save_point(I) -> 494 I. 495 496destroy_ctxt(Module) -> 497 transform_i(fun do_destroy_ctxt/1, Module). 498 499do_destroy_ctxt({bs_save2=I,Ctx,Point}) -> 500 {I,destroy_reg(Ctx),Point}; 501do_destroy_ctxt({bs_restore2=I,Ctx,Point}) -> 502 {I,destroy_reg(Ctx),Point}; 503do_destroy_ctxt({bs_context_to_binary=I,Ctx}) -> 504 {I,destroy_reg(Ctx)}; 505do_destroy_ctxt(I) -> 506 I. 507 508destroy_reg({Tag,N}) -> 509 case rand:uniform() of 510 R when R < 0.6 -> 511 {Tag,N+1}; 512 _ -> 513 {y,N+1} 514 end. 515 516bad_tuples(Config) -> 517 Errors = do_val(bad_tuples, Config), 518 [{{bad_tuples,heap_overflow,1}, 519 {{put,{x,0}},9,{heap_overflow,{left,0},{wanted,1}}}}, 520 {{bad_tuples,long,2}, 521 {{put,{atom,too_long}},9,not_building_a_tuple}}, 522 {{bad_tuples,self_referential,1}, 523 {{put,{x,1}},8,{unfinished_tuple,{x,1}}}}, 524 {{bad_tuples,short,1}, 525 {{move,{x,1},{x,0}},8,{unfinished_tuple,{x,1}}}}] = Errors, 526 527 ok. 528 529bad_try_catch_nesting(Config) -> 530 Errors = do_val(bad_try_catch_nesting, Config), 531 [{{bad_try_catch_nesting,main,2}, 532 {{'try',{y,2},{f,3}}, 533 8, 534 {bad_try_catch_nesting,{y,2},[{{y,1},{trytag,[5]}}]}}}] = Errors, 535 ok. 536 537receive_stacked(Config) -> 538 Mod = ?FUNCTION_NAME, 539 Errors = do_val(Mod, Config), 540 [{{receive_stacked,f1,0}, 541 {{loop_rec_end,{f,3}}, 542 18, 543 {fragile_message_reference,{y,_}}}}, 544 {{receive_stacked,f2,0}, 545 {{test_heap,3,0},11,{fragile_message_reference,{y,_}}}}, 546 {{receive_stacked,f3,0}, 547 {{test_heap,3,0},11,{fragile_message_reference,{y,_}}}}, 548 {{receive_stacked,f4,0}, 549 {{test_heap,3,0},11,{fragile_message_reference,{y,_}}}}, 550 {{receive_stacked,f5,0}, 551 {{loop_rec_end,{f,23}}, 552 24, 553 {fragile_message_reference,{y,_}}}}, 554 {{receive_stacked,f6,0}, 555 {{gc_bif,byte_size,{f,29},0,[{y,_}],{x,0}}, 556 13, 557 {fragile_message_reference,{y,_}}}}, 558 {{receive_stacked,f7,0}, 559 {{loop_rec_end,{f,33}}, 560 21, 561 {fragile_message_reference,{y,_}}}}, 562 {{receive_stacked,f8,0}, 563 {{loop_rec_end,{f,38}}, 564 21, 565 {fragile_message_reference,{y,_}}}}, 566 {{receive_stacked,m1,0}, 567 {{loop_rec_end,{f,43}}, 568 20, 569 {fragile_message_reference,{y,_}}}}, 570 {{receive_stacked,m2,0}, 571 {{loop_rec_end,{f,48}}, 572 34, 573 {fragile_message_reference,{y,_}}}}] = Errors, 574 575 %% Compile the original source code as a smoke test. 576 Data = proplists:get_value(data_dir, Config), 577 Base = atom_to_list(Mod), 578 File = filename:join(Data, Base), 579 {ok,Mod,_} = compile:file(File, [binary]), 580 581 ok. 582 583aliased_types(Config) -> 584 Seq = lists:seq(1, 5), 585 1 = aliased_types_1(Seq, Config), 586 587 {1,1} = aliased_types_2(Seq), 588 {42,none} = aliased_types_2([]), 589 590 gurka = aliased_types_3([gurka]), 591 gaffel = aliased_types_3([gaffel]), 592 593 ok. 594 595%% ERL-735: validator failed to track types on aliased registers, rejecting 596%% legitimate optimizations. 597%% 598%% move x0 y0 599%% bif hd L1 x0 600%% get_hd y0 %% The validator failed to see that y0 was a list 601%% 602aliased_types_1(Bug, Config) -> 603 if 604 Config =/= [gurka, gaffel] -> %% Pointless branch. 605 _ = hd(Bug), 606 lists:seq(1, 5), 607 hd(Bug) 608 end. 609 610%% ERL-832: validator failed to realize that a Y register was a cons. 611aliased_types_2(Bug) -> 612 Res = case Bug of 613 [] -> id(42); 614 _ -> hd(Bug) 615 end, 616 {Res,case Bug of 617 [] -> none; 618 _ -> hd(Bug) 619 end}. 620 621%% ERL-832 part deux; validator failed to realize that an aliased register was 622%% a cons. 623aliased_types_3(Bug) -> 624 List = [Y || Y <- Bug], 625 case List of 626 [] -> Bug; 627 _ -> 628 if 629 hd(List) -> a:a(); 630 true -> ok 631 end, 632 hd(List) 633 end. 634 635 636%% ERL-867; validation proceeded after a type conflict, causing incorrect types 637%% to be joined. 638 639-record(r, { e1 = e1, e2 = e2 }). 640 641type_conflict(Config) when is_list(Config) -> 642 {e1, e2} = type_conflict_1(#r{}), 643 ok. 644 645type_conflict_1(C) -> 646 Src = id(C#r.e2), 647 TRes = try id(Src) of 648 R -> R 649 catch 650 %% C:R can never match, yet it assumed that the type of 'C' was 651 %% an atom from here on. 652 C:R -> R 653 end, 654 {C#r.e1, TRes}. 655 656%% ERL-886; validation failed to infer types on both sides of '=:=' 657 658infer_on_eq(Config) when is_list(Config) -> 659 {ok, gurka} = infer_on_eq_1(id({gurka})), 660 {ok, gaffel} = infer_on_eq_2(id({gaffel})), 661 {ok, elefant} = infer_on_eq_3(id({elefant})), 662 {ok, myra} = infer_on_eq_4(id({myra})), 663 ok. 664 665infer_on_eq_1(T) -> 666 1 = erlang:tuple_size(T), 667 {ok, erlang:element(1, T)}. 668 669infer_on_eq_2(T) -> 670 Size = erlang:tuple_size(T), 671 Size = 1, 672 {ok, erlang:element(1, T)}. 673 674infer_on_eq_3(T) -> 675 true = 1 =:= erlang:tuple_size(T), 676 {ok, erlang:element(1, T)}. 677 678infer_on_eq_4(T) -> 679 true = erlang:tuple_size(T) =:= 1, 680 {ok, erlang:element(1, T)}. 681 682%% ERIERL-348; types were inferred for dead values, causing validation to fail. 683 684-record(idv, {key}). 685 686infer_dead_value(Config) when is_list(Config) -> 687 a = idv_1({a, b, c, d, e, f, g}, {0, 0, 0, 0, 0, 0, 0}), 688 b = idv_1({a, b, c, d, 0, 0, 0}, {a, b, c, d, 0, 0, 0}), 689 c = idv_1({0, 0, 0, 0, 0, f, g}, {0, 0, 0, 0, 0, f, g}), 690 error = idv_1(gurka, gaffel), 691 692 ok = idv_2(id(#idv{})), 693 694 ok. 695 696idv_1({_A, _B, _C, _D, _E, _F, _G}, 697 {0, 0, 0, 0, 0, 0, 0}) -> 698 a; 699idv_1({A, B, C, D,_E, _F, _G}=_Tuple1, 700 {A, B, C, D, 0, 0, 0}=_Tuple2) -> 701 b; 702idv_1({_A, _B, _C, _D, _E, F, G}, 703 {0, 0, 0, 0, 0, F, G}) -> 704 c; 705idv_1(_A, _B) -> 706 error. 707 708%% ERL-998; type inference for select_val (#b_switch{}) was more clever than 709%% that for is_ne_exact (#b_br{}), sometimes failing validation when the type 710%% optimization pass acted on the former and the validator got the latter. 711 712-record(ion, {state}). 713 714infer_on_ne(Config) when is_list(Config) -> 715 #ion{state = closing} = ion_1(#ion{ state = id(open) }), 716 #ion{state = closing} = ion_close(#ion{ state = open }), 717 ok. 718 719ion_1(State = #ion{state = open}) -> ion_2(State); 720ion_1(State = #ion{state = closing}) -> ion_2(State). 721 722ion_2(State = #ion{state = open}) -> ion_close(State); 723ion_2(#ion{state = closing}) -> ok. 724 725ion_close(State = #ion{}) -> State#ion{state = closing}. 726 727%% ERL-995: The first solution to ERIERL-348 was incomplete and caused 728%% validation to fail when living values depended on delayed type inference on 729%% "dead" values. 730 731idv_2(State) -> 732 Flag = (State#idv.key == undefined), 733 case id(gurka) of 734 {_} -> id([Flag]); 735 _ -> ok 736 end, 737 if 738 Flag -> idv_called_once(State); 739 true -> ok 740 end. 741 742idv_called_once(_State) -> ok. 743 744%% Direct jumps to try/catch handlers crash the emulator and must fail 745%% validation. This is provoked by OTP-15945. 746 747branch_to_try_handler(Config) -> 748 Errors = do_val(branch_to_try_handler, Config), 749 [{{branch_to_try_handler,main,1}, 750 {{bif,tuple_size,{f,3},[{y,0}],{x,0}}, 751 13, 752 {illegal_branch,try_handler,3}}}] = Errors, 753 ok. 754 755receive_marker(Config) when is_list(Config) -> 756 Errors = do_val(receive_marker, Config), 757 758 [{{receive_marker,t1,1}, 759 {return,_, 760 {return_in_receive,entered_loop}}}, 761 {{receive_marker,t2,1}, 762 {{call_last,1,{f,2},1},_, 763 {return_in_receive,entered_loop}}}, 764 {{receive_marker,t3,1}, 765 {return,_, 766 {return_in_receive,entered_loop}}}] = Errors, 767 768 ok. 769 770%% ERL-1128: the validator erroneously thought that many non-throwing 771%% instructions like is_eq_exact could throw. 772safe_instructions(Config) when is_list(Config) -> 773 Errors = do_val(safe_instructions, Config), 774 775 [] = Errors, 776 777 ok. 778 779missing_return_type(Config) when is_list(Config) -> 780 %% ERL-1161: the validator didn't know that is_map_key always returns a 781 %% bool. 782 Map = #{ hello => there }, 783 true = mrt_1(true), 784 false = mrt_1(false), 785 true = mrt_1(is_map_key(id(hello), Map)), 786 false = mrt_1(is_map_key(id(there), Map)), 787 788 ok. 789 790mrt_1(Bool) -> 791 true = is_boolean(Bool), 792 Bool. 793 794%% ERL-1340: the unit of previously saved match positions wasn't updated. 795bs_saved_position_units(Config) when is_list(Config) -> 796 M = {bs_saved_position_units, 797 [{no_errors,1},{some_errors,1}], 798 [], 799 [{function,ctx_test_8,1,2, 800 [{label,1}, 801 {func_info,{atom,bs_saved_position_units},{atom,ctx_test_8},1}, 802 {label,2}, 803 {'%', 804 {var_info, 805 {x,0}, 806 [{type,{t_bs_context,8,0,0}},accepts_match_context]}}, 807 {move,nil,{x,0}}, 808 return]}, 809 {function,no_errors,1,4, 810 [{label,3}, 811 {func_info,{atom,bs_saved_position_units},{atom,no_errors},1}, 812 {label,4}, 813 {'%',{var_info,{x,0},[accepts_match_context]}}, 814 {test,bs_start_match3,{f,3},1,[{x,0}],{x,1}}, 815 {bs_get_position,{x,1},{x,0},2}, 816 {test,bs_test_unit,{f,5},[{x,1},8]}, 817 {bs_set_position,{x,1},{x,0}}, 818 {test,bs_get_binary2, 819 {f,5}, 820 2, 821 [{x,1},{atom,all},1,{field_flags,[unsigned,big]}], 822 {x,2}}, 823 {bs_set_position,{x,1},{x,0}}, 824 {bs_get_tail,{x,1},{x,0},3}, 825 {test,is_eq_exact,{f,5},[{x,2},{x,0}]}, 826 {move,{x,1},{x,0}}, 827 %% Context unit should be 8 here. 828 {call_only,1,{f,2}}, 829 {label,5}, 830 {bs_get_tail,{x,1},{x,0},2}, 831 {jump,{f,3}}]}, 832 {function,some_errors,1,7, 833 [{label,6}, 834 {func_info,{atom,bs_saved_position_units},{atom,some_errors},1}, 835 {label,7}, 836 {'%',{var_info,{x,0},[accepts_match_context]}}, 837 {test,bs_start_match3,{f,6},1,[{x,0}],{x,1}}, 838 {bs_get_position,{x,1},{x,0},2}, 839 {test,bs_get_binary2, 840 {f,8}, 841 2, 842 [{x,1},{atom,all},4,{field_flags,[unsigned,big]}], 843 {x,2}}, 844 {bs_set_position,{x,1},{x,0}}, 845 {test,bs_test_unit,{f,9},[{x,1},3]}, 846 {bs_set_position,{x,1},{x,0}}, 847 {bs_get_tail,{x,1},{x,0},3}, 848 {test,is_eq_exact,{f,8},[{x,2},{x,0}]}, 849 {move,{x,1},{x,0}}, 850 %% Context unit should be 12 here, failing validation. 851 {call_only,1,{f,2}}, 852 {label,8}, 853 {bs_get_tail,{x,1},{x,0},2}, 854 {jump,{f,6}}, 855 {label,9}, 856 %% Context unit should be 4 here. 857 {move,nil,{x,0}}, 858 return]}], 859 10}, 860 861 Errors = beam_val(M), 862 863 [{{bs_saved_position_units,some_errors,1}, 864 {{call_only,1,{f,2}}, 865 14, 866 {bad_arg_type,{x,0}, 867 {t_bs_context,12,0,0}, 868 {t_bs_context,8,0,0}}}}] = Errors, 869 870 ok. 871 872%%%------------------------------------------------------------------------- 873 874transform_remove(Remove, Module) -> 875 transform_is(fun(Is) -> [I || I <- Is, not Remove(I)] end, Module). 876 877transform_i(Transform, Module) -> 878 transform_is(fun(Is) -> [Transform(I) || I <- Is] end, Module). 879 880transform_is(Transform, {Mod,Exp,Imp,Fs0,Lc}) -> 881 Fs = [transform_is_1(Transform, F) || F <- Fs0], 882 {Mod,Exp,Imp,Fs,Lc}. 883 884transform_is_1(Transform, {function,N,A,E,Is0}) -> 885 Is = Transform(Is0), 886 {function,N,A,E,Is}. 887 888do_val(Mod, Config) -> 889 Data = proplists:get_value(data_dir, Config), 890 Base = atom_to_list(Mod), 891 File = filename:join(Data, Base), 892 case compile:file(File, [from_asm,no_postopt,return_errors]) of 893 {error,L,[]} -> 894 [{Base,Errors0}] = L, 895 Errors = [E || {_Pos,beam_validator,E} <- Errors0], 896 _ = [io:put_chars(beam_validator:format_error(E)) || 897 E <- Errors], 898 Errors; 899 {ok,Mod} -> 900 [] 901 end. 902 903beam_val(M) -> 904 Name = atom_to_list(element(1, M)), 905 {error,[{Name,Errors0}]} = beam_validator:validate(M, strong), 906 Errors = [E || {_Pos,beam_validator,E} <- Errors0], 907 _ = [io:put_chars(beam_validator:format_error(E)) || 908 E <- Errors], 909 Errors. 910 911%%%------------------------------------------------------------------------- 912 913val_dsetel(_Config) -> 914 self() ! 13, 915 {'EXIT',{{try_clause,participating},_}} = (catch night(0)), 916 ok. 917 918night(Turned) -> 919 receive 920 13 -> 921 try participating of engine -> 16 after false end 922 end, 923 %% The setelement/3 call is unreachable. 924 Turned(setelement(#{true => Turned}, 925 participating(Turned, "suit", 40, []), 926 Turned < Turned)), 927 ok. 928 929participating(_, _, _, _) -> ok. 930 931%% map_get was known as returning 'none', but 'will_succeed' still returned 932%% 'maybe' causing validation to continue, eventually exploding when the 'none' 933%% value was used. 934will_bif_succeed(_Config) -> 935 ok = f1(body). 936 937%% +no_ssa_opt 938f1(body) when map_get(girl, #{friend => node()}); [], community -> 939 case $q and $K of 940 _V0 -> 941 0.1825965401179273; 942 0 -> 943 state#{[] => 0.10577334580729858, $J => 0} 944 end; 945f1(body) -> 946 ok. 947 948%% ERL-1426: When a value was extracted from a tuple, subsequent type tests did 949%% not update the type of said tuple. 950 951-record(pc, {a}). 952 953parent_container(_Config) -> 954 ok = pc_1(id(#pc{a=true})). 955 956pc_1(#pc{a=A}=R) -> 957 case A of 958 true -> ok; 959 false -> ok 960 end, 961 ok = pc_2(R). 962 963pc_2(_R) -> 964 ok. 965 966id(I) -> 967 I. 968