LogoopenSUSE Build Service > Projects
Sign Up | Log In

View File 0352-Abort-size-calculation-when-a-matched-out-variable-i.patch of Package erlang (Project home:Ledest:erlang:20)

From 798b39ae97c9495869990fd1264ad07e61600963 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Mon, 16 Jul 2018 10:51:12 +0200
Subject: [PATCH] Abort size calculation when a matched-out variable is used

Referencing a matched-out variable in a size expression makes it
impossible to calculate the size of the result based on the size of
the matched binary. The compiler would still generate code to do
this however, which would crash since the variable isn't defined
at the size calculation.
---
 lib/compiler/src/v3_core.erl           | 36 +++++++++++++++++++++++-----------
 lib/compiler/test/bs_bincomp_SUITE.erl | 11 +++++++++--
 2 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 0196e7fdfd..3b746ab5bf 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1501,7 +1501,7 @@ bc_initial_size(E0, Q, St0) ->
     end.
 
 bc_elem_size({bin,_,El}, St0) ->
-    case bc_elem_size_1(El, 0, []) of
+    case bc_elem_size_1(El, ordsets:new(), 0, []) of
 	{Bits,[]} ->
 	    {#c_literal{val=Bits},[],[],St0};
 	{Bits,Vars0} ->
@@ -1515,19 +1515,33 @@ bc_elem_size(_, _) ->
     throw(impossible).
 
 bc_elem_size_1([{bin_element,_,{string,_,String},{integer,_,N},_}=El|Es],
-	       Bits, Vars) ->
+	       DefVars, Bits, SizeVars) ->
     U = get_unit(El),
-    bc_elem_size_1(Es, Bits+U*N*length(String), Vars);
-bc_elem_size_1([{bin_element,_,_,{integer,_,N},_}=El|Es], Bits, Vars) ->
+    bc_elem_size_1(Es, DefVars, Bits+U*N*length(String), SizeVars);
+bc_elem_size_1([{bin_element,_,Expr,{integer,_,N},_}=El|Es],
+               DefVars0, Bits, SizeVars) ->
     U = get_unit(El),
-    bc_elem_size_1(Es, Bits+U*N, Vars);
-bc_elem_size_1([{bin_element,_,_,{var,_,Var},_}=El|Es], Bits, Vars) ->
-    U = get_unit(El),
-    bc_elem_size_1(Es, Bits, [{U,#c_var{name=Var}}|Vars]);
-bc_elem_size_1([_|_], _, _) ->
+    DefVars = bc_elem_size_def_var(Expr, DefVars0),
+    bc_elem_size_1(Es, DefVars, Bits+U*N, SizeVars);
+bc_elem_size_1([{bin_element,_,Expr,{var,_,Src},_}=El|Es],
+               DefVars0, Bits, SizeVars) ->
+    case ordsets:is_element(Src, DefVars0) of
+        false ->
+            U = get_unit(El),
+            DefVars = bc_elem_size_def_var(Expr, DefVars0),
+            bc_elem_size_1(Es, DefVars, Bits, [{U,#c_var{name=Src}}|SizeVars]);
+        true ->
+            throw(impossible)
+    end;
+bc_elem_size_1([_|_], _, _, _) ->
     throw(impossible);
-bc_elem_size_1([], Bits, Vars) ->
-    {Bits,Vars}.
+bc_elem_size_1([], _DefVars, Bits, SizeVars) ->
+    {Bits,SizeVars}.
+
+bc_elem_size_def_var({var,_,Var}, DefVars) ->
+    ordsets:add_element(Var, DefVars);
+bc_elem_size_def_var(_Expr, DefVars) ->
+    DefVars.
 
 bc_elem_size_combine([{U,V}|T], U, UVars, Acc) ->
     bc_elem_size_combine(T, U, [V|UVars], Acc);
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index 42361ea546..a5d49020a9 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -26,7 +26,7 @@
 	 init_per_group/2,end_per_group/2,
 	 byte_aligned/1,bit_aligned/1,extended_byte_aligned/1,
 	 extended_bit_aligned/1,mixed/1,filters/1,trim_coverage/1,
-	 nomatch/1,sizes/1,general_expressions/1]).
+	 nomatch/1,sizes/1,general_expressions/1,matched_out_size/1]).
 
 -include_lib("common_test/include/ct.hrl").
 
@@ -36,7 +36,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
     test_lib:recompile(?MODULE),
     [byte_aligned, bit_aligned, extended_byte_aligned,
      extended_bit_aligned, mixed, filters, trim_coverage,
-     nomatch, sizes, general_expressions].
+     nomatch, sizes, general_expressions, matched_out_size].
 
 groups() -> 
     [].
@@ -338,6 +338,13 @@ general_expressions(_) ->
 
 -undef(BAD).
 
+matched_out_size(Config) when is_list(Config) ->
+    <<1, 2>> = matched_out_size_1(<<4, 1:4, 4, 2:4>>),
+    ok.
+
+matched_out_size_1(Binary) ->
+    << <<X>> || <<S, X:S>> <= Binary>>.
+
 cs_init() ->
     erts_debug:set_internal_state(available_internal_state, true),
     ok.
-- 
2.16.4