File 0456-Don-t-crash-when-a-stacktrace-is-used-as-size-in-bin.patch of Package erlang

From 319bf983020f23dc4bdb165c52a2a9c40eb5beab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Thu, 27 Feb 2020 08:48:51 +0100
Subject: [PATCH 17/30] Don't crash when a stacktrace is used as size in binary
 matching

When a stacktrace was used as the size of binary segment in binary
matching, sys_core_fold would do an unsafe optimization that
would cause the compiler to crash in a later pass. Example:

    foo(Bin) ->
	try
	    throw(fail)
	catch
	    throw:fail:Stk ->
		 <<0:Stk>> = Bin

	end.
---
 lib/compiler/src/sys_core_fold.erl   | 20 +++++++++-----------
 lib/compiler/test/trycatch_SUITE.erl | 14 ++++++++++++++
 2 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 56b60a0fa4..2ed21cb2aa 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -2382,13 +2382,16 @@ opt_build_stacktrace(#c_let{vars=[#c_var{name=Cooked}],
                 true ->
                     Let
             end;
-        #c_case{arg=Arg,clauses=Cs0} ->
-            case core_lib:is_var_used(Cooked, Arg) orelse
-                is_used_in_any_guard(Cooked, Cs0) of
+        #c_case{clauses=Cs0} ->
+            NilBody = #c_literal{val=[]},
+            Cs1 = [C#c_clause{body=NilBody} || C <- Cs0],
+            Case = Body#c_case{clauses=Cs1},
+            case core_lib:is_var_used(Cooked, Case) of
                 false ->
-                    %% The built stacktrace is not used in the argument,
-                    %% so we can sink the building of the stacktrace into
-                    %% each arm of the case.
+                    %% The built stacktrace is not used in the case
+                    %% argument or in the head of any clause. Thus
+                    %% it is safe sink the building of the stacktrace
+                    %% into each arm of the case.
                     Cs = [begin
                               B = opt_build_stacktrace(Let#c_let{body=B0}),
                               C#c_clause{body=B}
@@ -2403,11 +2406,6 @@ opt_build_stacktrace(#c_let{vars=[#c_var{name=Cooked}],
 opt_build_stacktrace(Expr) ->
     Expr.
 
-is_used_in_any_guard(V, Cs) ->
-    any(fun(#c_clause{guard=G}) ->
-                core_lib:is_var_used(V, G)
-        end, Cs).
-
 %% opt_case_in_let(Let) -> Let'
 %%  Try to avoid building tuples that are immediately matched.
 %%  A common pattern is:
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index 4cff129d1f..6a97a3aa79 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -1178,8 +1178,22 @@ raise(_Config) ->
 
     badarg = bad_raise(fun() -> abs(id(x)) end),
 
+    error = stk_used_in_bin_size(<<0:42>>),
     ok.
 
+stk_used_in_bin_size(Bin) ->
+    try
+        throw(fail)
+    catch
+        throw:fail:Stk ->
+            %% The compiler would crash because the building of the
+            %% stacktrack was sunk into each case arm.
+            case Bin of
+                <<0:Stk>> -> ok;
+                _ -> error
+            end
+    end.
+
 bad_raise(Expr) ->
     try
         Expr()
-- 
2.16.4

openSUSE Build Service is sponsored by