]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
d: Limit recursive expansion to a common global limit.
authorIain Buclaw <ibuclaw@gdcproject.org>
Tue, 25 Aug 2020 09:44:48 +0000 (11:44 +0200)
committerIain Buclaw <ibuclaw@gdcproject.org>
Sun, 30 Aug 2020 14:23:54 +0000 (16:23 +0200)
Fixes both a bug where compilation would hang, and an issue where recursive
template limits are hit too early.

gcc/d/ChangeLog:

* dmd/globals.h (Global): Add recursionLimit.
* dmd/dmacro.c (Macro::expand): Limit recursive expansion to
global.recursionLimit.
* dmd/dtemplate.c (deduceType): Likewise.
(TemplateInstance::tryExpandMembers): Likewise.
(TemplateInstance::trySemantic3): Likewise.
(TemplateMixin::semantic): Likewise.
* dmd/expressionsem.c (ExpressionSemanticVisitor::visit): Likewise.
* dmd/mtype.c (Type::noMember): Likewise.
(TypeFunction::semantic): Likewise.
* dmd/optimize.c (Expression_optimize): Likewise.

gcc/testsuite/ChangeLog:

* gdc.test/compilable/ice20092.d: New test.

(cherry picked from commit 0f5c98b6a1a7eed281e359f40bc2e4326f2a2f56)

gcc/d/dmd/dmacro.c
gcc/d/dmd/dtemplate.c
gcc/d/dmd/expressionsem.c
gcc/d/dmd/globals.h
gcc/d/dmd/mtype.c
gcc/d/dmd/optimize.c
gcc/testsuite/gdc.test/compilable/ice20092.d [new file with mode: 0644]

index 77fe08add1f5eda660bba9f9b01299f84fc79893..5a85866493de505c163ceb350df6cb56003f817d 100644 (file)
@@ -226,11 +226,10 @@ void Macro::expand(OutBuffer *buf, size_t start, size_t *pend,
 {
     // limit recursive expansion
     static int nest;
-    static const int nestLimit = 1000;
-    if (nest > nestLimit)
+    if (nest > global.recursionLimit)
     {
-        error(Loc(), "DDoc macro expansion limit exceeded; more than %d "
-            "expansions.", nestLimit);
+        error(Loc(), "DDoc macro expansion limit exceeded; more than %d expansions.",
+              global.recursionLimit);
         return;
     }
     nest++;
index b5e3662a9e30b855fb181731009aa7b8d1ef78f1..9d211eb0340d00fcbff64267255760e9741b9548 100644 (file)
@@ -4337,6 +4337,13 @@ MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *par
 
         void visit(ArrayLiteralExp *e)
         {
+            // https://issues.dlang.org/show_bug.cgi?id=20092
+            if (e->elements && e->elements->dim &&
+                e->type->toBasetype()->nextOf()->ty == Tvoid)
+            {
+                result = deduceEmptyArrayElement();
+                return;
+            }
             if ((!e->elements || !e->elements->dim) &&
                 e->type->toBasetype()->nextOf()->ty == Tvoid &&
                 tparam->ty == Tarray)
@@ -5932,10 +5939,10 @@ void TemplateInstance::tryExpandMembers(Scope *sc2)
     static int nest;
     // extracted to a function to allow windows SEH to work without destructors in the same function
     //printf("%d\n", nest);
-    if (++nest > 500)
+    if (++nest > global.recursionLimit)
     {
         global.gag = 0;                 // ensure error message gets printed
-        error("recursive expansion");
+        error("recursive expansion exceeded allowed nesting limit");
         fatal();
     }
 
@@ -5949,10 +5956,10 @@ void TemplateInstance::trySemantic3(Scope *sc2)
     // extracted to a function to allow windows SEH to work without destructors in the same function
     static int nest;
     //printf("%d\n", nest);
-    if (++nest > 300)
+    if (++nest > global.recursionLimit)
     {
         global.gag = 0;            // ensure error message gets printed
-        error("recursive expansion");
+        error("recursive expansion exceeded allowed nesting limit");
         fatal();
     }
     semantic3(sc2);
@@ -6353,7 +6360,7 @@ Lerror:
         while (ti && !ti->deferred && ti->tinst)
         {
             ti = ti->tinst;
-            if (++nest > 500)
+            if (++nest > global.recursionLimit)
             {
                 global.gag = 0;            // ensure error message gets printed
                 error("recursive expansion");
@@ -8440,7 +8447,7 @@ void TemplateMixin::semantic(Scope *sc)
 
     static int nest;
     //printf("%d\n", nest);
-    if (++nest > 500)
+    if (++nest > global.recursionLimit)
     {
         global.gag = 0;                 // ensure error message gets printed
         error("recursive expansion");
index 559c656e65406b9c74413f303fb2e963dc6be04d..5ec4683848e7802de55304bbc6e1ffcc4f05b36e 100644 (file)
@@ -2900,7 +2900,7 @@ public:
             else
             {
                 static int nest;
-                if (++nest > 500)
+                if (++nest > global.recursionLimit)
                 {
                     exp->error("recursive evaluation of %s", exp->toChars());
                     --nest;
index 1094679b83761071c345564399c66b87ef38a5b0..855ba739b5d45d3e75f252ce2ac0b100dc512dba 100644 (file)
@@ -236,6 +236,8 @@ struct Global
 
     void* console;         // opaque pointer to console for controlling text attributes
 
+    enum { recursionLimit = 500 }; // number of recursive template expansions before abort
+
     /* Start gagging. Return the current number of gagged errors
      */
     unsigned startGagging();
index aa1880624cebc52efba6ab7b54135b120ca88c62..3fb16e000ef76e702e6b8e34f5aaedca008778c3 100644 (file)
@@ -2202,7 +2202,7 @@ Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident, int flag
 
     static int nest;      // https://issues.dlang.org/show_bug.cgi?id=17380
 
-    if (++nest > 500)
+    if (++nest > global.recursionLimit)
     {
       ::error(e->loc, "cannot resolve identifier `%s`", ident->toChars());
       --nest;
@@ -5449,7 +5449,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
 
     bool errors = false;
 
-    if (inuse > 500)
+    if (inuse > global.recursionLimit)
     {
         inuse = 0;
         ::error(loc, "recursive type");
index 2e702ba9d86690eeedbc500dad21c0852215fb9b..bae9d8e54031d9494fbc248becde04e2ea519136 100644 (file)
@@ -19,6 +19,7 @@
 #include "init.h"
 #include "enum.h"
 #include "ctfe.h"
+#include "errors.h"
 
 Expression *semantic(Expression *e, Scope *sc);
 
@@ -1256,10 +1257,18 @@ Expression *Expression_optimize(Expression *e, int result, bool keepLvalue)
     v.ret = e;
 
     // Optimize the expression until it can no longer be simplified.
-    while (ex != v.ret)
+    size_t b = 0;
+    while (1)
     {
+        if (b++ == global.recursionLimit)
+        {
+            e->error("infinite loop while optimizing expression");
+            fatal();
+        }
         ex = v.ret;
         ex->accept(&v);
+        if (ex == v.ret)
+            break;
     }
     return ex;
 }
diff --git a/gcc/testsuite/gdc.test/compilable/ice20092.d b/gcc/testsuite/gdc.test/compilable/ice20092.d
new file mode 100644 (file)
index 0000000..ff2be37
--- /dev/null
@@ -0,0 +1,10 @@
+void foo()
+{
+    (void[1]).init.front;
+}
+
+void front(T)(T[] a)
+{
+    static assert(is(T == void));
+}
+