]> granicus.if.org Git - clang/commitdiff
Pull VLA size checker into its own files.
authorZhongxing Xu <xuzhongxing@gmail.com>
Tue, 3 Nov 2009 12:13:38 +0000 (12:13 +0000)
committerZhongxing Xu <xuzhongxing@gmail.com>
Tue, 3 Nov 2009 12:13:38 +0000 (12:13 +0000)
Split it to two checkers, one for undefined size,
the other for zero size, so that we don't need to query the size
when emitting the bug report.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85895 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/PathSensitive/Checker.h
include/clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h [new file with mode: 0644]
include/clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h [new file with mode: 0644]
lib/Analysis/GRExprEngine.cpp
lib/Analysis/GRExprEngineInternalChecks.cpp
lib/Analysis/UndefSizedVLAChecker.cpp [new file with mode: 0644]
lib/Analysis/ZeroSizedVLAChecker.cpp [new file with mode: 0644]
test/Analysis/misc-ps.m

index ac856d370fef9985433235ae50ddf4dd8b202f32..013459951168c6f7515dfb80928fbaa751e80409 100644 (file)
@@ -126,6 +126,13 @@ public:
                                       GRExprEngine &Eng) {
     return Pred;
   }
+
+  virtual ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, 
+                                  const GRState *state, Stmt *S, 
+                                  GRExprEngine &Eng) {
+    return Pred;
+  }
+
 };
 
 } // end clang namespace
diff --git a/include/clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h b/include/clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h
new file mode 100644 (file)
index 0000000..9d4507c
--- /dev/null
@@ -0,0 +1,29 @@
+//=== UndefSizedVLAChecker.h - Undefined dereference checker ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefSizedVLAChecker, a builtin check in GRExprEngine that 
+// performs checks for declaration of VLA of undefined size.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checker.h"
+
+namespace clang {
+
+class UndefSizedVLAChecker : public Checker {
+  BugType *BT;
+
+public:
+  UndefSizedVLAChecker() : BT(0) {}
+  static void *getTag();
+  ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, 
+                          const GRState *state, Stmt *S, GRExprEngine &Eng);
+};
+
+}
diff --git a/include/clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h b/include/clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h
new file mode 100644 (file)
index 0000000..4d3be31
--- /dev/null
@@ -0,0 +1,29 @@
+//=== ZeroSizedVLAChecker.cpp - Undefined dereference checker ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines ZeorSizedVLAChecker, a builtin check in GRExprEngine that 
+// performs checks for declaration of VLA of zero size.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checker.h"
+
+namespace clang {
+
+class ZeroSizedVLAChecker : public Checker {
+  BugType *BT;
+
+public:
+  ZeroSizedVLAChecker() : BT(0) {}
+  static void *getTag();
+  ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, 
+                          const GRState *state, Stmt *S, GRExprEngine &Eng);
+};
+
+}
index d0710e588084b1e3feaf66a3e9cba3ed823bab5c..eb8c39c306647eddca1c75b0e9a1aa7d3bbb4a30 100644 (file)
@@ -2058,45 +2058,25 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
     Tmp.Add(Pred);
 
   for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
-    const GRState* state = GetState(*I);
-    unsigned Count = Builder->getCurrentBlockCount();
-
-    // Check if 'VD' is a VLA and if so check if has a non-zero size.
-    QualType T = getContext().getCanonicalType(VD->getType());
-    if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
-      // FIXME: Handle multi-dimensional VLAs.
-
-      Expr* SE = VLA->getSizeExpr();
-      SVal Size_untested = state->getSVal(SE);
-
-      if (Size_untested.isUndef()) {
-        if (ExplodedNode* N = Builder->generateNode(DS, state, Pred)) {
-          N->markAsSink();
-          ExplicitBadSizedVLA.insert(N);
-        }
-        continue;
-      }
-
-      DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Size_untested);
-      const GRState *zeroState =  state->Assume(Size, false);
-      state = state->Assume(Size, true);
+    ExplodedNode *N = *I;
+    const GRState *state;
+
+    for (CheckersOrdered::iterator CI = Checkers.begin(), CE = Checkers.end(); 
+         CI != CE; ++CI) {
+      state = GetState(N);
+      N = CI->second->CheckType(getContext().getCanonicalType(VD->getType()),
+                                N, state, DS, *this);
+      if (!N)
+        break;
+    }
 
-      if (zeroState) {
-        if (ExplodedNode* N = Builder->generateNode(DS, zeroState, Pred)) {
-          N->markAsSink();
-          if (state)
-            ImplicitBadSizedVLA.insert(N);
-          else
-            ExplicitBadSizedVLA.insert(N);
-        }
-      }
+    if (!N)
+      continue;
 
-      if (!state)
-        continue;
-    }
+    state = GetState(N);
 
     // Decls without InitExpr are not initialized explicitly.
-    const LocationContext *LC = (*I)->getLocationContext();
+    const LocationContext *LC = N->getLocationContext();
 
     if (InitEx) {
       SVal InitVal = state->getSVal(InitEx);
@@ -2106,7 +2086,8 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
       // UnknownVal.
       if (InitVal.isUnknown() ||
           !getConstraintManager().canReasonAbout(InitVal)) {
-        InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Count);
+        InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, 
+                                               Builder->getCurrentBlockCount());
       }
 
       state = state->bindDecl(VD, LC, InitVal);
index 908835a53ccfb345a649476ad473df6ce5ce51b7..089d25d6cf5be2167cc3a2f963718fcfef0afb7a 100644 (file)
@@ -21,6 +21,8 @@
 #include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h"
 #include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h"
 #include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h"
+#include "clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h"
+#include "clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h"
 #include "clang/Analysis/PathDiagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/Support/Compiler.h"
@@ -449,66 +451,6 @@ public:
   }
 };
 
-class VISIBILITY_HIDDEN BadSizeVLA : public BuiltinBug {
-public:
-  BadSizeVLA(GRExprEngine* eng) :
-    BuiltinBug(eng, "Bad variable-length array (VLA) size") {}
-
-  void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
-    for (GRExprEngine::ErrorNodes::iterator
-          I = Eng.ExplicitBadSizedVLA.begin(),
-          E = Eng.ExplicitBadSizedVLA.end(); I!=E; ++I) {
-
-      // Determine whether this was a 'zero-sized' VLA or a VLA with an
-      // undefined size.
-      ExplodedNode* N = *I;
-      PostStmt PS = cast<PostStmt>(N->getLocation());
-      const DeclStmt *DS = cast<DeclStmt>(PS.getStmt());
-      VarDecl* VD = cast<VarDecl>(*DS->decl_begin());
-      QualType T = Eng.getContext().getCanonicalType(VD->getType());
-      VariableArrayType* VT = cast<VariableArrayType>(T);
-      Expr* SizeExpr = VT->getSizeExpr();
-
-      std::string buf;
-      llvm::raw_string_ostream os(buf);
-      os << "The expression used to specify the number of elements in the "
-            "variable-length array (VLA) '"
-         << VD->getNameAsString() << "' evaluates to ";
-
-      bool isUndefined = N->getState()->getSVal(SizeExpr).isUndef();
-
-      if (isUndefined)
-        os << "an undefined or garbage value.";
-      else
-        os << "0. VLAs with no elements have undefined behavior.";
-
-      std::string shortBuf;
-      llvm::raw_string_ostream os_short(shortBuf);
-      os_short << "Variable-length array '" << VD->getNameAsString() << "' "
-               << (isUndefined ? "garbage value for array size"
-                   : "has zero elements (undefined behavior)");
-
-      ArgReport *report = new ArgReport(*this, os_short.str().c_str(),
-                                        os.str().c_str(), N, SizeExpr);
-
-      report->addRange(SizeExpr->getSourceRange());
-      BR.EmitReport(report);
-    }
-  }
-
-  void registerInitialVisitors(BugReporterContext& BRC,
-                               const ExplodedNode* N,
-                               BuiltinBugReport *R) {
-    registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
-                                  N);
-  }
-};
-
-//===----------------------------------------------------------------------===//
-// __attribute__(nonnull) checking
-
-
-
 } // end clang namespace
 
 //===----------------------------------------------------------------------===//
@@ -528,7 +470,6 @@ void GRExprEngine::RegisterInternalChecks() {
   BR.Register(new BadMsgExprArg(this));
   BR.Register(new BadReceiver(this));
   BR.Register(new OutOfBoundMemoryAccess(this));
-  BR.Register(new BadSizeVLA(this));
   BR.Register(new NilReceiverStructRet(this));
   BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
 
@@ -543,4 +484,6 @@ void GRExprEngine::RegisterInternalChecks() {
   registerCheck<DivZeroChecker>(new DivZeroChecker());
   registerCheck<UndefDerefChecker>(new UndefDerefChecker());
   registerCheck<NullDerefChecker>(new NullDerefChecker());
+  registerCheck<UndefSizedVLAChecker>(new UndefSizedVLAChecker());
+  registerCheck<ZeroSizedVLAChecker>(new ZeroSizedVLAChecker());
 }
diff --git a/lib/Analysis/UndefSizedVLAChecker.cpp b/lib/Analysis/UndefSizedVLAChecker.cpp
new file mode 100644 (file)
index 0000000..e51e10e
--- /dev/null
@@ -0,0 +1,54 @@
+//=== UndefSizedVLAChecker.cpp - Undefined dereference checker --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefSizedVLAChecker, a builtin check in GRExprEngine that 
+// performs checks for declaration of VLA of undefined size.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+void *UndefSizedVLAChecker::getTag() {
+  static int x = 0;
+  return &x;
+}
+
+ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
+                                              const GRState *state,
+                                              Stmt *S, GRExprEngine &Eng) {
+  GRStmtNodeBuilder &Builder = Eng.getBuilder();
+  BugReporter &BR = Eng.getBugReporter();
+
+  if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
+    // FIXME: Handle multi-dimensional VLAs.
+    Expr* SE = VLA->getSizeExpr();
+    SVal Size_untested = state->getSVal(SE);
+
+    if (Size_untested.isUndef()) {
+      if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) {
+        N->markAsSink();
+        if (!BT)
+          BT = new BugType("Declare variable-length array (VLA) of undefined "
+                            "size", "Logic error");
+
+        EnhancedBugReport *R =
+                          new EnhancedBugReport(*BT, BT->getName().c_str(), N);
+        R->addRange(SE->getSourceRange());
+        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+        BR.EmitReport(R);
+      }
+      return 0;    
+    }
+  }
+  return Pred;
+}
diff --git a/lib/Analysis/ZeroSizedVLAChecker.cpp b/lib/Analysis/ZeroSizedVLAChecker.cpp
new file mode 100644 (file)
index 0000000..8984a5f
--- /dev/null
@@ -0,0 +1,66 @@
+//=== ZeroSizedVLAChecker.cpp - Undefined dereference checker ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines ZeorSizedVLAChecker, a builtin check in GRExprEngine that 
+// performs checks for declaration of VLA of zero size.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+void *ZeroSizedVLAChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, 
+                                             const GRState *state, Stmt *S, 
+                                             GRExprEngine &Eng) {
+  GRStmtNodeBuilder &Builder = Eng.getBuilder();
+  BugReporter &BR = Eng.getBugReporter();
+
+  if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
+    // FIXME: Handle multi-dimensional VLAs.
+    Expr* SE = VLA->getSizeExpr();
+    SVal Size_untested = state->getSVal(SE);
+
+    DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested);
+    // Undefined size is checked in another checker.
+    if (!Size)
+      return Pred;
+
+    const GRState *zeroState =  state->Assume(*Size, false);
+    state = state->Assume(*Size, true);
+
+    if (zeroState && !state) {
+      if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) {
+        N->markAsSink();
+        if (!BT)
+          BT = new BugType("Declare variable-length array (VLA) of zero size",
+                            "Logic error");
+
+        EnhancedBugReport *R =
+                          new EnhancedBugReport(*BT, BT->getName().c_str(), N);
+        R->addRange(SE->getSourceRange());
+        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+        BR.EmitReport(R);
+      }
+    }
+    if (!state)
+      return 0;
+
+    return Builder.generateNode(S, state, Pred);
+  }
+  else
+    return Pred;
+}
index 0d4592a9e3085646628d6945702a9f53ea94a376..947b41ae794cc9fc62ad5f68999b899d3c020263 100644 (file)
@@ -121,12 +121,12 @@ void check_zero_sized_VLA(int x) {
   if (x)
     return;
 
-  int vla[x]; // expected-warning{{Variable-length array 'vla' has zero elements (undefined behavior)}}
+  int vla[x]; // expected-warning{{Declare variable-length array (VLA) of zero size}}
 }
 
 void check_uninit_sized_VLA() {
   int x;
-  int vla[x]; // expected-warning{{Variable-length array 'vla' garbage value for array size}}
+  int vla[x]; // expected-warning{{Declare variable-length array (VLA) of undefined size}}
 }
 
 // sizeof(void)