Mordante created this revision.
Mordante added reviewers: rnk, rsmith, aaron.ballman.
Mordante added a project: clang.

When a long set of expressions is chained it may overflow the stack. This warns 
about the issue.

Note I'm not sure whether `AnalyzeImplicitConversions` is the best place to add 
this test, but it was the best I could find. Also not sure what the naming 
convention for these helpers is. Another option is to put the original code in 
a lambda in `AnalyzeImplicitConversions` and thus remove the extra function.

Fixes https://bugs.llvm.org/show_bug.cgi?id=14030

Depends on D69478 <https://reviews.llvm.org/D69478> (if this patch is unwanted 
it is possible to remove the dependency.)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D69479

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaChecking.cpp
  clang/test/Sema/stack-overflow-expr-bool.cpp
  clang/test/Sema/stack-overflow-expr-double.c
  clang/test/Sema/stack-overflow-expr-int.c

Index: clang/test/Sema/stack-overflow-expr-int.c
===================================================================
--- /dev/null
+++ clang/test/Sema/stack-overflow-expr-int.c
@@ -0,0 +1,21 @@
+// The segmentation fault gives exit code 139
+// RUN: not not %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
+// REQUIRES: thread_support
+
+#define A10 ARG ARG ARG ARG ARG ARG ARG ARG ARG ARG
+#define A100 A10 A10 A10 A10 A10 A10 A10 A10 A10 A10
+#define A1000 A10 A10 A10 A10 A10 A10 A10 A10 A10 A10
+#define A10000 A100 A100 A100 A100 A100 A100 A100 A100 A100 A100
+#define A100000 A1000 A1000 A1000 A1000 A1000 A1000 A1000 A1000 A1000 A1000
+#define A1000000 A10000 A10000 A10000 A10000 A10000 A10000 A10000 A10000 A10000 A10000
+#define A10000000 A100000 A100000 A100000 A100000 A100000 A100000 A100000 A100000 A100000 A100000
+#define A100000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000
+
+#define ARG 1 +
+void foo() {
+  int i = A100000000 1;
+}
+
+// CHECK: warning: stack nearly exhausted; compilation time may suffer, and crashes due to stack overflow are likely
+// CHECK: note: Reduce the number of chained expressions, using helper variables or parens
+// CHECK: Stack dump:
Index: clang/test/Sema/stack-overflow-expr-double.c
===================================================================
--- /dev/null
+++ clang/test/Sema/stack-overflow-expr-double.c
@@ -0,0 +1,21 @@
+// The segmentation fault gives exit code 139
+// RUN: not not %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
+// REQUIRES: thread_support
+
+#define A10 ARG ARG ARG ARG ARG ARG ARG ARG ARG ARG
+#define A100 A10 A10 A10 A10 A10 A10 A10 A10 A10 A10
+#define A1000 A10 A10 A10 A10 A10 A10 A10 A10 A10 A10
+#define A10000 A100 A100 A100 A100 A100 A100 A100 A100 A100 A100
+#define A100000 A1000 A1000 A1000 A1000 A1000 A1000 A1000 A1000 A1000 A1000
+#define A1000000 A10000 A10000 A10000 A10000 A10000 A10000 A10000 A10000 A10000 A10000
+#define A10000000 A100000 A100000 A100000 A100000 A100000 A100000 A100000 A100000 A100000 A100000
+#define A100000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000
+
+#define ARG 1. +
+void foo() {
+  double f = A100000000 1.;
+}
+
+// CHECK: warning: stack nearly exhausted; compilation time may suffer, and crashes due to stack overflow are likely
+// CHECK: note: Reduce the number of chained expressions, using helper variables or parens
+// CHECK: Stack dump:
Index: clang/test/Sema/stack-overflow-expr-bool.cpp
===================================================================
--- /dev/null
+++ clang/test/Sema/stack-overflow-expr-bool.cpp
@@ -0,0 +1,21 @@
+// The segmentation fault gives exit code 139
+// RUN: not not %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
+// REQUIRES: thread_support
+
+#define A10 ARG ARG ARG ARG ARG ARG ARG ARG ARG ARG
+#define A100 A10 A10 A10 A10 A10 A10 A10 A10 A10 A10
+#define A1000 A10 A10 A10 A10 A10 A10 A10 A10 A10 A10
+#define A10000 A100 A100 A100 A100 A100 A100 A100 A100 A100 A100
+#define A100000 A1000 A1000 A1000 A1000 A1000 A1000 A1000 A1000 A1000 A1000
+#define A1000000 A10000 A10000 A10000 A10000 A10000 A10000 A10000 A10000 A10000 A10000
+#define A10000000 A100000 A100000 A100000 A100000 A100000 A100000 A100000 A100000 A100000 A100000
+#define A100000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000 A1000000
+
+#define ARG true &&
+void foo() {
+  bool b = A100000000 true;
+}
+
+// CHECK: warning: stack nearly exhausted; compilation time may suffer, and crashes due to stack overflow are likely
+// CHECK: note: Reduce the number of chained expressions, using helper variables or parens
+// CHECK: Stack dump:
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -10368,8 +10368,8 @@
           IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
 }
 
-static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC,
-                                       bool IsListInit = false);
+static void analyzeImplicitConversionsWithSufficientStackSpace(
+    Sema &S, Expr *E, SourceLocation CC, bool IsListInit = false);
 
 static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) {
   // Suppress cases where we are comparing against an enum constant.
@@ -10666,8 +10666,10 @@
 /// Analyze the operands of the given comparison.  Implements the
 /// fallback case from AnalyzeComparison.
 static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
-  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
-  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
+  analyzeImplicitConversionsWithSufficientStackSpace(S, E->getLHS(),
+                                                     E->getOperatorLoc());
+  analyzeImplicitConversionsWithSufficientStackSpace(S, E->getRHS(),
+                                                     E->getOperatorLoc());
 }
 
 /// Implements -Wsign-compare.
@@ -10756,8 +10758,10 @@
 
   // Go ahead and analyze implicit conversions in the operands.  Note
   // that we skip the implicit conversions on both sides.
-  AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc());
-  AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
+  analyzeImplicitConversionsWithSufficientStackSpace(S, LHS,
+                                                     E->getOperatorLoc());
+  analyzeImplicitConversionsWithSufficientStackSpace(S, RHS,
+                                                     E->getOperatorLoc());
 
   // If the signed range is non-negative, -Wsign-compare won't fire.
   if (signedRange.NonNegative)
@@ -10924,7 +10928,8 @@
 /// operations.
 static void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
   // Just recurse on the LHS.
-  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
+  analyzeImplicitConversionsWithSufficientStackSpace(S, E->getLHS(),
+                                                     E->getOperatorLoc());
 
   // We want to recurse on the RHS as normal unless we're assigning to
   // a bitfield.
@@ -10932,12 +10937,13 @@
     if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(),
                                   E->getOperatorLoc())) {
       // Recurse, ignoring any implicit conversions on the RHS.
-      return AnalyzeImplicitConversions(S, E->getRHS()->IgnoreParenImpCasts(),
-                                        E->getOperatorLoc());
+      return analyzeImplicitConversionsWithSufficientStackSpace(
+          S, E->getRHS()->IgnoreParenImpCasts(), E->getOperatorLoc());
     }
   }
 
-  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
+  analyzeImplicitConversionsWithSufficientStackSpace(S, E->getRHS(),
+                                                     E->getOperatorLoc());
 
   // Diagnose implicitly sequentially-consistent atomic assignment.
   if (E->getLHS()->getType()->isAtomicType())
@@ -11108,8 +11114,10 @@
   assert(isa<CompoundAssignOperator>(E) &&
          "Must be compound assignment operation");
   // Recurse on the LHS and RHS in here
-  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
-  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
+  analyzeImplicitConversionsWithSufficientStackSpace(S, E->getLHS(),
+                                                     E->getOperatorLoc());
+  analyzeImplicitConversionsWithSufficientStackSpace(S, E->getRHS(),
+                                                     E->getOperatorLoc());
 
   if (E->getLHS()->getType()->isAtomicType())
     S.Diag(E->getOperatorLoc(), diag::warn_atomic_implicit_seq_cst);
@@ -11876,14 +11884,15 @@
   if (isa<ConditionalOperator>(E))
     return CheckConditionalOperator(S, cast<ConditionalOperator>(E), CC, T);
 
-  AnalyzeImplicitConversions(S, E, CC);
+  analyzeImplicitConversionsWithSufficientStackSpace(S, E, CC);
   if (E->getType() != T)
     return CheckImplicitConversion(S, E, T, CC, &ICContext);
 }
 
 static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
                                      SourceLocation CC, QualType T) {
-  AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc());
+  analyzeImplicitConversionsWithSufficientStackSpace(S, E->getCond(),
+                                                     E->getQuestionLoc());
 
   bool Suspicious = false;
   CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious);
@@ -11927,8 +11936,11 @@
 /// AnalyzeImplicitConversions - Find and report any interesting
 /// implicit conversions in the given expression.  There are a couple
 /// of competing diagnostics here, -Wconversion and -Wsign-compare.
+///
+/// \note Do not call this function direct but use
+/// \ref analyzeImplicitConversionsWithSufficientStackSpace
 static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
-                                       bool IsListInit/*= false*/) {
+                                       bool IsListInit) {
   QualType T = OrigE->getType();
   Expr *E = OrigE->IgnoreParenImpCasts();
 
@@ -11974,7 +11986,8 @@
     // FIXME: Use a more uniform representation for this.
     for (auto *SE : POE->semantics())
       if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE))
-        AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC, IsListInit);
+        analyzeImplicitConversionsWithSufficientStackSpace(
+            S, OVE->getSourceExpr(), CC, IsListInit);
   }
 
   // Skip past explicit casts.
@@ -11982,7 +11995,8 @@
     E = CE->getSubExpr()->IgnoreParenImpCasts();
     if (!CE->getType()->isVoidType() && E->getType()->isAtomicType())
       S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
-    return AnalyzeImplicitConversions(S, E, CC, IsListInit);
+    return analyzeImplicitConversionsWithSufficientStackSpace(S, E, CC,
+                                                              IsListInit);
   }
 
   if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
@@ -12021,7 +12035,8 @@
       // Ignore checking string literals that are in logical and operators.
       // This is a common pattern for asserts.
       continue;
-    AnalyzeImplicitConversions(S, ChildExpr, CC, IsListInit);
+    analyzeImplicitConversionsWithSufficientStackSpace(S, ChildExpr, CC,
+                                                       IsListInit);
   }
 
   if (BO && BO->isLogicalOp()) {
@@ -12045,6 +12060,16 @@
   }
 }
 
+/// analyzeImplicitConversionsWithSufficientStackSpace - Find and report any
+/// interesting implicit conversions in the given expression.  There are a
+/// couple of competing diagnostics here, -Wconversion and -Wsign-compare.
+static void analyzeImplicitConversionsWithSufficientStackSpace(
+    Sema &S, Expr *OrigE, SourceLocation CC, bool IsListInit /*= false*/) {
+  S.runWithSufficientStackSpace(
+      CC, [&] { AnalyzeImplicitConversions(S, OrigE, CC, IsListInit); },
+      diag::note_reduce_expression_chaining);
+}
+
 /// Diagnose integer type and any valid implicit conversion to it.
 static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) {
   // Taking into account implicit conversions,
@@ -12321,7 +12346,7 @@
   CheckArrayAccess(E);
 
   // This is not the right CC for (e.g.) a variable initialization.
-  AnalyzeImplicitConversions(*this, E, CC);
+  analyzeImplicitConversionsWithSufficientStackSpace(*this, E, CC);
 }
 
 /// CheckBoolLikeConversion - Check conversion of given expression to boolean.
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3477,6 +3477,9 @@
   "cast to %1 from smaller integer type %0">,
   InGroup<IntToVoidPointerCast>;
 
+def note_reduce_expression_chaining : Note<
+  "Reduce the number of chained expressions, using helper variables or parens">;
+
 def warn_attribute_ignored_for_field_of_type : Warning<
   "%0 attribute ignored for field of type %1">,
   InGroup<IgnoredAttributes>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D69479: [... Mark de Wever via Phabricator via cfe-commits

Reply via email to