]> granicus.if.org Git - clang/commitdiff
Added proof-of-concept NULL pointer diagnostics to GRConstants.
authorTed Kremenek <kremenek@apple.com>
Thu, 7 Feb 2008 06:33:19 +0000 (06:33 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 7 Feb 2008 06:33:19 +0000 (06:33 +0000)
Modified the driver to pass the Diagnostic object to GRConstants.

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

Analysis/GRConstants.cpp
Driver/ASTConsumers.cpp
Driver/ASTConsumers.h
Driver/clang.cpp
include/clang/Analysis/Analyses/GRConstants.h
include/clang/Basic/DiagnosticKinds.def

index 9fc828616af5dc16d717699b6130dab9bcbd3ad8..84b0debb61fc089ef95594f3dc4a9a60e3daf66e 100644 (file)
@@ -22,6 +22,7 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Basic/Diagnostic.h"
 
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/DataTypes.h"
@@ -133,8 +134,6 @@ protected:
   
   bool StateCleaned;
   
-  ASTContext& getContext() const { return G.getContext(); }
-  
 public:
   GRConstants(GraphTy& g) : G(g), Liveness(G.getCFG(), G.getFunctionDecl()),
       Builder(NULL),
@@ -148,6 +147,9 @@ public:
     Liveness.runOnAllBlocks(G.getCFG(), NULL, true);
   }
   
+  /// getContext - Return the ASTContext associated with this analysis.
+  ASTContext& getContext() const { return G.getContext(); }
+  
   /// getCFG - Returns the CFG associated with this analysis.
   CFG& getCFG() { return G.getCFG(); }
   
@@ -178,6 +180,9 @@ public:
     return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
   }
   
+  typedef NullDerefTy::iterator null_iterator;
+  null_iterator null_begin() { return ExplicitNullDeref.begin(); }
+  null_iterator null_end() { return ExplicitNullDeref.end(); }
 
   /// ProcessStmt - Called by GREngine. Used to generate new successor
   ///  nodes by processing the 'effects' of a block-level statement.
@@ -1321,11 +1326,28 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRConstants::NodeTy*> :
 #endif
 
 namespace clang {
-void RunGRConstants(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx) {
+void RunGRConstants(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
+                    Diagnostic& Diag) {
+  
   GREngine<GRConstants> Engine(cfg, FD, Ctx);
-  Engine.ExecuteWorkList();  
+  Engine.ExecuteWorkList();
+  
+  // Look for explicit-Null dereferences and warn about them.
+  GRConstants* CheckerState = &Engine.getCheckerState();
+  
+  for (GRConstants::null_iterator I=CheckerState->null_begin(),
+                                  E=CheckerState->null_end(); I!=E; ++I) {
+    
+    const PostStmt& L = cast<PostStmt>((*I)->getLocation());
+    Expr* E = cast<Expr>(L.getStmt());
+    
+    Diag.Report(FullSourceLoc(E->getExprLoc(), Ctx.getSourceManager()),
+                diag::chkr_null_deref_after_check);
+  }
+  
+  
 #ifndef NDEBUG
-  GraphPrintCheckerState = &Engine.getCheckerState();
+  GraphPrintCheckerState = CheckerState;
   llvm::ViewGraph(*Engine.getGraph().roots_begin(),"GRConstants");
   GraphPrintCheckerState = NULL;
 #endif  
index 7b96a6c13868e4483a2a0403ceb1e79ba858fc25..3868e7d75c3836535e35eef77ce44dd5e1cc0161 100644 (file)
@@ -572,20 +572,22 @@ ASTConsumer *clang::CreateUnitValsChecker(Diagnostic &Diags) {
 
 namespace {
   class GRConstantsVisitor : public CFGVisitor {
+    Diagnostic &Diags;
     ASTContext* Ctx;
   public:
+    GRConstantsVisitor(Diagnostic &diags) : Diags(diags) {}
     
     virtual void Initialize(ASTContext &Context) { Ctx = &Context; }    
     virtual void VisitCFG(CFG& C, FunctionDecl&);
   };
 } // end anonymous namespace
 
-ASTConsumer* clang::CreateGRConstants() {
-  return new GRConstantsVisitor();
+ASTConsumer* clang::CreateGRConstants(Diagnostic &Diags) {
+  return new GRConstantsVisitor(Diags);
 }
 
 void GRConstantsVisitor::VisitCFG(CFG& C, FunctionDecl& FD) {
-  RunGRConstants(C, FD, *Ctx);
+  RunGRConstants(C, FD, *Ctx, Diags);
 }
 
 //===----------------------------------------------------------------------===//
index 10ab1eb83c4dc5910054f7e432c96cf0003cc1a0..28decda9b30bba019744344467b5955e08d70f36 100644 (file)
@@ -41,7 +41,7 @@ ASTConsumer *CreateDeadStoreChecker(Diagnostic &Diags);
 
 ASTConsumer *CreateUnitValsChecker(Diagnostic &Diags);
   
-ASTConsumer *CreateGRConstants();
+ASTConsumer *CreateGRConstants(Diagnostic &Diags);
 
 ASTConsumer *CreateCodeRewriterTest(const std::string& InFile,
                                     Diagnostic &Diags);
index 998ac1ed8699836aca21787228252d523fdb94a5..8b3c2f9cf003af72bbacbb717f1133972de10add 100644 (file)
@@ -969,7 +969,7 @@ static ASTConsumer* CreateASTConsumer(const std::string& InFile,
       return CreateUnitValsChecker(Diag);
       
     case AnalysisGRConstants:
-      return CreateGRConstants();
+      return CreateGRConstants(Diag);
       
     case TestSerialization:
       return CreateSerializationTest(Diag, FileMgr, LangOpts);
index 3a0385e5f7134bea6095fb91f51bc7da0d78a4da..afd0535a9aefa58f6aa3b1b3223b16a2a35e4bb2 100644 (file)
 #define LLVM_CLANG_GRCONSTANTS
 
 namespace clang {
+  class Diagnostic;
   
   /// RunGRConstants - This is a simple driver to run the GRConstants analysis
   ///  on a provided CFG.  This interface will eventually be replaced with
   ///  something more elaborate as the requirements on the interface become
   ///  clearer.
-  void RunGRConstants(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx);
+  void RunGRConstants(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
+                      Diagnostic& Diag);
   
 } // end clang namespace
 
index b19c485cf258058f076ebe76c3be95c6770339d7..7e31847e86a8061a0bb0ed49bdf348c1cafdd2e2 100644 (file)
@@ -954,5 +954,11 @@ DIAG(ext_return_missing_expr, EXTENSION,
 DIAG(ext_return_has_expr, EXTENSION,
      "void function '%0' should not return a value")
 
+//===----------------------------------------------------------------------===//
+// Static Analysis Warnings (Bug-Finding)
+//===----------------------------------------------------------------------===//
+
+DIAG(chkr_null_deref_after_check, ERROR,
+    "NULL pointer is dereferenced after it is checked for NULL.")
 
 #undef DIAG