File 0803-Fix-crash-when-compiling-is_list-1-call.patch of Package erlang
From f9a3fa9366209ba05d902f387fb47ace7273b9a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Mon, 31 Jul 2023 06:06:56 +0200
Subject: [PATCH] Fix crash when compiling is_list/1 call
Fixes #7504
---
lib/compiler/src/beam_ssa_codegen.erl | 17 +++++++++++++++--
lib/compiler/test/beam_type_SUITE.erl | 15 +++++++++++++++
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl
index 9f6169829b..6f6de99962 100644
--- a/lib/compiler/src/beam_ssa_codegen.erl
+++ b/lib/compiler/src/beam_ssa_codegen.erl
@@ -1270,9 +1270,22 @@ cg_block([#cg_set{op=is_tagged_tuple,anno=Anno,dst=Bool,args=Args0}], {Bool,Fail
[Src,{integer,Arity},Tag] = beam_args(Args0, 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
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 94f1b8b0a6..f65dce28c3 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -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) ->
@@ -1105,5 +1110,14 @@ 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.
+
id(I) ->
I.
--
2.35.3