]> granicus.if.org Git - clang/commitdiff
Enhance static analyzer diagnostics by introducing a new 'EnhancedBugReporter'
authorTed Kremenek <kremenek@apple.com>
Tue, 18 Aug 2009 01:05:30 +0000 (01:05 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 18 Aug 2009 01:05:30 +0000 (01:05 +0000)
which allows custom checks to register callback creator functions for creating
BugReporterVisitor objects. This allows various checks to include diagnostics
such as 'assuming value is null' with little extra work. Eventually this API
should be refactored to be cleaner and more simple.

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

include/clang/Analysis/PathSensitive/BugReporter.h
include/clang/Analysis/PathSensitive/Checker.h
lib/Analysis/BugReporter.cpp
lib/Analysis/BugReporterVisitors.cpp
lib/Analysis/GRExprEngineInternalChecks.cpp

index 70eb1da8f29935370d40aaf948f06ec5f39c9fb7..b99eaee953dc8a954d61a1fe61f70953d2ca48b4 100644 (file)
@@ -244,6 +244,35 @@ public:
   }
 };
   
+class EnhancedBugReport : public RangedBugReport {
+public:
+  typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
+                                 const ExplodedNode *N);
+  
+private:
+  typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
+  Creators creators;
+  
+public:
+  EnhancedBugReport(BugType& D, const char* description, ExplodedNode *n)
+   : RangedBugReport(D, description, n) {}
+  
+  EnhancedBugReport(BugType& D, const char *shortDescription,
+                  const char *description, ExplodedNode *n)
+    : RangedBugReport(D, shortDescription, description, n) {}
+  
+  ~EnhancedBugReport() {}
+  
+  void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {    
+    for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
+      I->first(BRC, I->second, N);
+  }
+  
+  void addVisitorCreator(VisitorCreator creator, const void *data) {
+    creators.push_back(std::make_pair(creator, data));
+  }
+};
+  
 //===----------------------------------------------------------------------===//
 // BugReporter and friends.
 //===----------------------------------------------------------------------===//
@@ -471,7 +500,7 @@ const Stmt *GetDenomExpr(const ExplodedNode *N);
 const Stmt *GetCalleeExpr(const ExplodedNode *N);
 const Stmt *GetRetValExpr(const ExplodedNode *N);
 
-void registerTrackNullOrUndefValue(BugReporterContext& BRC, const Stmt *S,
+void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
                                    const ExplodedNode* N);
 
 } // end namespace clang::bugreporter
index 278f85c16075bdfee47b0e18faad9069548d1e0a..77373699a2d553a24bc54f1d83a11d4db0af6f37 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/Analysis/Support/SaveAndRestore.h"
 #include "clang/Analysis/PathSensitive/GRCoreEngine.h"
 #include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/StmtCXX.h"
@@ -67,9 +68,18 @@ public:
   ExplodedNode *&getPredecessor() { return Pred; }
   const GRState *getState() { return B.GetState(Pred); }
   
-  ExplodedNode *generateNode(const Stmt* S,
-                                      const GRState *state) {
-    return B.generateNode(S, state, Pred);
+  ASTContext &getASTContext() {
+    return Eng.getContext();
+  }
+  
+  ExplodedNode *generateNode(const Stmt* S, const GRState *state,
+                             bool markAsSink = false) {    
+    ExplodedNode *node = B.generateNode(S, state, Pred);
+    
+    if (markAsSink && node)
+      node->markAsSink();
+    
+    return node;
   }
   
   void addTransition(ExplodedNode *node) {
index af4fd384e85ef049b7601f5d1ca26d06a6b949b4..354bafd9896c2bb22bc5689ef662f6083b201c3e 100644 (file)
@@ -41,8 +41,8 @@ BugReporterContext::~BugReporterContext() {
 //===----------------------------------------------------------------------===//
 
 static inline const Stmt* GetStmt(ProgramPoint P) {
-  if (const PostStmt* PS = dyn_cast<PostStmt>(&P))
-    return PS->getStmt();
+  if (const StmtPoint* SP = dyn_cast<StmtPoint>(&P))
+    return SP->getStmt();
   else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P))
     return BE->getSrc()->getTerminator();
   
index 77501bbba226fa94858620fbe9df5886d1d1a0e6..604542b2c1394f0d9239d2fddb155927467b4b7f 100644 (file)
@@ -189,6 +189,10 @@ public:
       else if (V.isUndef()) {
         os << "Uninitialized value stored to ";
       }
+      else if (isa<nonloc::ConcreteInt>(V)) {
+        os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
+           << " is assigned to ";
+      }
       else
         return NULL;
       
@@ -296,9 +300,11 @@ static void registerTrackConstraint(BugReporterContext& BRC, SVal Constraint,
 }
 
 void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
-                                                       const Stmt *S,
+                                                       const void *data,
                                                        const ExplodedNode* N) {
   
+  const Stmt *S = static_cast<const Stmt*>(data);
+  
   if (!S)
     return;
   
index 3c316eb3e9060e90c8b8b5af4fedc45b98a95cfc..d22f276a55ca77024b7c60d082196a14e5a31adf 100644 (file)
@@ -583,7 +583,7 @@ public:
       if (stateNull && !stateNotNull) {
         // Generate an error node.  Check for a null node in case
         // we cache out.
-        if (ExplodedNode *errorNode = C.generateNode(CE, stateNull)) {
+        if (ExplodedNode *errorNode = C.generateNode(CE, stateNull, true)) {
                   
           // Lazily allocate the BugType object if it hasn't already been
           // created. Ownership is transferred to the BugReporter object once
@@ -592,12 +592,15 @@ public:
             BT = new BugType("Argument with 'nonnull' attribute passed null",
                              "API");
           
-          RangedBugReport *R =
-            new RangedBugReport(*BT, "Null pointer passed as an argument to a "
-                                "'nonnull' parameter", errorNode);
+          EnhancedBugReport *R =
+            new EnhancedBugReport(*BT,
+                                  "Null pointer passed as an argument to a "
+                                  "'nonnull' parameter", errorNode);
           
           // Highlight the range of the argument that was null.
-          R->addRange((*I)->getSourceRange());
+          const Expr *arg = *I;
+          R->addRange(arg->getSourceRange());
+          R->addVisitorCreator(registerTrackNullOrUndefValue, arg);
           
           // Emit the bug report.
           C.EmitReport(R);