[clang] 3b9b3d5 - [Analyzer] Include typedef statements in CFG build.

Balázs Kéri via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 27 03:36:50 PDT 2020


Author: Balázs Kéri
Date: 2020-04-27T12:36:26+02:00
New Revision: 3b9b3d56efaa6f611458899d5a1cdc74f36d72a4

URL: https://github.com/llvm/llvm-project/commit/3b9b3d56efaa6f611458899d5a1cdc74f36d72a4
DIFF: https://github.com/llvm/llvm-project/commit/3b9b3d56efaa6f611458899d5a1cdc74f36d72a4.diff

LOG: [Analyzer] Include typedef statements in CFG build.

Summary:
Array size expressions in typedef statements with a VLA
(variable-length array) are handled from now as in plain
(non-typedef) VLA declarations.
Type-aliases with VLA are handled too
(but main focus is on C code).

Reviewers: Szelethus, aaron.ballman, NoQ, xazax.hun

Reviewed By: aaron.ballman, xazax.hun

Subscribers: rnkovacs, NoQ, efriedma, xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, Szelethus, donat.nagy, dkrupp, gamesh411, Charusso, martong, ASDenysPetrov, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D77809

Added: 
    clang/test/Analysis/cfg.c

Modified: 
    clang/lib/Analysis/CFG.cpp
    clang/test/Analysis/cfg.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 8091625703bc..bedc8455366f 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -2839,11 +2839,30 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
 /// DeclStmts and initializers in them.
 CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
   assert(DS->isSingleDecl() && "Can handle single declarations only.");
+
+  if (const auto *TND = dyn_cast<TypedefNameDecl>(DS->getSingleDecl())) {
+    // If we encounter a VLA, process its size expressions.
+    const Type *T = TND->getUnderlyingType().getTypePtr();
+    if (!T->isVariablyModifiedType())
+      return Block;
+
+    autoCreateBlock();
+    appendStmt(Block, DS);
+
+    CFGBlock *LastBlock = Block;
+    for (const VariableArrayType *VA = FindVA(T); VA != nullptr;
+         VA = FindVA(VA->getElementType().getTypePtr())) {
+      if (CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
+        LastBlock = NewBlock;
+    }
+    return LastBlock;
+  }
+
   VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
 
   if (!VD) {
-    // Of everything that can be declared in a DeclStmt, only VarDecls impact
-    // runtime semantics.
+    // Of everything that can be declared in a DeclStmt, only VarDecls and the
+    // exceptions above impact runtime semantics.
     return Block;
   }
 
@@ -2905,6 +2924,8 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
   }
 
   // If the type of VD is a VLA, then we must process its size expressions.
+  // FIXME: This does not find the VLA if it is embedded in other types,
+  // like here: `int (*p_vla)[x];`
   for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr());
        VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr())) {
     if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
@@ -3997,6 +4018,11 @@ CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
   }
 
   // VLA types have expressions that must be evaluated.
+  // Evaluation is done only for `sizeof`.
+
+  if (E->getKind() != UETT_SizeOf)
+    return Block;
+
   CFGBlock *lastBlock = Block;
 
   if (E->isArgumentType()) {

diff  --git a/clang/test/Analysis/cfg.c b/clang/test/Analysis/cfg.c
new file mode 100644
index 000000000000..3494dd6ac2a3
--- /dev/null
+++ b/clang/test/Analysis/cfg.c
@@ -0,0 +1,120 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -fheinous-gnu-extensions %s > %t 2>&1
+// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,WARNINGS %s
+
+// This file is the C version of cfg.cpp.
+// Tests that are C-specific should go into this file.
+
+// CHECK-LABEL: void checkWrap(int i)
+// CHECK: ENTRY
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK: Succs (21): B2 B3 B4 B5 B6 B7 B8 B9
+// CHECK: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
+// CHECK: B20 B21 B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (21): B2 B3 B4 B5 B6 B7 B8 B9
+// CHECK-NEXT: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
+// CHECK-NEXT: B20 B21 B1
+void checkWrap(int i) {
+  switch(i) {
+    case 0: break;
+    case 1: break;
+    case 2: break;
+    case 3: break;
+    case 4: break;
+    case 5: break;
+    case 6: break;
+    case 7: break;
+    case 8: break;
+    case 9: break;
+    case 10: break;
+    case 11: break;
+    case 12: break;
+    case 13: break;
+    case 14: break;
+    case 15: break;
+    case 16: break;
+    case 17: break;
+    case 18: break;
+    case 19: break;
+  }
+}
+
+// CHECK-LABEL: void checkGCCAsmRValueOutput()
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT:   1: int arg
+// CHECK-NEXT:   2: arg
+// CHECK-NEXT:   3: (int)[B1.2] (CStyleCastExpr, NoOp, int)
+// CHECK-NEXT:   4: asm ("" : "=r" ([B1.3]));
+// CHECK-NEXT:   5: arg
+// CHECK-NEXT:   6: asm ("" : "=r" ([B1.5]));
+void checkGCCAsmRValueOutput() {
+  int arg;
+  __asm__("" : "=r"((int)arg));  // rvalue output operand
+  __asm__("" : "=r"(arg));       // lvalue output operand
+}
+
+// CHECK-LABEL: int overlap_compare(int x)
+// CHECK: [B2]
+// CHECK-NEXT:   1: 1
+// CHECK-NEXT:   2: return [B2.1];
+// CHECK-NEXT:   Preds (1): B3(Unreachable)
+// CHECK-NEXT:   Succs (1): B0
+// CHECK: [B3]
+// CHECK-NEXT:   1: x
+// CHECK-NEXT:   2: [B3.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 5
+// CHECK-NEXT:   4: [B3.2] > [B3.3]
+// CHECK-NEXT:   T: if [B4.5] && [B3.4]
+// CHECK-NEXT:   Preds (1): B4
+// CHECK-NEXT:   Succs (2): B2(Unreachable) B1
+int overlap_compare(int x) {
+  if (x == -1 && x > 5)
+    return 1;
+
+  return 2;
+}
+
+// CHECK-LABEL: void vla_simple(int x)
+// CHECK: [B1]
+// CHECK-NEXT:   1: x
+// CHECK-NEXT:   2: [B1.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: int vla[x];
+void vla_simple(int x) {
+  int vla[x];
+}
+
+// CHECK-LABEL: void vla_typedef(int x)
+// CHECK: [B1]
+// CHECK-NEXT:   1: x
+// CHECK-NEXT:   2: [B1.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: typedef int VLA[x];
+void vla_typedef(int x) {
+  typedef int VLA[x];
+}
+
+// CHECK-LABEL: void vla_typedef_multi(int x, int y)
+// CHECK:  [B1]
+// CHECK-NEXT:   1: y
+// CHECK-NEXT:   2: [B1.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: x
+// CHECK-NEXT:   4: [B1.3] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   5: typedef int VLA[x][y];
+void vla_typedef_multi(int x, int y) {
+  typedef int VLA[x][y];
+}
+
+// CHECK-LABEL: void vla_type_indirect(int x)
+// CHECK:  [B1]
+// CHECK-NEXT:   1: int (*p_vla)[x];
+// CHECK-NEXT:   2: void (*fp_vla)(int *);
+void vla_type_indirect(int x) {
+  // Should evaluate x
+  // FIXME: does not work
+  int (*p_vla)[x];
+
+  // Do not evaluate x
+  void (*fp_vla)(int[x]);
+}

diff  --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp
index a7d707ee20d1..0159a3c0488c 100644
--- a/clang/test/Analysis/cfg.cpp
+++ b/clang/test/Analysis/cfg.cpp
@@ -12,42 +12,6 @@
 // off. Feel free to add tests that test only one of the CFG flavors if you're
 // not sure how the other flavor is supposed to work in your case.
 
-// CHECK-LABEL: void checkWrap(int i)
-// CHECK: ENTRY
-// CHECK-NEXT: Succs (1): B1
-// CHECK: [B1]
-// CHECK: Succs (21): B2 B3 B4 B5 B6 B7 B8 B9
-// CHECK: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
-// CHECK: B20 B21 B0
-// CHECK: [B0 (EXIT)]
-// CHECK-NEXT: Preds (21): B2 B3 B4 B5 B6 B7 B8 B9
-// CHECK-NEXT: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
-// CHECK-NEXT: B20 B21 B1
-void checkWrap(int i) {
-  switch(i) {
-    case 0: break;
-    case 1: break;
-    case 2: break;
-    case 3: break;
-    case 4: break;
-    case 5: break;
-    case 6: break;
-    case 7: break;
-    case 8: break;
-    case 9: break;
-    case 10: break;
-    case 11: break;
-    case 12: break;
-    case 13: break;
-    case 14: break;
-    case 15: break;
-    case 16: break;
-    case 17: break;
-    case 18: break;
-    case 19: break;
-  }
-}
-
 // CHECK-LABEL: void checkDeclStmts()
 // CHECK: ENTRY
 // CHECK-NEXT: Succs (1): B1
@@ -84,24 +48,6 @@ void checkDeclStmts() {
   static_assert(1, "abc");
 }
 
-
-// CHECK-LABEL: void checkGCCAsmRValueOutput()
-// CHECK: [B2 (ENTRY)]
-// CHECK-NEXT: Succs (1): B1
-// CHECK: [B1]
-// CHECK-NEXT:   1: int arg
-// CHECK-NEXT:   2: arg
-// CHECK-NEXT:   3: (int)[B1.2] (CStyleCastExpr, NoOp, int)
-// CHECK-NEXT:   4: asm ("" : "=r" ([B1.3]));
-// CHECK-NEXT:   5: arg
-// CHECK-NEXT:   6: asm ("" : "=r" ([B1.5]));
-void checkGCCAsmRValueOutput() {
-  int arg;
-  __asm__("" : "=r"((int)arg));  // rvalue output operand
-  __asm__("" : "=r"(arg));       // lvalue output operand
-}
-
-
 // CHECK-LABEL: void F(EmptyE e)
 // CHECK: ENTRY
 // CHECK-NEXT: Succs (1): B1
@@ -136,7 +82,6 @@ void testBuiltinSize() {
   (void)__builtin_object_size(dummy(), 0);
 }
 
-
 class A {
 public:
   A() {}
@@ -355,7 +300,6 @@ int test_enum_with_extension_default(enum MyEnum value) {
   return x;
 }
 
-
 // CHECK-LABEL: void test_placement_new()
 // CHECK:  [B2 (ENTRY)]
 // CHECK-NEXT:  Succs (1): B1
@@ -547,25 +491,88 @@ int foo() {
 }
 } // namespace statement_expression_in_return
 
-// CHECK-LABEL: int overlap_compare(int x)
-// CHECK: [B2]
-// CHECK-NEXT:   1: 1
-// CHECK-NEXT:   2: return [B2.1];
-// CHECK-NEXT:   Preds (1): B3(Unreachable)
-// CHECK-NEXT:   Succs (1): B0
-// CHECK: [B3]
+// CHECK-LABEL: void vla_simple(int x)
+// CHECK: [B1]
 // CHECK-NEXT:   1: x
-// CHECK-NEXT:   2: [B3.1] (ImplicitCastExpr, LValueToRValue, int)
-// CHECK-NEXT:   3: 5
-// CHECK-NEXT:   4: [B3.2] > [B3.3]
-// CHECK-NEXT:   T: if [B4.5] && [B3.4]
-// CHECK-NEXT:   Preds (1): B4
-// CHECK-NEXT:   Succs (2): B2(Unreachable) B1
-int overlap_compare(int x) {
-  if (x == -1 && x > 5)
-    return 1;
-
-  return 2;
+// CHECK-NEXT:   2: [B1.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: int vla[x];
+void vla_simple(int x) {
+  int vla[x];
+}
+
+// CHECK-LABEL: void vla_typedef(int x)
+// CHECK: [B1]
+// CHECK-NEXT:   1: x
+// CHECK-NEXT:   2: [B1.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: typedef int VLA[x];
+void vla_typedef(int x) {
+  typedef int VLA[x];
+}
+
+// CHECK-LABEL: void vla_typealias(int x)
+// CHECK: [B1]
+// CHECK-NEXT:   1: x
+// CHECK-NEXT:   2: [B1.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: using VLA = int [x];
+void vla_typealias(int x) {
+  using VLA = int[x];
+}
+
+// CHECK-LABEL: void vla_typedef_multi(int x, int y)
+// CHECK:  [B1]
+// CHECK-NEXT:   1: y
+// CHECK-NEXT:   2: [B1.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: x
+// CHECK-NEXT:   4: [B1.3] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   5: typedef int VLA[x][y];
+void vla_typedef_multi(int x, int y) {
+  typedef int VLA[x][y];
+}
+
+// CHECK-LABEL: void vla_typedefname_multi(int x, int y)
+// CHECK:  [B1]
+// CHECK-NEXT:   1: x
+// CHECK-NEXT:   2: [B1.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: typedef int VLA[x];
+// CHECK-NEXT:   4: y
+// CHECK-NEXT:   5: [B1.4] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   6: typedef VLA VLA1[y];
+// CHECK-NEXT:   7: 3
+// CHECK-NEXT:   8: using VLA2 = VLA1 [3];
+// CHECK-NEXT:   9: 4
+// CHECK-NEXT:  10: VLA2 vla[4];
+void vla_typedefname_multi(int x, int y) {
+  typedef int VLA[x];
+  typedef VLA VLA1[y];
+  using VLA2 = VLA1[3];
+  VLA2 vla[4];
+}
+
+// CHECK-LABEL: int vla_evaluate(int x)
+// CHECK:  [B1]
+// CHECK-NEXT:   1: x
+// CHECK-NEXT:   2: ++[B1.1]
+// CHECK-NEXT:   3: [B1.2] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   4: typedef int VLA[++x];
+// CHECK-NEXT:   5: x
+// CHECK-NEXT:   6: ++[B1.5]
+// CHECK-NEXT:   7: [B1.6] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   8: sizeof(int [++x])
+// CHECK-NEXT:   9: alignof(int [++x])
+// CHECK-NEXT:  10: 0
+// CHECK-NEXT:  11: x
+// CHECK-NEXT:  12: [B1.11] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:  13: return [B1.12];
+int vla_evaluate(int x) {
+  // Evaluates the ++x
+  typedef int VLA[++x];
+  sizeof(int[++x]);
+
+  // Do not evaluate the ++x
+  _Alignof(int[++x]);
+  _Generic((int(*)[++x])0, default : 0);
+
+  return x;
 }
 
 // CHECK-LABEL: template<> int *PR18472<int>()


        


More information about the cfe-commits mailing list