[cfe-commits] r86003 - in /cfe/trunk: include/clang/Analysis/PathSensitive/Checker.h include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h include/clang/Analysis/PathSensitive/GRExprEngine.h lib/Analysis/GRExprEngine.cpp lib/Analysis/GRExprEngineInternalChecks.cpp lib/Analysis/UndefinedAssignmentChecker.cpp test/Analysis/uninit-vals-ps-region.c

Ted Kremenek kremenek at apple.com
Tue Nov 3 20:24:19 PST 2009


Author: kremenek
Date: Tue Nov  3 22:24:16 2009
New Revision: 86003

URL: http://llvm.org/viewvc/llvm-project?rev=86003&view=rev
Log:
Catch uses of undefined values when they are used in assignment, thus catching such bugs closer to the source.

Added:
    cfe/trunk/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h
    cfe/trunk/lib/Analysis/UndefinedAssignmentChecker.cpp
Modified:
    cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
    cfe/trunk/lib/Analysis/GRExprEngine.cpp
    cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp
    cfe/trunk/test/Analysis/uninit-vals-ps-region.c

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h?rev=86003&r1=86002&r2=86003&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h Tue Nov  3 22:24:16 2009
@@ -114,11 +114,19 @@
     _PreVisit(C, stmt);
   }
 
-
+  void GR_VisitBind(ExplodedNodeSet &Dst,
+                    GRStmtNodeBuilder &Builder, GRExprEngine &Eng,
+                    const Stmt *stmt, ExplodedNode *Pred, void *tag, 
+                    SVal location, SVal val,
+                    bool isPrevisit) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit);
+    assert(isPrevisit && "Only previsit supported for now.");
+    PreVisitBind(C, stmt, location, val);
+  }
 
 public:
   virtual ~Checker() {}
-  virtual void _PreVisit(CheckerContext &C, const Stmt *stmt) {}
+  virtual void _PreVisit(CheckerContext &C, const Stmt *ST) {}
   
   // This is a previsit which takes a node returns a node.
   virtual ExplodedNode *CheckLocation(const Stmt *S, ExplodedNode *Pred,
@@ -126,6 +134,9 @@
                                       GRExprEngine &Eng) {
     return Pred;
   }
+  
+  virtual void PreVisitBind(CheckerContext &C, const Stmt *ST, 
+                            SVal location, SVal val) {}
 
   virtual ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, 
                                   const GRState *state, Stmt *S, 

Added: cfe/trunk/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h?rev=86003&view=auto

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h (added)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h Tue Nov  3 22:24:16 2009
@@ -0,0 +1,32 @@
+//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefinedAssginmentChecker, a builtin check in GRExprEngine that
+// checks for assigning undefined values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNDEFASSIGNMENTCHECKER
+#define LLVM_CLANG_UNDEFASSIGNMENTCHECKER
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+
+namespace clang {
+class UndefinedAssignmentChecker
+  : public CheckerVisitor<UndefinedAssignmentChecker> {
+  BugType *BT;
+public:
+  UndefinedAssignmentChecker() : BT(0) {}
+  static void *getTag();
+  virtual void PreVisitBind(CheckerContext &C, const Stmt *S, SVal location,
+                            SVal val);
+};
+}
+#endif
+

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=86003&r1=86002&r2=86003&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Tue Nov  3 22:24:16 2009
@@ -411,6 +411,10 @@
   ///  at specific statements.
   void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, 
                     bool isPrevisit);
+  
+  void CheckerVisitBind(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, 
+                        SVal location, SVal val, bool isPrevisit);
+
 
   /// Visit - Transfer function logic for all statements.  Dispatches to
   ///  other functions that handle specific kinds of statements.

Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=86003&r1=86002&r2=86003&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Tue Nov  3 22:24:16 2009
@@ -139,6 +139,41 @@
   // automatically.
 }
 
+// FIXME: This is largely copy-paste from CheckerVisit().  Need to 
+// unify.
+void GRExprEngine::CheckerVisitBind(Stmt *S, ExplodedNodeSet &Dst,
+                                    ExplodedNodeSet &Src,
+                                    SVal location, SVal val, bool isPrevisit) {
+  
+  if (Checkers.empty()) {
+    Dst = Src;
+    return;
+  }
+  
+  ExplodedNodeSet Tmp;
+  ExplodedNodeSet *PrevSet = &Src;
+  
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+  {
+    ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst 
+    : (PrevSet == &Tmp) ? &Src : &Tmp;
+    
+    CurrSet->clear();
+    void *tag = I->first;
+    Checker *checker = I->second;
+    
+    for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+         NI != NE; ++NI)
+      checker->GR_VisitBind(*CurrSet, *Builder, *this, S, *NI, tag, location,
+                            val, isPrevisit);
+    
+    // Update which NodeSet is the current one.
+    PrevSet = CurrSet;
+  }
+  
+  // Don't autotransition.  The CheckerContext objects should do this
+  // automatically.
+}
 //===----------------------------------------------------------------------===//
 // Engine construction and deletion.
 //===----------------------------------------------------------------------===//
@@ -1093,36 +1128,49 @@
 void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt* Ex, ExplodedNode* Pred,
                             const GRState* state, SVal location, SVal Val,
                             bool atDeclInit) {
+  
+  
+  // Do a previsit of the bind.
+  ExplodedNodeSet CheckedSet, Src;
+  Src.Add(Pred);
+  CheckerVisitBind(Ex, CheckedSet, Src, location, Val, true);
+  
+  for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+       I!=E; ++I) {
+    
+    if (Pred != *I)
+      state = GetState(*I);
+    
+    const GRState* newState = 0;
 
-  const GRState* newState = 0;
-
-  if (atDeclInit) {
-    const VarRegion *VR =
-      cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion());
+    if (atDeclInit) {
+      const VarRegion *VR =
+        cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion());
 
-    newState = state->bindDecl(VR, Val);
-  }
-  else {
-    if (location.isUnknown()) {
-      // We know that the new state will be the same as the old state since
-      // the location of the binding is "unknown".  Consequently, there
-      // is no reason to just create a new node.
-      newState = state;
+      newState = state->bindDecl(VR, Val);
     }
     else {
-      // We are binding to a value other than 'unknown'.  Perform the binding
-      // using the StoreManager.
-      newState = state->bindLoc(cast<Loc>(location), Val);
+      if (location.isUnknown()) {
+        // We know that the new state will be the same as the old state since
+        // the location of the binding is "unknown".  Consequently, there
+        // is no reason to just create a new node.
+        newState = state;
+      }
+      else {
+        // We are binding to a value other than 'unknown'.  Perform the binding
+        // using the StoreManager.
+        newState = state->bindLoc(cast<Loc>(location), Val);
+      }
     }
-  }
 
-  // The next thing to do is check if the GRTransferFuncs object wants to
-  // update the state based on the new binding.  If the GRTransferFunc object
-  // doesn't do anything, just auto-propagate the current state.
-  GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, Pred, newState, Ex,
-                                  newState != state);
+    // The next thing to do is check if the GRTransferFuncs object wants to
+    // update the state based on the new binding.  If the GRTransferFunc object
+    // doesn't do anything, just auto-propagate the current state.
+    GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, Ex,
+                                    newState != state);
 
-  getTF().EvalBind(BuilderRef, location, Val);
+    getTF().EvalBind(BuilderRef, location, Val);
+  }
 }
 
 /// EvalStore - Handle the semantics of a store via an assignment.

Modified: cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp?rev=86003&r1=86002&r2=86003&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp Tue Nov  3 22:24:16 2009
@@ -19,6 +19,7 @@
 #include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h"
 #include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h"
 #include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h"
+#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
 #include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h"
 #include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h"
 #include "clang/Analysis/PathDiagnostic.h"
@@ -476,12 +477,13 @@
   // their associated BugType will get registered with the BugReporter
   // automatically.  Note that the check itself is owned by the GRExprEngine
   // object.
-  registerCheck<AttrNonNullChecker>(new AttrNonNullChecker());
-  registerCheck<UndefinedArgChecker>(new UndefinedArgChecker());
-  registerCheck<BadCallChecker>(new BadCallChecker());
-  registerCheck<DivZeroChecker>(new DivZeroChecker());
-  registerCheck<UndefDerefChecker>(new UndefDerefChecker());
-  registerCheck<NullDerefChecker>(new NullDerefChecker());
-  registerCheck<UndefSizedVLAChecker>(new UndefSizedVLAChecker());
-  registerCheck<ZeroSizedVLAChecker>(new ZeroSizedVLAChecker());
+  registerCheck(new AttrNonNullChecker());
+  registerCheck(new UndefinedArgChecker());
+  registerCheck(new UndefinedAssignmentChecker());
+  registerCheck(new BadCallChecker());
+  registerCheck(new DivZeroChecker());
+  registerCheck(new UndefDerefChecker());
+  registerCheck(new NullDerefChecker());
+  registerCheck(new UndefSizedVLAChecker());
+  registerCheck(new ZeroSizedVLAChecker());
 }

Added: cfe/trunk/lib/Analysis/UndefinedAssignmentChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/UndefinedAssignmentChecker.cpp?rev=86003&view=auto

==============================================================================
--- cfe/trunk/lib/Analysis/UndefinedAssignmentChecker.cpp (added)
+++ cfe/trunk/lib/Analysis/UndefinedAssignmentChecker.cpp Tue Nov  3 22:24:16 2009
@@ -0,0 +1,59 @@
+//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefinedAssginmentChecker, a builtin check in GRExprEngine that
+// checks for assigning undefined values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+void *UndefinedAssignmentChecker::getTag() {
+  static int x = 0;
+  return &x;
+}
+
+void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, 
+                                              const Stmt *S,
+                                              SVal location,
+                                              SVal val) {
+  if (!val.isUndef())
+    return;
+
+  ExplodedNode *N = C.GenerateNode(S, true);
+
+  if (!N)
+    return;
+
+  if (!BT)
+    BT = new BugType("Assigned value is garbage or undefined",
+                     "Logic error");
+
+  // Generate a report for this bug.
+  EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), N);
+  const Expr *ex = 0;
+
+  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
+    ex = B->getRHS();
+  else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+    const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+    ex = VD->getInit();
+  }
+
+  if (ex) {
+    R->addRange(ex->getSourceRange());
+    R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex);
+  }
+
+  C.EmitReport(R);
+}  
+

Modified: cfe/trunk/test/Analysis/uninit-vals-ps-region.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/uninit-vals-ps-region.c?rev=86003&r1=86002&r2=86003&view=diff

==============================================================================
--- cfe/trunk/test/Analysis/uninit-vals-ps-region.c (original)
+++ cfe/trunk/test/Analysis/uninit-vals-ps-region.c Tue Nov  3 22:24:16 2009
@@ -24,9 +24,20 @@
   struct TestUninit v1 = { 0, 0 };
   struct TestUninit v2 = test_uninit_aux();
   int z;
-  v1.y = z;
-  test_unit_aux2(v2.x + v1.y);  // expected-warning{{The right operand of '+' is a garbage value}}
+  v1.y = z; // expected-warning{{Assigned value is garbage or undefined}}
+  test_unit_aux2(v2.x + v1.y);
 }
+void test_uninit_pos_2() {
+  struct TestUninit v1 = { 0, 0 };
+  struct TestUninit v2;
+  test_unit_aux2(v2.x + v1.y);  // expected-warning{{The left operand of '+' is a garbage value}}
+}
+void test_uninit_pos_3() {
+  struct TestUninit v1 = { 0, 0 };
+  struct TestUninit v2;
+  test_unit_aux2(v1.y + v2.x);  // expected-warning{{The right operand of '+' is a garbage value}}
+}
+
 void test_uninit_neg() {
   struct TestUninit v1 = { 0, 0 };
   struct TestUninit v2 = test_uninit_aux();





More information about the cfe-commits mailing list