zcov: / lib/Checker/AttrNonNullChecker.cpp


Files: 1 Branches Taken: 79.3% 23 / 29
Generated: 2010-02-10 01:31 Branches Executed: 93.1% 27 / 29
Line Coverage: 97.4% 37 / 38


Programs: 1 Runs 2897


       1                 : //===--- AttrNonNullChecker.h - Undefined arguments 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 AttrNonNullChecker, a builtin check in GRExprEngine that 
      11                 : // performs checks for arguments declared to have nonnull attribute.
      12                 : //
      13                 : //===----------------------------------------------------------------------===//
      14                 : 
      15                 : #include "clang/Checker/PathSensitive/CheckerVisitor.h"
      16                 : #include "clang/Checker/BugReporter/BugReporter.h"
      17                 : #include "GRExprEngineInternalChecks.h"
      18                 : 
      19                 : using namespace clang;
      20                 : 
      21                 : namespace {
      22                 : class AttrNonNullChecker
                     2138: branch 1 taken
                        0: branch 2 not taken
                        0: branch 5 not taken
                        0: branch 6 not taken
      23             2138:   : public CheckerVisitor<AttrNonNullChecker> {
      24                 :   BugType *BT;
      25                 : public:
      26             2138:   AttrNonNullChecker() : BT(0) {}
      27             2138:   static void *getTag() {
      28                 :     static int x = 0;
      29             2138:     return &x;
      30                 :   }
      31                 :   void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
      32                 : };
      33                 : } // end anonymous namespace
      34                 : 
      35             2138: void clang::RegisterAttrNonNullChecker(GRExprEngine &Eng) {
      36             2138:   Eng.registerCheck(new AttrNonNullChecker());
      37             2138: }
      38                 : 
      39                 : void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, 
      40             1678:                                           const CallExpr *CE) {
      41             1678:   const GRState *state = C.getState();
      42                 : 
      43                 :   // Check if the callee has a 'nonnull' attribute.
      44             1678:   SVal X = state->getSVal(CE->getCallee());
      45                 : 
      46             1678:   const FunctionDecl* FD = X.getAsFunctionDecl();
                       58: branch 0 taken
                     1620: branch 1 taken
      47             1678:   if (!FD)
      48             1654:     return;
      49                 : 
      50             1620:   const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
                     1584: branch 0 taken
                       36: branch 1 taken
      51             1620:   if (!Att)
      52                 :     return;
      53                 : 
      54                 :   // Iterate through the arguments of CE and check them for null.
      55               36:   unsigned idx = 0;
      56                 : 
                       30: branch 3 taken
                        4: branch 4 taken
                       12: branch 5 taken
                       70: branch 8 taken
                       24: branch 9 taken
      57              140:   for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
      58                 :        ++I, ++idx) {
      59                 : 
                       46: branch 1 taken
                       24: branch 2 taken
      60               70:     if (!Att->isNonNull(idx))
      61               24:       continue;
      62                 : 
      63               46:     const SVal &V = state->getSVal(*I);
      64               46:     const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
      65                 : 
                        4: branch 0 taken
                       42: branch 1 taken
      66               46:     if (!DV)
      67                4:       continue;
      68                 : 
      69               42:     ConstraintManager &CM = C.getConstraintManager();
      70                 :     const GRState *stateNotNull, *stateNull;
      71               42:     llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV);
      72                 : 
                       26: branch 0 taken
                       16: branch 1 taken
                       12: branch 2 taken
                       14: branch 3 taken
      73               42:     if (stateNull && !stateNotNull) {
      74                 :       // Generate an error node.  Check for a null node in case
      75                 :       // we cache out.
                       12: branch 1 taken
                        0: branch 2 not taken
      76               12:       if (ExplodedNode *errorNode = C.GenerateSink(stateNull)) {
      77                 : 
      78                 :         // Lazily allocate the BugType object if it hasn't already been
      79                 :         // created. Ownership is transferred to the BugReporter object once
      80                 :         // the BugReport is passed to 'EmitWarning'.
                       12: branch 0 taken
                        0: branch 1 not taken
      81               12:         if (!BT)
      82                 :           BT = new BugType("Argument with 'nonnull' attribute passed null",
      83               12:                            "API");
      84                 : 
      85                 :         EnhancedBugReport *R =
      86                 :           new EnhancedBugReport(*BT,
      87                 :                                 "Null pointer passed as an argument to a "
      88               12:                                 "'nonnull' parameter", errorNode);
      89                 : 
      90                 :         // Highlight the range of the argument that was null.
      91               12:         const Expr *arg = *I;
      92               12:         R->addRange(arg->getSourceRange());
      93               12:         R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg);
      94                 : 
      95                 :         // Emit the bug report.
      96               12:         C.EmitReport(R);
      97                 :       }
      98                 : 
      99                 :       // Always return.  Either we cached out or we just emitted an error.
     100                 :       return;
     101                 :     }
     102                 : 
     103                 :     // If a pointer value passed the check we should assume that it is
     104                 :     // indeed not null from this point forward.
                        0: branch 0 not taken
                       30: branch 1 taken
     105               30:     assert(stateNotNull);
     106               30:     state = stateNotNull;
     107                 :   }
     108                 : 
     109                 :   // If we reach here all of the arguments passed the nonnull check.
     110                 :   // If 'state' has been updated generated a new node.
                       24: branch 2 taken
                     1654: branch 3 taken
     111               24:   C.addTransition(state);
     112                0: }

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