diff options
author | Björn Gustavsson <[email protected]> | 2019-05-21 14:48:11 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2019-05-21 15:32:25 +0200 |
commit | 7173fb8984d1822cc9c081f094841fb755f800fc (patch) | |
tree | 7c4258089de470fff4ed035ee54d5d79676ed97c | |
parent | d32991afaf3fc5f9f73e3e2448672bb9a1b80101 (diff) | |
download | otp-7173fb8984d1822cc9c081f094841fb755f800fc.tar.gz otp-7173fb8984d1822cc9c081f094841fb755f800fc.tar.bz2 otp-7173fb8984d1822cc9c081f094841fb755f800fc.zip |
Eliminate compiler crash when compiling complex receive statements
Certain complex receive statements would result in an internal
compiler failure. That would happen when the compiler would fail
to find the common exit block following a receive. See the added
test case for an example.
https://bugs.erlang.org/browse/ERL-950
-rw-r--r-- | lib/compiler/src/beam_ssa_pre_codegen.erl | 11 | ||||
-rw-r--r-- | lib/compiler/test/receive_SUITE.erl | 26 |
2 files changed, 31 insertions, 6 deletions
diff --git a/lib/compiler/src/beam_ssa_pre_codegen.erl b/lib/compiler/src/beam_ssa_pre_codegen.erl index bf99e8fc26..9af72afca7 100644 --- a/lib/compiler/src/beam_ssa_pre_codegen.erl +++ b/lib/compiler/src/beam_ssa_pre_codegen.erl @@ -1415,12 +1415,15 @@ fix_receive([], _Defs, Blocks, Count) -> find_loop_exit([L1,L2|_Ls], Blocks) -> Path1 = beam_ssa:rpo([L1], Blocks), Path2 = beam_ssa:rpo([L2], Blocks), - find_loop_exit_1(reverse(Path1), reverse(Path2), none); + find_loop_exit_1(Path1, cerl_sets:from_list(Path2)); find_loop_exit(_, _) -> none. -find_loop_exit_1([H|T1], [H|T2], _) -> - find_loop_exit_1(T1, T2, H); -find_loop_exit_1(_, _, Exit) -> Exit. +find_loop_exit_1([H|T], OtherPath) -> + case cerl_sets:is_element(H, OtherPath) of + true -> H; + false -> find_loop_exit_1(T, OtherPath) + end; +find_loop_exit_1([], _) -> none. %% find_rm_blocks(StartLabel, Blocks) -> [Label]. %% Find all blocks that start with remove_message within the receive diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl index 0038eb1a4b..752491f0f8 100644 --- a/lib/compiler/test/receive_SUITE.erl +++ b/lib/compiler/test/receive_SUITE.erl @@ -26,7 +26,7 @@ init_per_testcase/2,end_per_testcase/2, export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1, wait/1,recv_in_try/1,double_recv/1,receive_var_zero/1, - match_built_terms/1]). + match_built_terms/1,elusive_common_exit/1]). -include_lib("common_test/include/ct.hrl"). @@ -47,7 +47,7 @@ groups() -> [{p,test_lib:parallel(), [recv,coverage,otp_7980,ref_opt,export,wait, recv_in_try,double_recv,receive_var_zero, - match_built_terms]}]. + match_built_terms,elusive_common_exit]}]. init_per_suite(Config) -> @@ -427,4 +427,26 @@ match_built_terms(Config) when is_list(Config) -> ?MATCH_BUILT_TERM(Ref, <<A, B>>), ?MATCH_BUILT_TERM(Ref, #{ 1 => A, 2 => B}). +elusive_common_exit(_Config) -> + self() ! {1, a}, + self() ! {2, b}, + {[z], [{2,b},{1,a}]} = elusive_loop([x,y,z], 2, []), + ok. + +elusive_loop(List, 0, Results) -> + {List, Results}; +elusive_loop(List, ToReceive, Results) -> + {Result, RemList} = + receive + {_Pos, _R} = Res when List =/= [] -> + [_H|T] = List, + {Res, T}; + {_Pos, _R} = Res when List =:= [] -> + {Res, []} + end, + %% beam_ssa_pre_codegen:fix_receives() would fail to find + %% the common exit block for this receive. That would mean + %% that it would not insert all necessary copy instructions. + elusive_loop(RemList, ToReceive-1, [Result | Results]). + id(I) -> I. |