From 2e40d8d1c51ad1c3d3750490ecac6b290233f085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 7 Aug 2018 12:52:33 +0200 Subject: Fix bug in binary matching The compiler generates incorrect code for the following example: decode_binary(_, <>) -> case {Length, Data} of {0, _} -> %% When converting the match context back to a binary, %% Data will be set to the entire original binary, %% that is, to <<0>> instead of <<>>. {{0, 0, 0}, Data}; {4, <>} -> {{Y, M, D}, Rest} end. The problem is the delayed sub binary creation optimization, which is not safe to do in this case. This commit introduces a heuristic that will disable the delayed sub binary creation optimization for this example. Unfortunately, the heuristic may turn off the optimization when it would actually be safe. In the OTP codebase, the optimization is turned off in two instances, once in string.erl and once in dets_v9.erl. https://bugs.erlang.org/browse/ERL-689 --- lib/compiler/test/bs_match_SUITE.erl | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'lib/compiler/test/bs_match_SUITE.erl') diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index e737839575..7814738449 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -40,7 +40,7 @@ map_and_binary/1,unsafe_branch_caching/1, bad_literals/1,good_literals/1,constant_propagation/1, parse_xml/1,get_payload/1,escape/1,num_slots_different/1, - beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1]). + beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1,erl_689/1]). -export([coverage_id/1,coverage_external_ignore/2]). @@ -72,7 +72,7 @@ groups() -> map_and_binary,unsafe_branch_caching, bad_literals,good_literals,constant_propagation,parse_xml, get_payload,escape,num_slots_different, - beam_bsm,guard,is_ascii,non_opt_eq]}]. + beam_bsm,guard,is_ascii,non_opt_eq,erl_689]}]. init_per_suite(Config) -> @@ -1688,6 +1688,35 @@ non_opt_eq([_|_], <<_,_/binary>>) -> non_opt_eq([], <<>>) -> true. +%% ERL-689 + +erl_689(Config) -> + {{0, 0, 0}, <<>>} = do_erl_689_1(<<0>>, ?MODULE), + {{2018, 8, 7}, <<>>} = do_erl_689_1(<<4,2018:16/little,8,7>>, ?MODULE), + {{0, 0, 0}, <<>>} = do_erl_689_2(?MODULE, <<0>>), + {{2018, 8, 7}, <<>>} = do_erl_689_2(?MODULE, <<4,2018:16/little,8,7>>), + ok. + +do_erl_689_1(<>, _) -> + case {Data, Length} of + {_, 0} -> + %% bs_context_to_binary would incorrectly set Data to the original + %% binary (before matching in the function head). + {{0, 0, 0}, Data}; + {<>, 4} -> + {{Y, M, D}, Rest} + end. + +do_erl_689_2(_, <>) -> + case {Length, Data} of + {0, _} -> + %% bs_context_to_binary would incorrectly set Data to the original + %% binary (before matching in the function head). + {{0, 0, 0}, Data}; + {4, <>} -> + {{Y, M, D}, Rest} + end. + check(F, R) -> R = F(). -- cgit v1.2.3