zcov: / lib/Checker/OSAtomicChecker.cpp


Files: 1 Branches Taken: 61.3% 38 / 62
Generated: 2010-02-10 01:31 Branches Executed: 96.8% 60 / 62
Line Coverage: 88.8% 79 / 89


Programs: 1 Runs 2897


       1                 : //=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- 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 checker evaluates OSAtomic functions.
      11                 : //
      12                 : //===----------------------------------------------------------------------===//
      13                 : 
      14                 : #include "GRExprEngineInternalChecks.h"
      15                 : #include "clang/Checker/PathSensitive/Checker.h"
      16                 : #include "clang/Basic/Builtins.h"
      17                 : #include "llvm/ADT/StringSwitch.h"
      18                 : 
      19                 : using namespace clang;
      20                 : 
      21                 : namespace {
      22                 : 
                     2138: branch 2 taken
                        0: branch 3 not taken
                        0: branch 6 not taken
                        0: branch 7 not taken
      23             4276: class OSAtomicChecker : public Checker {
      24                 : public:
      25             2138:   static void *getTag() { static int tag = 0; return &tag; }
      26                 :   virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
      27                 : 
      28                 : private:
      29                 :   bool EvalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
      30                 : };
      31                 : 
      32                 : }
      33                 : 
      34             2138: void clang::RegisterOSAtomicChecker(GRExprEngine &Eng) {
      35             2138:   Eng.registerCheck(new OSAtomicChecker());
      36             2138: }
      37                 : 
      38             1605: bool OSAtomicChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE) {
      39             1605:   const GRState *state = C.getState();
      40             1605:   const Expr *Callee = CE->getCallee();
      41             1605:   SVal L = state->getSVal(Callee);
      42                 : 
      43             1605:   const FunctionDecl* FD = L.getAsFunctionDecl();
                       56: branch 0 taken
                     1549: branch 1 taken
      44             1605:   if (!FD)
      45               56:     return false;
      46                 : 
      47             1549:   const IdentifierInfo *II = FD->getIdentifier();
                        0: branch 0 not taken
                     1549: branch 1 taken
      48             1549:   if (!II)
      49                0:     return false;
      50                 :   
      51             1549:   llvm::StringRef FName(II->getName());
      52                 : 
      53                 :   // Check for compare and swap.
                     1493: branch 2 taken
                       56: branch 3 taken
                       16: branch 6 taken
                     1477: branch 7 taken
                       72: branch 8 taken
                     1477: branch 9 taken
      54             1549:   if (FName.startswith("OSAtomicCompareAndSwap") ||
      55                 :       FName.startswith("objc_atomicCompareAndSwap"))
      56               72:     return EvalOSAtomicCompareAndSwap(C, CE);
      57                 : 
      58                 :   // FIXME: Other atomics.
      59             1477:   return false;
      60                 : }
      61                 : 
      62                 : bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, 
      63               72:                                                  const CallExpr *CE) {
      64                 :   // Not enough arguments to match OSAtomicCompareAndSwap?
                        0: branch 1 not taken
                       72: branch 2 taken
      65               72:   if (CE->getNumArgs() != 3)
      66                0:     return false;
      67                 : 
      68               72:   ASTContext &Ctx = C.getASTContext();
      69               72:   const Expr *oldValueExpr = CE->getArg(0);
      70               72:   QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
      71                 : 
      72               72:   const Expr *newValueExpr = CE->getArg(1);
      73               72:   QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
      74                 : 
      75                 :   // Do the types of 'oldValue' and 'newValue' match?
                        0: branch 1 not taken
                       72: branch 2 taken
      76               72:   if (oldValueType != newValueType)
      77                0:     return false;
      78                 : 
      79               72:   const Expr *theValueExpr = CE->getArg(2);
      80               72:   const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
      81                 : 
      82                 :   // theValueType not a pointer?
                        0: branch 0 not taken
                       72: branch 1 taken
      83               72:   if (!theValueType)
      84                0:     return false;
      85                 : 
      86                 :   QualType theValueTypePointee =
      87               72:     Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
      88                 : 
      89                 :   // The pointee must match newValueType and oldValueType.
                        0: branch 1 not taken
                       72: branch 2 taken
      90               72:   if (theValueTypePointee != newValueType)
      91                0:     return false;
      92                 : 
      93                 :   static unsigned magic_load = 0;
      94                 :   static unsigned magic_store = 0;
      95                 : 
      96               72:   const void *OSAtomicLoadTag = &magic_load;
      97               72:   const void *OSAtomicStoreTag = &magic_store;
      98                 : 
      99                 :   // Load 'theValue'.
     100               72:   GRExprEngine &Engine = C.getEngine();
     101               72:   const GRState *state = C.getState();
     102               72:   ExplodedNodeSet Tmp;
     103               72:   SVal location = state->getSVal(theValueExpr);
     104                 :   // Here we should use the value type of the region as the load type.
     105               72:   QualType LoadTy;
                       72: branch 0 taken
                        0: branch 1 not taken
     106               72:   if (const TypedRegion *TR =
     107               72:       dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
     108               72:     LoadTy = TR->getValueType(Ctx);
     109                 :   }
     110                 :   Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(), 
     111               72:                   state, location, OSAtomicLoadTag, LoadTy);
     112                 : 
                        0: branch 1 not taken
                       72: branch 2 taken
     113               72:   if (Tmp.empty()) {
     114                 :     // If no nodes were generated, other checkers must generated sinks. But 
     115                 :     // since the builder state was restored, we set it manually to prevent 
     116                 :     // auto transition.
     117                 :     // FIXME: there should be a better approach.
     118                0:     C.getNodeBuilder().BuildSinks = true;
     119                0:     return true;
     120                 :   }
     121                 :  
                       72: branch 3 taken
                        0: branch 4 not taken
                       72: branch 6 taken
                        0: branch 7 not taken
                       72: branch 9 taken
                        0: branch 10 not taken
                       72: branch 12 taken
                        0: branch 13 not taken
                       72: branch 15 taken
                        0: branch 16 not taken
                       72: branch 19 taken
                       72: branch 20 taken
     122              144:   for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
     123                 :        I != E; ++I) {
     124                 : 
     125               72:     ExplodedNode *N = *I;
     126               72:     const GRState *stateLoad = N->getState();
     127               72:     SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
     128               72:     SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
     129                 : 
     130                 :     // FIXME: Issue an error.
                       72: branch 1 taken
                        0: branch 2 not taken
                        0: branch 4 not taken
                       72: branch 5 taken
                        0: branch 6 not taken
                       72: branch 7 taken
     131               72:     if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
     132                0:       return false;
     133                 :     }
     134                 :     
     135                 :     DefinedOrUnknownSVal theValueVal =
     136               72:       cast<DefinedOrUnknownSVal>(theValueVal_untested);
     137                 :     DefinedOrUnknownSVal oldValueVal =
     138               72:       cast<DefinedOrUnknownSVal>(oldValueVal_untested);
     139                 : 
     140               72:     SValuator &SVator = Engine.getSValuator();
     141                 : 
     142                 :     // Perform the comparison.
     143               72:     DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad,theValueVal,oldValueVal);
     144                 : 
     145               72:     const GRState *stateEqual = stateLoad->Assume(Cmp, true);
     146                 : 
     147                 :     // Were they equal?
                       58: branch 0 taken
                       14: branch 1 taken
     148               72:     if (stateEqual) {
     149                 :       // Perform the store.
     150               58:       ExplodedNodeSet TmpStore;
     151               58:       SVal val = stateEqual->getSVal(newValueExpr);
     152                 : 
     153                 :       // Handle implicit value casts.
                       58: branch 0 taken
                        0: branch 1 not taken
     154               58:       if (const TypedRegion *R =
     155               58:           dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
     156               58:         val = SVator.EvalCast(val,R->getValueType(Ctx),newValueExpr->getType());
     157                 :       }
     158                 : 
     159                 :       Engine.EvalStore(TmpStore, NULL, const_cast<Expr *>(theValueExpr), N, 
     160               58:                        stateEqual, location, val, OSAtomicStoreTag);
     161                 : 
                        0: branch 1 not taken
                       58: branch 2 taken
     162               58:       if (TmpStore.empty()) {
     163                 :         // If no nodes were generated, other checkers must generated sinks. But 
     164                 :         // since the builder state was restored, we set it manually to prevent 
     165                 :         // auto transition.
     166                 :         // FIXME: there should be a better approach.
     167                0:         C.getNodeBuilder().BuildSinks = true;
     168                0:         return true;
     169                 :       }
     170                 : 
     171                 :       // Now bind the result of the comparison.
                       58: branch 4 taken
                       58: branch 5 taken
     172              174:       for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
     173               58:            E2 = TmpStore.end(); I2 != E2; ++I2) {
     174               58:         ExplodedNode *predNew = *I2;
     175               58:         const GRState *stateNew = predNew->getState();
     176                 :         // Check for 'void' return type if we have a bogus function prototype.
     177               58:         SVal Res = UnknownVal();
     178               58:         QualType T = CE->getType();
                       58: branch 2 taken
                        0: branch 3 not taken
     179               58:         if (!T->isVoidType())
     180               58:           Res = Engine.getValueManager().makeTruthVal(true, T);
     181               58:         C.GenerateNode(stateNew->BindExpr(CE, Res), predNew);
                       58: branch 1 taken
                        0: branch 2 not taken
                       58: branch 4 taken
                        0: branch 5 not taken
     182               58:       }
     183                 :     }
     184                 : 
     185                 :     // Were they not equal?
                       52: branch 2 taken
                       20: branch 3 taken
     186               72:     if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
     187                 :       // Check for 'void' return type if we have a bogus function prototype.
     188               52:       SVal Res = UnknownVal();
     189               52:       QualType T = CE->getType();
                       52: branch 2 taken
                        0: branch 3 not taken
     190               52:       if (!T->isVoidType())
     191               52:         Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
     192               52:       C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N);
     193                 :     }
     194                 :   }
     195                 : 
     196               72:   return true;
     197                 : }

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