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

openSUSE Build Service is sponsored by