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