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