aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2019-05-27 15:34:35 +0200
committerBjörn Gustavsson <[email protected]>2019-05-28 09:27:05 +0200
commit528f17ad9b85c4a3a1e28428606494550eef3a1e (patch)
tree3a69fe46aef89538657bc1776c89f8b21968759d /lib/compiler/src
parentd32991afaf3fc5f9f73e3e2448672bb9a1b80101 (diff)
downloadotp-528f17ad9b85c4a3a1e28428606494550eef3a1e.tar.gz
otp-528f17ad9b85c4a3a1e28428606494550eef3a1e.tar.bz2
otp-528f17ad9b85c4a3a1e28428606494550eef3a1e.zip
Eliminate crash in the beam_ssa_dead compiler pass
The compiler could crash in the beam_ssa_dead pass while compiling complex nested `case` expressions. See the added test case for an example and explanation. https://bugs.erlang.org/browse/ERL-956
Diffstat (limited to 'lib/compiler/src')
-rw-r--r--lib/compiler/src/beam_ssa_dead.erl18
1 files changed, 16 insertions, 2 deletions
diff --git a/lib/compiler/src/beam_ssa_dead.erl b/lib/compiler/src/beam_ssa_dead.erl
index bb43a550ae..86f680c964 100644
--- a/lib/compiler/src/beam_ssa_dead.erl
+++ b/lib/compiler/src/beam_ssa_dead.erl
@@ -436,8 +436,22 @@ get_phi_arg([{Val,From}|_], From) -> Val;
get_phi_arg([_|As], From) -> get_phi_arg(As, From).
eval_terminator(#b_br{bool=#b_var{}=Bool}=Br, Bs, _St) ->
- Val = get_value(Bool, Bs),
- beam_ssa:normalize(Br#b_br{bool=Val});
+ case get_value(Bool, Bs) of
+ #b_literal{val=Val}=Lit ->
+ case is_boolean(Val) of
+ true ->
+ beam_ssa:normalize(Br#b_br{bool=Lit});
+ false ->
+ %% Non-boolean literal. This means that this `br`
+ %% terminator will never actually be reached with
+ %% these bindings. (There must be a previous two-way
+ %% branch that branches the other way when Bool
+ %% is bound to a non-boolean literal.)
+ none
+ end;
+ #b_var{}=Var ->
+ beam_ssa:normalize(Br#b_br{bool=Var})
+ end;
eval_terminator(#b_br{bool=#b_literal{}}=Br, _Bs, _St) ->
beam_ssa:normalize(Br);
eval_terminator(#b_switch{arg=Arg,fail=Fail,list=List}=Sw, Bs, St) ->