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

openSUSE Build Service is sponsored by