File 0916-sys_core_alias-Bail-out-when-expressions-get-too-dee.patch of Package erlang
From 7269a403a57400a19e9e0b7e10fbebf0cfbccc59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Wed, 1 Jul 2020 07:49:48 +0200
Subject: [PATCH] sys_core_alias: Bail out when expressions get too deep
---
lib/compiler/src/sys_core_alias.erl | 33 ++++++++++++++++----------
lib/compiler/test/core_alias_SUITE.erl | 29 ++++++++++++++++++++--
2 files changed, 47 insertions(+), 15 deletions(-)
diff --git a/lib/compiler/src/sys_core_alias.erl b/lib/compiler/src/sys_core_alias.erl
index 3326c6a2a8..591f38d0b7 100644
--- a/lib/compiler/src/sys_core_alias.erl
+++ b/lib/compiler/src/sys_core_alias.erl
@@ -284,24 +284,31 @@ nodes_to_alias(Kind, Inner, Anno, Node, Keys0) ->
%% Builds the key used to check if a value can be
%% replaced by an alias. It considers literals,
%% aliases, variables, tuples and cons recursively.
+%%
+%% We bail out after an arbitrary amount of nodes
+%% as very complex expressions may take forever to
+%% process otherwise.
+-define(DEPTH_LIMIT, 100).
nodes_to_key(Kind, Nodes) ->
- nodes_to_key(Nodes, [], Kind).
-
-nodes_to_key([#c_alias{var=Var}|T], Acc, Kind) ->
- nodes_to_key([Var|T], Acc, Kind);
-nodes_to_key([#c_var{name=Name}|T], Acc, Kind) ->
- nodes_to_key(T, [[var,Name]|Acc], Kind);
-nodes_to_key([Node|T], Acc0, Kind) ->
+ ntk_1(Nodes, [], Kind, ?DEPTH_LIMIT).
+
+ntk_1(_, _Acc, _Kind, 0) ->
+ error;
+ntk_1([#c_alias{var=Var}|T], Acc, Kind, N) ->
+ ntk_1([Var|T], Acc, Kind, N - 1);
+ntk_1([#c_var{name=Name}|T], Acc, Kind, N) ->
+ ntk_1(T, [[var,Name]|Acc], Kind, N - 1);
+ntk_1([Node|T], Acc0, Kind, N) ->
case cerl:is_data(Node) of
- false ->
- error;
true ->
- case nodes_to_key(cerl:data_es(Node), [], cerl:data_type(Node)) of
+ case ntk_1(cerl:data_es(Node), [], cerl:data_type(Node), N - 1) of
{ok,Key} ->
- nodes_to_key(T, [Key|Acc0], Kind);
+ ntk_1(T, [Key|Acc0], Kind, N - 1);
error ->
error
- end
+ end;
+ false ->
+ error
end;
-nodes_to_key([], Acc, Kind) ->
+ntk_1([], Acc, Kind, _N) ->
{ok,[Kind|Acc]}.
diff --git a/lib/compiler/test/core_alias_SUITE.erl b/lib/compiler/test/core_alias_SUITE.erl
index 094d3c8557..7e5dc4cbc0 100644
--- a/lib/compiler/test/core_alias_SUITE.erl
+++ b/lib/compiler/test/core_alias_SUITE.erl
@@ -21,7 +21,7 @@
-export([all/0, suite/0, groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2, end_per_group/2,
- tuples/1, cons/1]).
+ tuples/1, cons/1, catastrophic_runtime/1]).
-include_lib("common_test/include/ct.hrl").
@@ -32,7 +32,7 @@ all() ->
groups() ->
[{p,[parallel],
- [tuples, cons]}].
+ [tuples, cons, catastrophic_runtime]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -192,3 +192,28 @@ unaliased_literal_cons_body([nested,[ok|value]=X]) ->
unaliased_different_var_cons([nested,[ok|value]=X], Y) ->
io:format("~p~n", [X]),
[nested,Y].
+
+catastrophic_runtime(Config) ->
+ ct:timetrap({minutes, 6}),
+ Depth = 16000,
+
+ PrivDir = proplists:get_value(priv_dir,Config),
+ Path = filename:join(PrivDir, "catastrophic_runtime.erl"),
+
+ Term = catastrophic_runtime_1(Depth),
+ Source = <<"-module(catastrophic_runtime). t(Value) -> ", Term/bits, ".">>,
+ file:write_file(Path, Source),
+
+ {ok, catastrophic_runtime} = compile:file(Path, [return_error]),
+ file:delete(Path),
+
+ ok.
+
+catastrophic_runtime_1(0) ->
+ <<"Value">>;
+catastrophic_runtime_1(N) ->
+ Nested = catastrophic_runtime_1(N - 1),
+ Integer = integer_to_binary(N),
+ Eq = <<"{{'.',[],[erlang,'=:=']},[],[Value, \"", Integer/bits, "\"]}">>,
+ <<"{{'.',[],[erlang,atom]},[],[", Nested/bits, ",", Eq/bits, "]}">>.
+
--
2.26.2