zcov: / lib/Checker/BugReporterVisitors.cpp


Files: 1 Branches Taken: 63.0% 87 / 138
Generated: 2010-02-10 01:31 Branches Executed: 87.0% 120 / 138
Line Coverage: 76.5% 127 / 166


Programs: 1 Runs 2897


       1                 : // BugReporterVisitors.cpp - Helpers for reporting bugs -----------*- C++ -*--//
       2                 : //
       3                 : //                     The LLVM Compiler Infrastructure
       4                 : //
       5                 : // This file is distributed under the University of Illinois Open Source
       6                 : // License. See LICENSE.TXT for details.
       7                 : //
       8                 : //===----------------------------------------------------------------------===//
       9                 : //
      10                 : //  This file defines a set of BugReporter "visitors" which can be used to
      11                 : //  enhance the diagnostics reported for a bug.
      12                 : //
      13                 : //===----------------------------------------------------------------------===//
      14                 : 
      15                 : #include "clang/AST/Expr.h"
      16                 : #include "clang/AST/ExprObjC.h"
      17                 : #include "clang/Checker/BugReporter/BugReporter.h"
      18                 : #include "clang/Checker/BugReporter/PathDiagnostic.h"
      19                 : #include "clang/Checker/PathSensitive/GRState.h"
      20                 : 
      21                 : using namespace clang;
      22                 : 
      23                 : //===----------------------------------------------------------------------===//
      24                 : // Utility functions.
      25                 : //===----------------------------------------------------------------------===//
      26                 : 
      27               84: const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
      28                 :   // Pattern match for a few useful cases (do something smarter later):
      29                 :   //   a[0], p->f, *p
      30               84:   const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
      31                 : 
                       70: branch 1 taken
                       14: branch 2 taken
      32               84:   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
                       70: branch 1 taken
                        0: branch 2 not taken
      33               70:     if (U->getOpcode() == UnaryOperator::Deref)
      34               70:       return U->getSubExpr()->IgnoreParenCasts();
      35                 :   }
                        4: branch 1 taken
                       10: branch 2 taken
      36               14:   else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
      37                4:     return ME->getBase()->IgnoreParenCasts();
      38                 :   }
                       10: branch 1 taken
                        0: branch 2 not taken
      39               10:   else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
      40                 :     // Retrieve the base for arrays since BasicStoreManager doesn't know how
      41                 :     // to reason about them.
      42               10:     return AE->getBase();
      43                 :   }
      44                 : 
      45                0:   return NULL;
      46                 : }
      47                 : 
      48                 : const Stmt*
      49                0: clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
      50                0:   const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
                        0: branch 1 not taken
                        0: branch 2 not taken
      51                0:   if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
      52                0:     return ME->getReceiver();
      53                0:   return NULL;
      54                 : }
      55                 : 
      56                 : const Stmt*
      57                0: clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
      58                0:   const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
                        0: branch 1 not taken
                        0: branch 2 not taken
      59                0:   if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
      60                0:     return BE->getRHS();
      61                0:   return NULL;
      62                 : }
      63                 : 
      64                 : const Stmt*
      65                0: clang::bugreporter::GetCalleeExpr(const ExplodedNode *N) {
      66                 :   // Callee is checked as a PreVisit to the CallExpr.
      67                0:   const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
                        0: branch 1 not taken
                        0: branch 2 not taken
      68                0:   if (const CallExpr *CE = dyn_cast<CallExpr>(S))
      69                0:     return CE->getCallee();
      70                0:   return NULL;
      71                 : }
      72                 : 
      73                 : const Stmt*
      74                0: clang::bugreporter::GetRetValExpr(const ExplodedNode *N) {
      75                0:   const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
                        0: branch 1 not taken
                        0: branch 2 not taken
      76                0:   if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
      77                0:     return RS->getRetValue();
      78                0:   return NULL;
      79                 : }
      80                 : 
      81                 : //===----------------------------------------------------------------------===//
      82                 : // Definitions for bug reporter visitors.
      83                 : //===----------------------------------------------------------------------===//
      84                 : 
      85                 : namespace {
                      170: branch 2 taken
                        0: branch 3 not taken
                        0: branch 7 not taken
                        0: branch 8 not taken
      86              170: class FindLastStoreBRVisitor : public BugReporterVisitor {
      87                 :   const MemRegion *R;
      88                 :   SVal V;
      89                 :   bool satisfied;
      90                 :   const ExplodedNode *StoreSite;
      91                 : public:
      92              170:   FindLastStoreBRVisitor(SVal v, const MemRegion *r)
      93              170:   : R(r), V(v), satisfied(false), StoreSite(0) {}
      94                 : 
      95                 :   PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
      96                 :                                  const ExplodedNode *PrevN,
      97             1472:                                  BugReporterContext& BRC) {
      98                 : 
                      550: branch 0 taken
                      922: branch 1 taken
      99             1472:     if (satisfied)
     100              550:       return NULL;
     101                 : 
                      170: branch 0 taken
                      752: branch 1 taken
     102              922:     if (!StoreSite) {
     103              170:       const ExplodedNode *Node = N, *Last = NULL;
     104                 : 
                      947: branch 1 taken
                        2: branch 2 taken
     105              949:       for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
     106                 : 
                      947: branch 1 taken
                        0: branch 2 not taken
     107              947:         if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
                      825: branch 1 taken
                      122: branch 2 taken
     108              947:           if (const PostStmt *P = Node->getLocationAs<PostStmt>())
                      180: branch 1 taken
                      645: branch 2 taken
     109              825:             if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
                      160: branch 2 taken
                       20: branch 3 taken
     110              180:               if (DS->getSingleDecl() == VR->getDecl()) {
     111              160:                 Last = Node;
     112              160:                 break;
     113                 :               }
     114                 :         }
     115                 : 
                        8: branch 4 taken
                      779: branch 5 taken
     116              787:         if (Node->getState()->getSVal(R) != V)
     117                8:           break;
     118                 :       }
     119                 : 
                      168: branch 0 taken
                        2: branch 1 taken
                        0: branch 2 not taken
                      168: branch 3 taken
     120              170:       if (!Node || !Last) {
     121                2:         satisfied = true;
     122                2:         return NULL;
     123                 :       }
     124                 : 
     125              168:       StoreSite = Last;
     126                 :     }
     127                 : 
                      752: branch 0 taken
                      168: branch 1 taken
     128              920:     if (StoreSite != N)
     129              752:       return NULL;
     130                 : 
     131              168:     satisfied = true;
     132              168:     std::string sbuf;
     133              168:     llvm::raw_string_ostream os(sbuf);
     134                 : 
                      168: branch 1 taken
                        0: branch 2 not taken
     135              168:     if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
                      160: branch 1 taken
                        8: branch 2 taken
     136              168:       if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
     137                 : 
                      160: branch 1 taken
                        0: branch 2 not taken
     138              160:         if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
     139              160:           os << "Variable '" << VR->getDecl()->getNameAsString() << "' ";
     140                 :         }
     141                 :         else
     142                0:           return NULL;
     143                 : 
                       47: branch 1 taken
                      113: branch 2 taken
     144              160:         if (isa<loc::ConcreteInt>(V)) {
     145               47:           bool b = false;
     146               47:           ASTContext &C = BRC.getASTContext();
                       47: branch 1 taken
                        0: branch 2 not taken
     147               47:           if (R->isBoundable()) {
                       47: branch 1 taken
                        0: branch 2 not taken
     148               47:             if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
                        8: branch 3 taken
                       39: branch 4 taken
     149               47:               if (TR->getValueType(C)->isObjCObjectPointerType()) {
     150                8:                 os << "initialized to nil";
     151                8:                 b = true;
     152                 :               }
     153                 :             }
     154                 :           }
     155                 : 
                       39: branch 0 taken
                        8: branch 1 taken
     156               47:           if (!b)
     157               39:             os << "initialized to a null pointer value";
     158                 :         }
                        0: branch 1 not taken
                      113: branch 2 taken
     159              113:         else if (isa<nonloc::ConcreteInt>(V)) {
     160                0:           os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
     161                 :         }
                      113: branch 1 taken
                        0: branch 2 not taken
     162              113:         else if (V.isUndef()) {
                      113: branch 1 taken
                        0: branch 2 not taken
     163              113:           if (isa<VarRegion>(R)) {
     164              113:             const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
                        0: branch 1 not taken
                      113: branch 2 taken
     165              113:             if (VD->getInit())
     166                0:               os << "initialized to a garbage value";
     167                 :             else
     168              113:               os << "declared without an initial value";
     169                 :           }
     170                 :         }
     171                 :       }
     172                 :     }
     173                 : 
                        8: branch 2 taken
                      160: branch 3 taken
     174              168:     if (os.str().empty()) {
                        8: branch 1 taken
                        0: branch 2 not taken
     175                8:       if (isa<loc::ConcreteInt>(V)) {
     176                8:         bool b = false;
     177                8:         ASTContext &C = BRC.getASTContext();
                        8: branch 1 taken
                        0: branch 2 not taken
     178                8:         if (R->isBoundable()) {
                        8: branch 1 taken
                        0: branch 2 not taken
     179                8:           if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
                        2: branch 3 taken
                        6: branch 4 taken
     180                8:             if (TR->getValueType(C)->isObjCObjectPointerType()) {
     181                2:               os << "nil object reference stored to ";
     182                2:               b = true;
     183                 :             }
     184                 :           }
     185                 :         }
     186                 : 
                        6: branch 0 taken
                        2: branch 1 taken
     187                8:         if (!b)
     188                6:           os << "Null pointer value stored to ";
     189                 :       }
                        0: branch 1 not taken
                        0: branch 2 not taken
     190                0:       else if (V.isUndef()) {
     191                0:         os << "Uninitialized value stored to ";
     192                 :       }
                        0: branch 1 not taken
                        0: branch 2 not taken
     193                0:       else if (isa<nonloc::ConcreteInt>(V)) {
     194                 :         os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
     195                0:            << " is assigned to ";
     196                 :       }
     197                 :       else
     198                0:         return NULL;
     199                 : 
                        8: branch 1 taken
                        0: branch 2 not taken
     200                8:       if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
     201                8:         os << '\'' << VR->getDecl()->getNameAsString() << '\'';
     202                 :       }
     203                 :       else
     204                0:         return NULL;
     205                 :     }
     206                 : 
     207                 :     // FIXME: Refactor this into BugReporterContext.
     208              168:     const Stmt *S = 0;
     209              168:     ProgramPoint P = N->getLocation();
     210                 : 
                        0: branch 1 not taken
                      168: branch 2 taken
     211              168:     if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
     212                0:       CFGBlock *BSrc = BE->getSrc();
     213                0:       S = BSrc->getTerminatorCondition();
     214                 :     }
                      168: branch 1 taken
                        0: branch 2 not taken
     215              168:     else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
     216              168:       S = PS->getStmt();
     217                 :     }
     218                 : 
                        0: branch 0 not taken
                      168: branch 1 taken
     219              168:     if (!S)
     220                0:       return NULL;
     221                 : 
     222                 :     // Construct a new PathDiagnosticPiece.
     223              168:     PathDiagnosticLocation L(S, BRC.getSourceManager());
     224              168:     return new PathDiagnosticEventPiece(L, os.str());
     225                 :   }
     226                 : };
     227                 : 
     228                 : 
     229                 : static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
     230              170:                                   SVal V) {
     231              170:   BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
     232              170: }
     233                 : 
                       42: branch 2 taken
                        0: branch 3 not taken
                        0: branch 7 not taken
                        0: branch 8 not taken
     234               42: class TrackConstraintBRVisitor : public BugReporterVisitor {
     235                 :   DefinedSVal Constraint;
     236                 :   const bool Assumption;
     237                 :   bool isSatisfied;
     238                 : public:
     239               42:   TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
     240               42:   : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
     241                 : 
     242                 :   PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
     243                 :                                  const ExplodedNode *PrevN,
     244              437:                                  BugReporterContext& BRC) {
                      148: branch 0 taken
                      289: branch 1 taken
     245              437:     if (isSatisfied)
     246              148:       return NULL;
     247                 : 
     248                 :     // Check if in the previous state it was feasible for this constraint
     249                 :     // to *not* be true.
                       42: branch 3 taken
                      247: branch 4 taken
     250              289:     if (PrevN->getState()->Assume(Constraint, !Assumption)) {
     251                 : 
     252               42:       isSatisfied = true;
     253                 : 
     254                 :       // As a sanity check, make sure that the negation of the constraint
     255                 :       // was infeasible in the current state.  If it is feasible, we somehow
     256                 :       // missed the transition point.
                        0: branch 3 not taken
                       42: branch 4 taken
     257               42:       if (N->getState()->Assume(Constraint, !Assumption))
     258                0:         return NULL;
     259                 : 
     260                 :       // We found the transition point for the constraint.  We now need to
     261                 :       // pretty-print the constraint. (work-in-progress)
     262               42:       std::string sbuf;
     263               42:       llvm::raw_string_ostream os(sbuf);
     264                 : 
                       42: branch 1 taken
                        0: branch 2 not taken
     265               42:       if (isa<Loc>(Constraint)) {
     266               42:         os << "Assuming pointer value is ";
                        0: branch 0 not taken
                       42: branch 1 taken
     267               42:         os << (Assumption ? "non-null" : "null");
     268                 :       }
     269                 : 
                        0: branch 2 not taken
                       42: branch 3 taken
     270               42:       if (os.str().empty())
     271                0:         return NULL;
     272                 : 
     273                 :       // FIXME: Refactor this into BugReporterContext.
     274               42:       const Stmt *S = 0;
     275               42:       ProgramPoint P = N->getLocation();
     276                 : 
                       42: branch 1 taken
                        0: branch 2 not taken
     277               42:       if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
     278               42:         CFGBlock *BSrc = BE->getSrc();
     279               42:         S = BSrc->getTerminatorCondition();
     280                 :       }
                        0: branch 1 not taken
                        0: branch 2 not taken
     281                0:       else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
     282                0:         S = PS->getStmt();
     283                 :       }
     284                 : 
                        0: branch 0 not taken
                       42: branch 1 taken
     285               42:       if (!S)
     286                0:         return NULL;
     287                 : 
     288                 :       // Construct a new PathDiagnosticPiece.
     289               42:       PathDiagnosticLocation L(S, BRC.getSourceManager());
     290               42:       return new PathDiagnosticEventPiece(L, os.str());
     291                 :     }
     292                 : 
     293              247:     return NULL;
     294                 :   }
     295                 : };
     296                 : } // end anonymous namespace
     297                 : 
     298                 : static void registerTrackConstraint(BugReporterContext& BRC,
     299                 :                                     DefinedSVal Constraint,
     300               42:                                     bool Assumption) {
     301               42:   BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
     302               42: }
     303                 : 
     304                 : void clang::bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
     305                 :                                                        const void *data,
     306              237:                                                        const ExplodedNode* N) {
     307                 : 
     308              237:   const Stmt *S = static_cast<const Stmt*>(data);
     309                 : 
                        0: branch 0 not taken
                      237: branch 1 taken
     310              237:   if (!S)
     311                0:     return;
     312                 : 
     313              237:   GRStateManager &StateMgr = BRC.getStateManager();
     314              237:   const GRState *state = N->getState();
     315                 : 
                      222: branch 1 taken
                       15: branch 2 taken
     316              237:   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
                      222: branch 2 taken
                        0: branch 3 not taken
     317              222:     if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
     318                 :       const VarRegion *R =
     319              222:       StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
     320                 : 
     321                 :       // What did we load?
     322              222:       SVal V = state->getSVal(S);
     323                 : 
                      167: branch 1 taken
                       55: branch 2 taken
                      167: branch 4 taken
                        0: branch 5 not taken
                      115: branch 7 taken
                       52: branch 8 taken
                      170: branch 9 taken
                       52: branch 10 taken
     324              222:       if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
     325                 :           || V.isUndef()) {
     326              170:         registerFindLastStore(BRC, R, V);
     327              222:       }
     328                 :     }
     329                 :   }
     330                 : 
     331              237:   SVal V = state->getSValAsScalarOrLoc(S);
     332                 : 
     333                 :   // Uncomment this to find cases where we aren't properly getting the
     334                 :   // base value that was dereferenced.
     335                 :   // assert(!V.isUnknownOrUndef());
     336                 : 
     337                 :   // Is it a symbolic value?
                       42: branch 1 taken
                      195: branch 2 taken
     338              237:   if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
     339               42:     const SubRegion *R = cast<SubRegion>(L->getRegion());
                       46: branch 0 taken
                        0: branch 1 not taken
                        4: branch 3 taken
                       42: branch 4 taken
                        4: branch 5 taken
                       42: branch 6 taken
     340               88:     while (R && !isa<SymbolicRegion>(R)) {
     341                4:       R = dyn_cast<SubRegion>(R->getSuperRegion());
     342                 :     }
     343                 : 
                       42: branch 0 taken
                        0: branch 1 not taken
     344               42:     if (R) {
                        0: branch 1 not taken
                       42: branch 2 taken
     345               42:       assert(isa<SymbolicRegion>(R));
     346               42:       registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
     347                 :     }
     348              237:   }
     349                 : }

Generated: 2010-02-10 01:31 by zcov