zcov: / lib/Checker/DereferenceChecker.cpp


Files: 1 Branches Taken: 67.6% 23 / 34
Generated: 2010-02-10 01:31 Branches Executed: 94.1% 32 / 34
Line Coverage: 97.9% 47 / 48


Programs: 1 Runs 2897


       1                 : //== NullDerefChecker.cpp - Null dereference checker ------------*- 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 defines NullDerefChecker, a builtin check in GRExprEngine that performs
      11                 : // checks for null pointers at loads and stores.
      12                 : //
      13                 : //===----------------------------------------------------------------------===//
      14                 : 
      15                 : #include "clang/Checker/Checkers/DereferenceChecker.h"
      16                 : #include "clang/Checker/PathSensitive/Checker.h"
      17                 : #include "clang/Checker/PathSensitive/GRExprEngine.h"
      18                 : #include "clang/Checker/BugReporter/BugReporter.h"
      19                 : #include "GRExprEngineInternalChecks.h"
      20                 : 
      21                 : using namespace clang;
      22                 : 
      23                 : namespace {
                     2138: branch 2 taken
                        0: branch 3 not taken
                        0: branch 7 not taken
                        0: branch 8 not taken
      24             2138: class DereferenceChecker : public Checker {
      25                 :   BuiltinBug *BT_null;
      26                 :   BuiltinBug *BT_undef;
      27                 :   llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
      28                 : public:
      29             2138:   DereferenceChecker() : BT_null(0), BT_undef(0) {}
      30             2162:   static void *getTag() { static int tag = 0; return &tag; }
      31                 :   void VisitLocation(CheckerContext &C, const Stmt *S, SVal location);
      32                 :   
      33                 :   std::pair<ExplodedNode * const*, ExplodedNode * const*>
      34               24:   getImplicitNodes() const {    
      35                 :     return std::make_pair(ImplicitNullDerefNodes.data(),
      36                 :                           ImplicitNullDerefNodes.data() +
      37               24:                           ImplicitNullDerefNodes.size());
      38                 :   }
      39                 : };
      40                 : } // end anonymous namespace
      41                 : 
      42             2138: void clang::RegisterDereferenceChecker(GRExprEngine &Eng) {
      43             2138:   Eng.registerCheck(new DereferenceChecker());
      44             2138: }
      45                 : 
      46                 : std::pair<ExplodedNode * const *, ExplodedNode * const *>
      47               24: clang::GetImplicitNullDereferences(GRExprEngine &Eng) {
      48               24:   DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
                        0: branch 0 not taken
                       24: branch 1 taken
      49               24:   if (!checker)
      50                 :     return std::make_pair((ExplodedNode * const *) 0,
      51                0:                           (ExplodedNode * const *) 0);
      52               24:   return checker->getImplicitNodes();
      53                 : }
      54                 : 
      55                 : void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
      56            10159:                                        SVal l) {
      57                 :   // Check for dereference of an undefined value.
                       10: branch 1 taken
                    10149: branch 2 taken
      58            10159:   if (l.isUndef()) {
                       10: branch 1 taken
                        0: branch 2 not taken
      59               10:     if (ExplodedNode *N = C.GenerateSink()) {
                       10: branch 0 taken
                        0: branch 1 not taken
      60               10:       if (!BT_undef)
      61               10:         BT_undef = new BuiltinBug("Dereference of undefined pointer value");
      62                 :       
      63                 :       EnhancedBugReport *report =
      64               10:         new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
      65                 :       report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
      66               10:                                 bugreporter::GetDerefExpr(N));
      67               10:       C.EmitReport(report);
      68                 :     }
      69               10:     return;
      70                 :   }
      71                 :   
      72            10149:   DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
      73                 :   
      74                 :   // Check for null dereferences.  
                        0: branch 1 not taken
                    10149: branch 2 taken
      75            10149:   if (!isa<Loc>(location))
      76               74:     return;
      77                 :   
      78            10149:   const GRState *state = C.getState();
      79                 :   const GRState *notNullState, *nullState;
      80            10149:   llvm::tie(notNullState, nullState) = state->Assume(location);
      81                 :   
      82                 :   // The explicit NULL case.
                      392: branch 0 taken
                     9757: branch 1 taken
      83            10149:   if (nullState) {
                       74: branch 0 taken
                      318: branch 1 taken
      84              392:     if (!notNullState) {    
      85                 :       // Generate an error node.
      86               74:       ExplodedNode *N = C.GenerateSink(nullState);
                        0: branch 0 not taken
                       74: branch 1 taken
      87               74:       if (!N)
      88                 :         return;
      89                 :       
      90                 :       // We know that 'location' cannot be non-null.  This is what
      91                 :       // we call an "explicit" null dereference.        
                       74: branch 0 taken
                        0: branch 1 not taken
      92               74:       if (!BT_null)
      93               74:         BT_null = new BuiltinBug("Dereference of null pointer");
      94                 :       
      95               74:       llvm::SmallString<100> buf;
      96                 : 
                       60: branch 1 taken
                       14: branch 2 taken
      97               74:       switch (S->getStmtClass()) {
      98                 :         case Stmt::UnaryOperatorClass: {
      99               60:           const UnaryOperator *U = cast<UnaryOperator>(S);
     100               60:           const Expr *SU = U->getSubExpr()->IgnoreParens();
                       59: branch 1 taken
                        1: branch 2 taken
     101               60:           if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
                       59: branch 2 taken
                        0: branch 3 not taken
     102               59:             if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
     103               59:               llvm::raw_svector_ostream os(buf);
     104                 :               os << "Dereference of null pointer loaded from variable '"
     105               59:                  << VD->getName() << '\'';
     106                 :             }
     107                 :           }
     108                 :         }
     109                 :         default:
     110                 :           break;
     111                 :       }
     112                 : 
     113                 :       EnhancedBugReport *report =
     114                 :         new EnhancedBugReport(*BT_null,
     115                 :                               buf.empty() ? BT_null->getDescription():buf.str(),
                       15: branch 1 taken
                       59: branch 2 taken
     116               74:                               N);
     117                 : 
     118                 :       report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
     119               74:                                 bugreporter::GetDerefExpr(N));
     120                 :       
     121               74:       C.EmitReport(report);
     122               74:       return;
     123                 :     }
     124                 :     else {
     125                 :       // Otherwise, we have the case where the location could either be
     126                 :       // null or not-null.  Record the error node as an "implicit" null
     127                 :       // dereference.      
                      318: branch 1 taken
                        0: branch 2 not taken
     128              318:       if (ExplodedNode *N = C.GenerateSink(nullState))
     129              318:         ImplicitNullDerefNodes.push_back(N);
     130                 :     }
     131                 :   }
     132                 :   
     133                 :   // From this point forward, we know that the location is not null.
                    10075: branch 2 taken
                       74: branch 3 taken
     134            10075:   C.addTransition(notNullState);
     135                 : }

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