Skip to content

Commit 5076069

Browse files
committed
sys_core_fold: Eliminate crash in beam_kernel_to_ssa, again
1 parent 9f578b2 commit 5076069

File tree

2 files changed

+101
-52
lines changed

2 files changed

+101
-52
lines changed

lib/compiler/src/sys_core_fold.erl

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,32 +2216,24 @@ move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner0,
22162216

22172217
OuterBody = body(OuterBody0, ScopeSub),
22182218

2219-
{InnerVs,Sub} = var_list(InnerVs0, Sub0),
2220-
InnerBody = body(InnerBody0, Sub),
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};
2219+
case will_fail(OuterBody) of
2220+
true ->
2221+
%%
2222+
%% Avoid creating potentially unsafe code that
2223+
%% depends on another iteration of the outer
2224+
%% fixpoint loop to clean up. If <OuterBody>
2225+
%% consists of nested lets, we may run out of
2226+
%% iterations before the unsafe code is
2227+
%% eliminated.
2228+
%%
2229+
Inner0;
2230+
false ->
2231+
{InnerVs,Sub} = var_list(InnerVs0, Sub0),
2232+
InnerBody = body(InnerBody0, Sub),
2233+
2234+
Inner = Inner0#c_let{vars=InnerVs,arg=OuterBody,body=InnerBody},
2235+
Outer#c_let{vars=OuterVs,arg=Arg,body=Inner}
2236+
end;
22452237
move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
22462238
#c_case{arg=Cexpr0,clauses=[Ca0|Cs0]}=Case, Sub0) ->
22472239
case not is_failing_clause(Ca0) andalso

lib/compiler/test/core_fold_SUITE.erl

Lines changed: 83 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -701,41 +701,98 @@ do_receive_effect() ->
701701
{} = receive _ -> {} = {} end.
702702

703703
nested_lets(_Config) ->
704-
{'EXIT',{{case_clause,ok},_}} = catch nested_lets_gh_6572(<<42>>),
704+
{'EXIT',{{case_clause,ok},_}} = catch nested_lets_1(<<42>>),
705+
{'EXIT',{badarith,_}} = catch nested_lets_2(id(0), id(0)),
705706
ok.
706707

707-
nested_lets_gh_6572(<<X>>) ->
708+
%% GH-6572: Deeply nested `let` expressions caused `sys_core_fold` to generate
709+
%% unsafe code that it would attempt to fix up later. Unfortunately it did so
710+
%% through a limited fixpoint iteration, and would leak said code once the
711+
%% limit was hit.
712+
nested_lets_1(<<X>>) ->
708713
Y =
709714
case ok of
710715
X ->
711-
true = (ok > ((Y = _) = -1)),
716+
true = (ok > (Y = -1)),
712717
<<>> =
713718
{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-
)}
719+
<<
720+
(ok - ok),
721+
(bnot ok),
722+
(nested_lets_1_f() band ok),
723+
(nested_lets_1_f()),
724+
(not ok),
725+
(ok or nested_lets_1_f()),
726+
(id(
727+
id(
728+
<<
729+
(id(
730+
<<
731+
(id(
732+
<<0 || _ <- []>>
733+
))
734+
>>
735+
) * ok)
736+
>>
737+
)
738+
))
739+
>>
740+
)}
736741
end.
737742

738-
nested_lets_gh_6572_f() ->
743+
nested_lets_1_f() ->
744+
ok.
745+
746+
%% GH-6612: A variant of GH-6572 that slipped through the initial fix.
747+
nested_lets_2(X, 0) ->
748+
try
749+
0 = {
750+
_ = 0 + 0,
751+
Z = bnot ok,
752+
{(_ = ok), (_ = X)}#{ok => ok},
753+
ok +
754+
(nested_lets_2_f(
755+
ok +
756+
nested_lets_2_f(
757+
ok +
758+
(nested_lets_2_f(
759+
(Y =
760+
-nested_lets_2_f(
761+
#{
762+
(ok +
763+
(ok +
764+
nested_lets_2_f(
765+
case
766+
try ok of
767+
_ ->
768+
fun(_) ->
769+
ok
770+
end
771+
after
772+
ok
773+
end
774+
of
775+
#{} ->
776+
ok
777+
end
778+
))) => ok
779+
} > ok
780+
))
781+
) + ok)
782+
) >
783+
ok
784+
))
785+
}
786+
of
787+
_ ->
788+
Z;
789+
_ ->
790+
Y
791+
after
792+
ok
793+
end.
794+
795+
nested_lets_2_f(_) ->
739796
ok.
740797

741798
%%% Common utility functions.

0 commit comments

Comments
 (0)