File 0561-Eliminate-infinite-loop-in-the-Erlang-compiler.patch of Package erlang
From 7ed952628caa2470c9cce8678aea3b7d2e0f26dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Wed, 16 Nov 2022 13:09:50 +0100
Subject: [PATCH] Eliminate infinite loop in the Erlang compiler
Closes #6474
---
lib/compiler/src/beam_ssa_bc_size.erl | 33 ++++++++++++++++---
.../compilation_SUITE_data/infinite_loop.erl | 10 ++++++
2 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/lib/compiler/src/beam_ssa_bc_size.erl b/lib/compiler/src/beam_ssa_bc_size.erl
index a93fe8f2f3..6505bf88b7 100644
--- a/lib/compiler/src/beam_ssa_bc_size.erl
+++ b/lib/compiler/src/beam_ssa_bc_size.erl
@@ -71,7 +71,8 @@ opt_function(Id, StMap) ->
opt_blks([{L,#b_blk{is=Is}=Blk}|Blks], ParamInfo, StMap, AnyChange, Count0, Acc0) ->
case Is of
[#b_set{op=bs_init_writable,dst=Dst}] ->
- Bs = #{st_map => StMap, Dst => {writable,#b_literal{val=0}}},
+ Bs = #{st_map => StMap, Dst => {writable,#b_literal{val=0}},
+ seen => sets:new([{version,2}])},
try opt_writable(Bs, L, Blk, Blks, ParamInfo, Count0, Acc0) of
{Acc,Count} ->
opt_blks(Blks, ParamInfo, StMap, changed, Count, Acc)
@@ -153,10 +154,32 @@ call_size_func(#b_set{anno=Anno,op=call,args=[Name|Args],dst=Dst}, Bs) ->
%% and there is no need to analyze it.
Bs#{Dst => any};
true ->
- NewBs = NewBs0#{Name => self, st_map => StMap},
- Map0 = #{0 => NewBs},
- Result = calc_size(Linear, Map0),
- Bs#{Dst => Result}
+ Seen0 = map_get(seen, Bs),
+ case sets:is_element(Name, Seen0) of
+ true ->
+ %% This can happen if there is a call such as:
+ %%
+ %% foo(<< 0 || false >>)
+ %%
+ %% Essentially, this is reduced to:
+ %%
+ %% foo(<<>>)
+ %%
+ %% This sub pass will then try to analyze
+ %% the code in foo/1 and everything it
+ %% calls. To prevent an infinite loop in
+ %% case there is mutual recursion between
+ %% some of the functions called by foo/1,
+ %% give up if function that has already
+ %% been analyzed is called again.
+ throw(not_possible);
+ false ->
+ Seen = sets:add_element(Name, Seen0),
+ NewBs = NewBs0#{Name => self, st_map => StMap, seen => Seen},
+ Map0 = #{0 => NewBs},
+ Result = calc_size(Linear, Map0),
+ Bs#{Dst => Result}
+ end
end;
#{} ->
case Name of
diff --git a/lib/compiler/test/compilation_SUITE_data/infinite_loop.erl b/lib/compiler/test/compilation_SUITE_data/infinite_loop.erl
index 6d9135bb01..8fb9125c77 100644
--- a/lib/compiler/test/compilation_SUITE_data/infinite_loop.erl
+++ b/lib/compiler/test/compilation_SUITE_data/infinite_loop.erl
@@ -20,3 +20,13 @@ foobar() ->
barfoo() ->
barfoo().
+
+%% GH-6474. The compiler would go into an infinite loop.
+
+bc_infinite_loop() ->
+ mutually_recursive(<<0 || false>>).
+
+mutually_recursive(X) ->
+ %% This LC will be implemented as mutually recursive functions.
+ %% Analyzing them would cause an infinite loop.
+ [0 || _ <- [], <<_>> <= X].
--
2.35.3