File 0615-Eliminate-crash-in-beam_kernel_to_ssa.patch of Package erlang

From ff05beecae2e002914515e94ab59930026dc9a75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Mon, 19 Dec 2022 08:31:40 +0100
Subject: [PATCH] Eliminate crash in beam_kernel_to_ssa

The `sys_core_fold` does a fixpoint iteration, limited to at most 20
iterations. One of the optimizations (coalescing two `let` constructs)
would temporarily generate unsafe code, which would eventually be
corrected, **unless** the 20 iteration limit was reached.

Closes #6572
---
 lib/compiler/src/sys_core_fold.erl    | 28 +++++++++++++++--
 lib/compiler/test/core_fold_SUITE.erl | 43 +++++++++++++++++++++++++--
 2 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 9021d9eb5c..206f39e190 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -2197,7 +2197,7 @@ simplify_fun_call(V, Values, #c_fun{vars=Vars,body=FunBody}, CallArgs) ->
 simplify_let(#c_let{arg=Arg}=Let, Sub) ->
     move_let_into_expr(Let, Arg, Sub).
 
-move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner,
+move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner0,
 		   #c_let{vars=OuterVs0,arg=Arg0,body=OuterBody0}=Outer, Sub0) ->
     %%
     %% let <InnerVars> = let <OuterVars> = <Arg>
@@ -2218,8 +2218,30 @@ move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner,
 
     {InnerVs,Sub} = var_list(InnerVs0, Sub0),
     InnerBody = body(InnerBody0, Sub),
-    Outer#c_let{vars=OuterVs,arg=Arg,
-		body=Inner#c_let{vars=InnerVs,arg=OuterBody,body=InnerBody}};
+    Inner = case will_fail(OuterBody) of
+                true ->
+                    %%
+                    %% Avoid creating potentially unsafe code that
+                    %% depends on another iteration of the outer
+                    %% fixpoint loop to clean up. If <OuterBody>
+                    %% consists of nested lets, we may run out of
+                    %% iterations before the unsafe code is
+                    %% eliminated.
+                    %%
+                    %% let <InnerVars> = let <OuterVars> = <Arg>
+                    %%                   in <OuterBody>
+                    %% in <InnerBody>
+                    %%
+                    %%       ==>
+                    %%
+                    %% let <OuterVars> = <Arg>
+                    %% in <OuterBody>
+                    %%
+                    OuterBody;
+                false ->
+                    Inner0#c_let{vars=InnerVs,arg=OuterBody,body=InnerBody}
+            end,
+    Outer#c_let{vars=OuterVs,arg=Arg,body=Inner};
 move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
 		   #c_case{arg=Cexpr0,clauses=[Ca0|Cs0]}=Case, Sub0) ->
     case not is_failing_clause(Ca0) andalso
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 4da55bed2e..de2b46e7a8 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -29,7 +29,7 @@
 	 no_no_file/1,configuration/1,supplies/1,
          redundant_stack_frame/1,export_from_case/1,
          empty_values/1,cover_letrec_effect/1,
-         receive_effect/1]).
+         receive_effect/1,nested_lets/1]).
 
 -export([foo/0,foo/1,foo/2,foo/3]).
 
@@ -50,7 +50,7 @@ groups() ->
        no_no_file,configuration,supplies,
        redundant_stack_frame,export_from_case,
        empty_values,cover_letrec_effect,
-       receive_effect]}].
+       receive_effect,nested_lets]}].
 
 
 init_per_suite(Config) ->
@@ -700,4 +700,43 @@ receive_effect(_Config) ->
 do_receive_effect() ->
     {} = receive _ -> {} = {} end.
 
+nested_lets(_Config) ->
+    {'EXIT',{{case_clause,ok},_}} = catch nested_lets_gh_6572(<<42>>),
+    ok.
+
+nested_lets_gh_6572(<<X>>) ->
+    Y =
+        case ok of
+            X ->
+                true = (ok > ((Y = _) = -1)),
+                <<>> =
+                    {id(
+                        <<
+                            (ok - ok),
+                            (bnot ok),
+                            (nested_lets_gh_6572_f() band ok),
+                            (nested_lets_gh_6572_f()),
+                            (not ok),
+                            (ok or nested_lets_gh_6572_f()),
+                            (id(
+                                id(
+                                    <<
+                                        (id(
+                                            <<
+                                                (id(
+                                                    <<0 || _ <- []>>
+                                                ))
+                                            >>
+                                        ) * ok)
+                                    >>
+                                )
+                            ))
+                        >>
+                    )}
+        end.
+
+nested_lets_gh_6572_f() ->
+    ok.
+
+%%% Common utility functions.
 id(I) -> I.
-- 
2.35.3

openSUSE Build Service is sponsored by