Skip to content

Commit ff05bee

Browse files
committed
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 erlang#6572
1 parent 148aac9 commit ff05bee

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

lib/compiler/src/sys_core_fold.erl

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,7 +2197,7 @@ simplify_fun_call(V, Values, #c_fun{vars=Vars,body=FunBody}, CallArgs) ->
21972197
simplify_let(#c_let{arg=Arg}=Let, Sub) ->
21982198
move_let_into_expr(Let, Arg, Sub).
21992199

2200-
move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner,
2200+
move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner0,
22012201
#c_let{vars=OuterVs0,arg=Arg0,body=OuterBody0}=Outer, Sub0) ->
22022202
%%
22032203
%% let <InnerVars> = let <OuterVars> = <Arg>
@@ -2218,8 +2218,30 @@ move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner,
22182218

22192219
{InnerVs,Sub} = var_list(InnerVs0, Sub0),
22202220
InnerBody = body(InnerBody0, Sub),
2221-
Outer#c_let{vars=OuterVs,arg=Arg,
2222-
body=Inner#c_let{vars=InnerVs,arg=OuterBody,body=InnerBody}};
2221+
Inner = case will_fail(OuterBody) of
2222+
true ->
2223+
%%
2224+
%% Avoid creating potentially unsafe code that
2225+
%% depends on another iteration of the outer
2226+
%% fixpoint loop to clean up. If <OuterBody>
2227+
%% consists of nested lets, we may run out of
2228+
%% iterations before the unsafe code is
2229+
%% eliminated.
2230+
%%
2231+
%% let <InnerVars> = let <OuterVars> = <Arg>
2232+
%% in <OuterBody>
2233+
%% in <InnerBody>
2234+
%%
2235+
%% ==>
2236+
%%
2237+
%% let <OuterVars> = <Arg>
2238+
%% in <OuterBody>
2239+
%%
2240+
OuterBody;
2241+
false ->
2242+
Inner0#c_let{vars=InnerVs,arg=OuterBody,body=InnerBody}
2243+
end,
2244+
Outer#c_let{vars=OuterVs,arg=Arg,body=Inner};
22232245
move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
22242246
#c_case{arg=Cexpr0,clauses=[Ca0|Cs0]}=Case, Sub0) ->
22252247
case not is_failing_clause(Ca0) andalso

lib/compiler/test/core_fold_SUITE.erl

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
no_no_file/1,configuration/1,supplies/1,
3030
redundant_stack_frame/1,export_from_case/1,
3131
empty_values/1,cover_letrec_effect/1,
32-
receive_effect/1]).
32+
receive_effect/1,nested_lets/1]).
3333

3434
-export([foo/0,foo/1,foo/2,foo/3]).
3535

@@ -50,7 +50,7 @@ groups() ->
5050
no_no_file,configuration,supplies,
5151
redundant_stack_frame,export_from_case,
5252
empty_values,cover_letrec_effect,
53-
receive_effect]}].
53+
receive_effect,nested_lets]}].
5454

5555

5656
init_per_suite(Config) ->
@@ -700,4 +700,43 @@ receive_effect(_Config) ->
700700
do_receive_effect() ->
701701
{} = receive _ -> {} = {} end.
702702

703+
nested_lets(_Config) ->
704+
{'EXIT',{{case_clause,ok},_}} = catch nested_lets_gh_6572(<<42>>),
705+
ok.
706+
707+
nested_lets_gh_6572(<<X>>) ->
708+
Y =
709+
case ok of
710+
X ->
711+
true = (ok > ((Y = _) = -1)),
712+
<<>> =
713+
{id(
714+
<<
715+
(ok - ok),
716+
(bnot ok),
717+
(nested_lets_gh_6572_f() band ok),
718+
(nested_lets_gh_6572_f()),
719+
(not ok),
720+
(ok or nested_lets_gh_6572_f()),
721+
(id(
722+
id(
723+
<<
724+
(id(
725+
<<
726+
(id(
727+
<<0 || _ <- []>>
728+
))
729+
>>
730+
) * ok)
731+
>>
732+
)
733+
))
734+
>>
735+
)}
736+
end.
737+
738+
nested_lets_gh_6572_f() ->
739+
ok.
740+
741+
%%% Common utility functions.
703742
id(I) -> I.

0 commit comments

Comments
 (0)