From 7f4f4ef02349b4bf973cbc3bacc4d53a6a6abad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 13 May 2016 15:59:31 +0200 Subject: Eliminate crash in beam_bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit beam_bool would crash when attempting to optimize BEAM code similar to this code: bif '=:=' Reg1 SomeValue => y(0) bif '=:=' Reg2 {atom,true} => x(2) bif '=:=' Reg3 {atom,true} => x(3) bif 'or' x(2) x(3) => x(2) is_eq_exact Fail x(2) {atom,true} The problem is that the first instruction that assigns a value to a Y register. beam_bool:ssa_assign/2 will not accept a Y register argument. We could change ssa_assign/2 to accept a Y register, but that would only cause the entire optimization to be rejected later because the Y register is alive in the code that follows. Therefore, a better solution is to modify extend_block/3 so that the instruction that assign to Y registers are not added to the block. That is, the optimizer will only operate on the following code: bif '=:=' Reg2 {atom,true} => x(2) bif '=:=' Reg3 {atom,true} => x(3) bif 'or' x(2) x(3) => x(2) is_eq_exact Fail x(2) {atom,true} Usually the optimization will succeed, rewriting the four instructions to a select_val instruction. Assembly code such as the above can be produced by code similar to: Y = Something == SomethingElse, case Y of Condition; OtherCondition -> . . . end, . . ., Y. Reported-by: http://bugs.erlang.org/browse/ERL-143 Reported-by: José Valim --- lib/compiler/src/beam_bool.erl | 4 ++-- lib/compiler/test/beam_bool_SUITE.erl | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl index f9a08f8718..359fdb6d3c 100644 --- a/lib/compiler/src/beam_bool.erl +++ b/lib/compiler/src/beam_bool.erl @@ -238,9 +238,9 @@ extend_block(BlAcc0, Fail, [{block,Is0}|OldAcc]) -> end; extend_block(BlAcc, _, OldAcc) -> {BlAcc,OldAcc}. -extend_block_1([{set,[_],_,{bif,_,{f,Fail}}}=I|Is], Fail, Acc) -> +extend_block_1([{set,[{x,_}],_,{bif,_,{f,Fail}}}=I|Is], Fail, Acc) -> extend_block_1(Is, Fail, [I|Acc]); -extend_block_1([{set,[_],As,{bif,Bif,_}}=I|Is]=Is0, Fail, Acc) -> +extend_block_1([{set,[{x,_}],As,{bif,Bif,_}}=I|Is]=Is0, Fail, Acc) -> case safe_bool_op(Bif, length(As)) of false -> {Acc,reverse(Is0)}; true -> extend_block_1(Is, Fail, [I|Acc]) diff --git a/lib/compiler/test/beam_bool_SUITE.erl b/lib/compiler/test/beam_bool_SUITE.erl index 413d03b0ff..84d634e5ca 100644 --- a/lib/compiler/test/beam_bool_SUITE.erl +++ b/lib/compiler/test/beam_bool_SUITE.erl @@ -22,7 +22,7 @@ -export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1, init_per_group/2,end_per_group/2, before_and_inside_if/1, - scotland/1]). + scotland/1,y_registers/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -34,7 +34,8 @@ all() -> groups() -> [{p,[parallel], [before_and_inside_if, - scotland + scotland, + y_registers ]}]. init_per_suite(Config) -> @@ -127,3 +128,33 @@ do_scotland(Echo) -> Echo = placed). found(_, _) -> million. + + +%% ERL-143: beam_bool could not handle Y registers as a destination. +y_registers(_Config) -> + {'EXIT',{badarith,[_|_]}} = (catch baker(valentine)), + {'EXIT',{badarith,[_|_]}} = (catch baker(clementine)), + + {not_ok,true} = potter([]), + {ok,false} = potter([{encoding,any}]), + + ok. + +%% Thanks to Quickcheck. +baker(Baker) -> + (valentine == Baker) + + case Baker of + Baker when Baker; Baker -> + Baker; + Baker -> + [] + end. + +%% Thanks to Jose Valim. +potter(Modes) -> + Raw = lists:keyfind(encoding, 1, Modes) == false, + Final = case Raw of + X when X == false; X == nil -> ok; + _ -> not_ok + end, + {Final,Raw}. -- cgit v1.2.3