Skip to content

Commit

Permalink
Fix crash when compiling is_list/1 call
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorng committed Jul 31, 2023
1 parent d051172 commit f9a3fa9
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
17 changes: 15 additions & 2 deletions lib/compiler/src/beam_ssa_codegen.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1270,9 +1270,22 @@ cg_block([#cg_set{op=is_tagged_tuple,anno=Anno,dst=Bool,args=Args0}], {Bool,Fail
[Src,{integer,Arity},Tag] = typed_args(Args0, Anno, St),
{[{test,is_tagged_tuple,ensure_label(Fail, St),[Src,Arity,Tag]}],St}
end;
cg_block([#cg_set{op=is_nonempty_list,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
cg_block([#cg_set{op=is_nonempty_list,dst=Bool0,args=Args0}=Set], {Bool0,Fail0}, St) ->
Fail = ensure_label(Fail0, St),
Args = beam_args(Args0, St),
{[{test,is_nonempty_list,ensure_label(Fail, St),Args}],St};
case beam_args([Bool0|Args0], St) of
[{z,0}|Args] ->
{[{test,is_nonempty_list,Fail,Args}],St};
[Dst|Args] ->
%% This instruction was a call to is_list/1, which was
%% rewritten to an is_nonempty_list test by
%% beam_ssa_type. BEAM has no is_nonempty_list instruction
%% that will return a boolean, so we must revert it to an
%% is_list/1 call.
#cg_set{anno=#{was_bif_is_list := true}} = Set, %Assertion.
{[{bif,is_list,Fail0,Args,Dst},
{test,is_eq_exact,Fail,[Dst,{atom,true}]}],St}
end;
cg_block([#cg_set{op=has_map_field,dst=Dst0,args=Args0}], {Dst0,Fail0}, St) ->
Fail = ensure_label(Fail0, St),
case beam_args([Dst0|Args0], St) of
Expand Down
15 changes: 15 additions & 0 deletions lib/compiler/test/beam_type_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,11 @@ cs_2({bar,baz}) ->
is_list_opt(_Config) ->
true = is_list_opt_1(id(<<"application/a2l">>)),
false = is_list_opt_1(id(<<"">>)),

ok = is_list_opt_3(id([])),
true = is_list_opt_3(id([a])),
{'EXIT',{badarg,_}} = catch is_list_opt_3(id(no_list)),

ok.

is_list_opt_1(Type) ->
Expand All @@ -1105,6 +1110,16 @@ is_list_opt_1(Type) ->
is_list_opt_2(<<"application/a2l">>) -> [<<"a2l">>];
is_list_opt_2(_Type) -> nil.

is_list_opt_3([]) ->
ok;
is_list_opt_3(A) ->
%% The call to is_list/1 would be optimized to an is_nonempty_list
%% instruction, which only exists as a guard test that cannot
%% produce boolean value.
_ = (Bool = is_list(A)) orelse binary_to_integer(<<"">>),
Bool.


%% We used to determine the type of `get_tuple_element` at the time of
%% extraction, which is simple but sometimes throws away type information when
%% on tuple unions.
Expand Down

0 comments on commit f9a3fa9

Please sign in to comment.