clang API Documentation

OSAtomicChecker.cpp
Go to the documentation of this file.
00001 //=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This checker evaluates OSAtomic functions.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "ClangSACheckers.h"
00015 #include "clang/StaticAnalyzer/Core/Checker.h"
00016 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
00017 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
00018 #include "clang/Basic/Builtins.h"
00019 
00020 using namespace clang;
00021 using namespace ento;
00022 
00023 namespace {
00024 
00025 class OSAtomicChecker : public Checker<eval::InlineCall> {
00026 public:
00027   bool inlineCall(const CallExpr *CE, ExprEngine &Eng,
00028                   ExplodedNode *Pred, ExplodedNodeSet &Dst) const;
00029 
00030 private:
00031   bool evalOSAtomicCompareAndSwap(const CallExpr *CE,
00032                                   ExprEngine &Eng,
00033                                   ExplodedNode *Pred,
00034                                   ExplodedNodeSet &Dst) const;
00035 };
00036 }
00037 
00038 static StringRef getCalleeName(ProgramStateRef State,
00039                                const CallExpr *CE,
00040                                const LocationContext *LCtx) {
00041   const Expr *Callee = CE->getCallee();
00042   SVal L = State->getSVal(Callee, LCtx);
00043   const FunctionDecl *funDecl =  L.getAsFunctionDecl();
00044   if (!funDecl)
00045     return StringRef();
00046   IdentifierInfo *funI = funDecl->getIdentifier();
00047   if (!funI)
00048     return StringRef();
00049   return funI->getName();
00050 }
00051 
00052 bool OSAtomicChecker::inlineCall(const CallExpr *CE,
00053                                  ExprEngine &Eng,
00054                                  ExplodedNode *Pred,
00055                                  ExplodedNodeSet &Dst) const {
00056   StringRef FName = getCalleeName(Pred->getState(),
00057                                   CE, Pred->getLocationContext());
00058   if (FName.empty())
00059     return false;
00060 
00061   // Check for compare and swap.
00062   if (FName.startswith("OSAtomicCompareAndSwap") ||
00063       FName.startswith("objc_atomicCompareAndSwap"))
00064     return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst);
00065 
00066   // FIXME: Other atomics.
00067   return false;
00068 }
00069 
00070 bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
00071                                                  ExprEngine &Eng,
00072                                                  ExplodedNode *Pred,
00073                                                  ExplodedNodeSet &Dst) const {
00074   // Not enough arguments to match OSAtomicCompareAndSwap?
00075   if (CE->getNumArgs() != 3)
00076     return false;
00077 
00078   ASTContext &Ctx = Eng.getContext();
00079   const Expr *oldValueExpr = CE->getArg(0);
00080   QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
00081 
00082   const Expr *newValueExpr = CE->getArg(1);
00083   QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
00084 
00085   // Do the types of 'oldValue' and 'newValue' match?
00086   if (oldValueType != newValueType)
00087     return false;
00088 
00089   const Expr *theValueExpr = CE->getArg(2);
00090   const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
00091 
00092   // theValueType not a pointer?
00093   if (!theValueType)
00094     return false;
00095 
00096   QualType theValueTypePointee =
00097     Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
00098 
00099   // The pointee must match newValueType and oldValueType.
00100   if (theValueTypePointee != newValueType)
00101     return false;
00102 
00103   static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load");
00104   static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
00105   
00106   // Load 'theValue'.
00107   ProgramStateRef state = Pred->getState();
00108   const LocationContext *LCtx = Pred->getLocationContext();
00109   ExplodedNodeSet Tmp;
00110   SVal location = state->getSVal(theValueExpr, LCtx);
00111   // Here we should use the value type of the region as the load type, because
00112   // we are simulating the semantics of the function, not the semantics of 
00113   // passing argument. So the type of theValue expr is not we are loading.
00114   // But usually the type of the varregion is not the type we want either,
00115   // we still need to do a CastRetrievedVal in store manager. So actually this
00116   // LoadTy specifying can be omitted. But we put it here to emphasize the 
00117   // semantics.
00118   QualType LoadTy;
00119   if (const TypedValueRegion *TR =
00120       dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
00121     LoadTy = TR->getValueType();
00122   }
00123   Eng.evalLoad(Tmp, CE, theValueExpr, Pred,
00124                state, location, &OSAtomicLoadTag, LoadTy);
00125 
00126   if (Tmp.empty()) {
00127     // If no nodes were generated, other checkers must have generated sinks. 
00128     // We return an empty Dst.
00129     return true;
00130   }
00131  
00132   for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
00133        I != E; ++I) {
00134 
00135     ExplodedNode *N = *I;
00136     ProgramStateRef stateLoad = N->getState();
00137 
00138     // Use direct bindings from the environment since we are forcing a load
00139     // from a location that the Environment would typically not be used
00140     // to bind a value.
00141     SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, LCtx, true);
00142 
00143     SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr, LCtx);
00144 
00145     // FIXME: Issue an error.
00146     if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
00147       return false;
00148     }
00149     
00150     DefinedOrUnknownSVal theValueVal =
00151       cast<DefinedOrUnknownSVal>(theValueVal_untested);
00152     DefinedOrUnknownSVal oldValueVal =
00153       cast<DefinedOrUnknownSVal>(oldValueVal_untested);
00154 
00155     SValBuilder &svalBuilder = Eng.getSValBuilder();
00156 
00157     // Perform the comparison.
00158     DefinedOrUnknownSVal Cmp =
00159       svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
00160 
00161     ProgramStateRef stateEqual = stateLoad->assume(Cmp, true);
00162 
00163     // Were they equal?
00164     if (stateEqual) {
00165       // Perform the store.
00166       ExplodedNodeSet TmpStore;
00167       SVal val = stateEqual->getSVal(newValueExpr, LCtx);
00168 
00169       // Handle implicit value casts.
00170       if (const TypedValueRegion *R =
00171           dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
00172         val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
00173       }
00174 
00175       Eng.evalStore(TmpStore, CE, theValueExpr, N,
00176                     stateEqual, location, val, &OSAtomicStoreTag);
00177 
00178       if (TmpStore.empty()) {
00179         // If no nodes were generated, other checkers must have generated sinks. 
00180         // We return an empty Dst.
00181         return true;
00182       }
00183       
00184       StmtNodeBuilder B(TmpStore, Dst, Eng.getBuilderContext());
00185       // Now bind the result of the comparison.
00186       for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
00187            E2 = TmpStore.end(); I2 != E2; ++I2) {
00188         ExplodedNode *predNew = *I2;
00189         ProgramStateRef stateNew = predNew->getState();
00190         // Check for 'void' return type if we have a bogus function prototype.
00191         SVal Res = UnknownVal();
00192         QualType T = CE->getType();
00193         if (!T->isVoidType())
00194           Res = Eng.getSValBuilder().makeTruthVal(true, T);
00195         B.generateNode(CE, predNew, stateNew->BindExpr(CE, LCtx, Res),
00196                        false, this);
00197       }
00198     }
00199 
00200     // Were they not equal?
00201     if (ProgramStateRef stateNotEqual = stateLoad->assume(Cmp, false)) {
00202       // Check for 'void' return type if we have a bogus function prototype.
00203       SVal Res = UnknownVal();
00204       QualType T = CE->getType();
00205       if (!T->isVoidType())
00206         Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType());
00207       StmtNodeBuilder B(N, Dst, Eng.getBuilderContext());    
00208       B.generateNode(CE, N, stateNotEqual->BindExpr(CE, LCtx, Res),
00209                      false, this);
00210     }
00211   }
00212 
00213   return true;
00214 }
00215 
00216 void ento::registerOSAtomicChecker(CheckerManager &mgr) {
00217   mgr.registerChecker<OSAtomicChecker>();
00218 }