zcov: / lib/Checker/CallAndMessageChecker.cpp


Files: 1 Branches Taken: 68.9% 51 / 74
Generated: 2010-02-10 01:31 Branches Executed: 89.2% 66 / 74
Line Coverage: 86.0% 86 / 100


Programs: 1 Runs 2897


       1                 : //===--- CallAndMessageChecker.cpp ------------------------------*- 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 CallAndMessageChecker, a builtin checker that checks for various
      11                 : // errors of call and objc message expressions.
      12                 : //
      13                 : //===----------------------------------------------------------------------===//
      14                 : 
      15                 : #include "clang/Basic/TargetInfo.h"
      16                 : #include "clang/Checker/PathSensitive/CheckerVisitor.h"
      17                 : #include "clang/Checker/BugReporter/BugReporter.h"
      18                 : #include "clang/AST/ParentMap.h"
      19                 : #include "GRExprEngineInternalChecks.h"
      20                 : 
      21                 : using namespace clang;
      22                 : 
      23                 : namespace {
      24                 : class CallAndMessageChecker
                     2138: branch 1 taken
                        0: branch 2 not taken
                        0: branch 5 not taken
                        0: branch 6 not taken
      25             2138:   : public CheckerVisitor<CallAndMessageChecker> {
      26                 :   BugType *BT_call_null;
      27                 :   BugType *BT_call_undef;  
      28                 :   BugType *BT_call_arg;
      29                 :   BugType *BT_msg_undef;
      30                 :   BugType *BT_msg_arg;
      31                 :   BugType *BT_msg_ret;
      32                 : public:
      33             2138:   CallAndMessageChecker() :
      34                 :     BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
      35             2138:     BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {}
      36                 : 
      37             2138:   static void *getTag() {
      38                 :     static int x = 0;
      39             2138:     return &x;
      40                 :   }
      41                 : 
      42                 :   void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
      43                 :   void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
      44                 :   bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
      45                 : 
      46                 : private:
      47                 :   void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
      48                 :   void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
      49                 :                           ExplodedNode *N);
      50                 :     
      51                 :   void HandleNilReceiver(CheckerContext &C, const GRState *state,
      52                 :                          const ObjCMessageExpr *ME);    
      53                 : };
      54                 : } // end anonymous namespace
      55                 : 
      56             2138: void clang::RegisterCallAndMessageChecker(GRExprEngine &Eng) {
      57             2138:   Eng.registerCheck(new CallAndMessageChecker());
      58             2138: }
      59                 : 
      60                 : void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
      61                0:                                         const CallExpr *CE) {
      62                0:   ExplodedNode *N = C.GenerateSink();
                        0: branch 0 not taken
                        0: branch 1 not taken
      63                0:   if (!N)
      64                0:     return;
      65                 :     
      66                0:   EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
      67                 :   R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
      68                0:                        bugreporter::GetCalleeExpr(N));
      69                0:   C.EmitReport(R);
      70                 : }
      71                 : 
      72                 : void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, 
      73             1666:                                              const CallExpr *CE){
      74                 :   
      75             1666:   const Expr *Callee = CE->getCallee()->IgnoreParens();
      76             1666:   SVal L = C.getState()->getSVal(Callee);
      77                 :   
                        0: branch 1 not taken
                     1666: branch 2 taken
      78             1666:   if (L.isUndef()) {
                        0: branch 0 not taken
                        0: branch 1 not taken
      79                0:     if (!BT_call_undef)
      80                 :       BT_call_undef =
      81                0:         new BuiltinBug("Called function pointer is an undefined pointer value");
      82                0:     EmitBadCall(BT_call_undef, C, CE);
      83               20:     return;
      84                 :   }
      85                 :   
                        0: branch 1 not taken
                     1666: branch 2 taken
      86             1666:   if (isa<loc::ConcreteInt>(L)) {
                        0: branch 0 not taken
                        0: branch 1 not taken
      87                0:     if (!BT_call_null)
      88                 :       BT_call_null =
      89                0:         new BuiltinBug("Called function pointer is null (null dereference)");
      90                0:     EmitBadCall(BT_call_null, C, CE);
      91                 :   }  
      92                 :   
                     2206: branch 4 taken
                     1646: branch 5 taken
      93             3852:   for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
      94                 :        I != E; ++I) {
                       20: branch 5 taken
                     2186: branch 6 taken
      95             2206:     if (C.getState()->getSVal(*I).isUndef()) {
                       20: branch 1 taken
                        0: branch 2 not taken
      96               20:       if (ExplodedNode *N = C.GenerateSink()) {
                       20: branch 0 taken
                        0: branch 1 not taken
      97               20:         if (!BT_call_arg)
      98                 :           BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
      99               20:                                        " is undefined");
     100                 :         // Generate a report for this bug.
     101                 :         EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
     102               20:                                                      BT_call_arg->getName(), N);
     103               20:         R->addRange((*I)->getSourceRange());
     104               20:         R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
     105               20:         C.EmitReport(R);
     106                 :         return;
     107                 :       }
     108                 :     }
                     1646: branch 1 taken
                       20: branch 2 taken
     109             1666:   }
     110                 : }
     111                 : 
     112                 : void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
     113             1271:                                                     const ObjCMessageExpr *ME) {
     114                 : 
     115             1271:   const GRState *state = C.getState();
     116                 : 
                      906: branch 1 taken
                      365: branch 2 taken
     117             1271:   if (const Expr *receiver = ME->getReceiver())
                        4: branch 3 taken
                      902: branch 4 taken
     118              906:     if (state->getSVal(receiver).isUndef()) {
                        4: branch 1 taken
                        0: branch 2 not taken
     119                4:       if (ExplodedNode *N = C.GenerateSink()) {
                        4: branch 0 taken
                        0: branch 1 not taken
     120                4:         if (!BT_msg_undef)
     121                 :           BT_msg_undef =
     122                4:             new BuiltinBug("Receiver in message expression is a garbage value");
     123                 :         EnhancedBugReport *R =
     124                4:           new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
     125                4:         R->addRange(receiver->getSourceRange());
     126                 :         R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
     127                4:                              receiver);
     128                4:         C.EmitReport(R);
     129                 :       }
     130                4:       return;
     131                 :     }
     132                 : 
     133                 :   // Check for any arguments that are uninitialized/undefined.
                      595: branch 3 taken
                     1255: branch 4 taken
     134             3117:   for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
     135             1267:          E = ME->arg_end(); I != E; ++I) {
                       12: branch 4 taken
                      583: branch 5 taken
     136              595:     if (state->getSVal(*I).isUndef()) {
                       12: branch 1 taken
                        0: branch 2 not taken
     137               12:       if (ExplodedNode *N = C.GenerateSink()) {
                       12: branch 0 taken
                        0: branch 1 not taken
     138               12:         if (!BT_msg_arg)
     139                 :           BT_msg_arg =
     140                 :             new BuiltinBug("Pass-by-value argument in message expression"
     141               12:                            " is undefined");      
     142                 :         // Generate a report for this bug.
     143                 :         EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
     144               12:                                                      BT_msg_arg->getName(), N);
     145               12:         R->addRange((*I)->getSourceRange());
     146               12:         R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
     147               12:         C.EmitReport(R);
     148               12:         return;
     149                 :       }
     150                 :     }
     151                 :   }
     152                 : }
     153                 : 
     154                 : bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
     155               44:                                             const ObjCMessageExpr *ME) {
     156               44:   HandleNilReceiver(C, C.getState(), ME);
     157               44:   return true; // Nil receiver is not handled elsewhere.
     158                 : }
     159                 : 
     160                 : void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
     161                 :                                                const ObjCMessageExpr *ME,
     162               12:                                                ExplodedNode *N) {
     163                 :   
                       12: branch 0 taken
                        0: branch 1 not taken
     164               12:   if (!BT_msg_ret)
     165                 :     BT_msg_ret =
     166                 :       new BuiltinBug("Receiver in message expression is "
     167               12:                      "'nil' and returns a garbage value");
     168                 :   
     169               12:   llvm::SmallString<200> buf;
     170               12:   llvm::raw_svector_ostream os(buf);
     171                 :   os << "The receiver of message '" << ME->getSelector().getAsString()
     172                 :      << "' is nil and returns a value of type '"
     173               12:      << ME->getType().getAsString() << "' that will be garbage";
     174                 :   
     175               12:   EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
     176               12:   const Expr *receiver = ME->getReceiver();
     177               12:   report->addRange(receiver->getSourceRange());
     178                 :   report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 
     179               12:                             receiver);
     180               12:   C.EmitReport(report);  
     181               12: }
     182                 : 
     183               16: static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
     184                 :   return triple.getVendor() == llvm::Triple::Apple &&
                       16: branch 1 taken
                        0: branch 2 not taken
                        8: branch 4 taken
                        8: branch 5 taken
     185               16:          triple.getDarwinMajorNumber() >= 9;
     186                 : }
     187                 : 
     188                 : void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
     189                 :                                               const GRState *state,
     190               44:                                               const ObjCMessageExpr *ME) {
     191                 :   
     192                 :   // Check the return type of the message expression.  A message to nil will
     193                 :   // return different values depending on the return type and the architecture.
     194               44:   QualType RetTy = ME->getType();
     195                 :   
     196               44:   ASTContext &Ctx = C.getASTContext();
     197               44:   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
     198                 : 
                        6: branch 3 taken
                       38: branch 4 taken
     199               44:   if (CanRetTy->isStructureType()) {
     200                 :     // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
     201                 :     // have the "use of undefined value" be smarter about where the
     202                 :     // undefined value came from.
                        4: branch 3 taken
                        2: branch 4 taken
     203                6:     if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
                        4: branch 1 taken
                        0: branch 2 not taken
     204                4:       if (ExplodedNode* N = C.GenerateSink(state))
     205                4:         EmitNilReceiverBug(C, ME, N);
     206                4:       return;
     207                 :     }
     208                 : 
     209                 :     // The result is not consumed by a surrounding expression.  Just propagate
     210                 :     // the current state.
     211                2:     C.addTransition(state);
     212                2:     return;
     213                 :   }
     214                 : 
     215                 :   // Other cases: check if the return type is smaller than void*.
                       34: branch 1 taken
                        4: branch 2 taken
                       30: branch 6 taken
                        4: branch 7 taken
                       30: branch 8 taken
                        8: branch 9 taken
     216               38:   if (CanRetTy != Ctx.VoidTy &&
     217                 :       C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
     218                 :     // Compute: sizeof(void *) and sizeof(return type)
     219               30:     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);    
     220               30:     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
     221                 : 
                       16: branch 0 taken
                       14: branch 1 taken
                        8: branch 4 taken
                        8: branch 5 taken
                        8: branch 7 taken
                        0: branch 8 not taken
                        6: branch 10 taken
                        2: branch 11 taken
                        4: branch 13 taken
                        2: branch 14 taken
                        0: branch 16 not taken
                        4: branch 17 taken
                        8: branch 18 taken
                       22: branch 19 taken
     222               30:     if (voidPtrSize < returnTypeSize &&
     223                 :         !(SupportsNilWithFloatRet(Ctx.Target.getTriple()) &&
     224                 :           (Ctx.FloatTy == CanRetTy ||
     225                 :            Ctx.DoubleTy == CanRetTy ||
     226                 :            Ctx.LongDoubleTy == CanRetTy ||
     227                 :            Ctx.LongLongTy == CanRetTy))) {
                        8: branch 1 taken
                        0: branch 2 not taken
     228                8:       if (ExplodedNode* N = C.GenerateSink(state))
     229                8:         EmitNilReceiverBug(C, ME, N);
     230                8:       return;
     231                 :     }
     232                 : 
     233                 :     // Handle the safe cases where the return value is 0 if the
     234                 :     // receiver is nil.
     235                 :     //
     236                 :     // FIXME: For now take the conservative approach that we only
     237                 :     // return null values if we *know* that the receiver is nil.
     238                 :     // This is because we can have surprises like:
     239                 :     //
     240                 :     //   ... = [[NSScreens screens] objectAtIndex:0];
     241                 :     //
     242                 :     // What can happen is that [... screens] could return nil, but
     243                 :     // it most likely isn't nil.  We should assume the semantics
     244                 :     // of this case unless we have *a lot* more knowledge.
     245                 :     //
     246               22:     SVal V = C.getValueManager().makeZeroVal(ME->getType());
     247               22:     C.GenerateNode(state->BindExpr(ME, V));
     248               22:     return;
     249                 :   }
     250                 :   
     251                8:   C.addTransition(state);
     252                0: }

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