OSAtomicChecker.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. #include "ClangSACheckers.h"
  14. #include "clang/StaticAnalyzer/Core/Checker.h"
  15. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  16. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  17. #include "clang/Basic/Builtins.h"
  18. using namespace clang;
  19. using namespace ento;
  20. namespace {
  21. class OSAtomicChecker : public Checker<eval::Call> {
  22. public:
  23. bool evalCall(const CallExpr *CE, CheckerContext &C) const;
  24. private:
  25. static bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
  26. };
  27. }
  28. bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
  29. const GRState *state = C.getState();
  30. const Expr *Callee = CE->getCallee();
  31. SVal L = state->getSVal(Callee);
  32. const FunctionDecl* FD = L.getAsFunctionDecl();
  33. if (!FD)
  34. return false;
  35. const IdentifierInfo *II = FD->getIdentifier();
  36. if (!II)
  37. return false;
  38. StringRef FName(II->getName());
  39. // Check for compare and swap.
  40. if (FName.startswith("OSAtomicCompareAndSwap") ||
  41. FName.startswith("objc_atomicCompareAndSwap"))
  42. return evalOSAtomicCompareAndSwap(C, CE);
  43. // FIXME: Other atomics.
  44. return false;
  45. }
  46. bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
  47. const CallExpr *CE) {
  48. // Not enough arguments to match OSAtomicCompareAndSwap?
  49. if (CE->getNumArgs() != 3)
  50. return false;
  51. ASTContext &Ctx = C.getASTContext();
  52. const Expr *oldValueExpr = CE->getArg(0);
  53. QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
  54. const Expr *newValueExpr = CE->getArg(1);
  55. QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
  56. // Do the types of 'oldValue' and 'newValue' match?
  57. if (oldValueType != newValueType)
  58. return false;
  59. const Expr *theValueExpr = CE->getArg(2);
  60. const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
  61. // theValueType not a pointer?
  62. if (!theValueType)
  63. return false;
  64. QualType theValueTypePointee =
  65. Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
  66. // The pointee must match newValueType and oldValueType.
  67. if (theValueTypePointee != newValueType)
  68. return false;
  69. static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load");
  70. static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
  71. // Load 'theValue'.
  72. ExprEngine &Engine = C.getEngine();
  73. const GRState *state = C.getState();
  74. ExplodedNodeSet Tmp;
  75. SVal location = state->getSVal(theValueExpr);
  76. // Here we should use the value type of the region as the load type, because
  77. // we are simulating the semantics of the function, not the semantics of
  78. // passing argument. So the type of theValue expr is not we are loading.
  79. // But usually the type of the varregion is not the type we want either,
  80. // we still need to do a CastRetrievedVal in store manager. So actually this
  81. // LoadTy specifying can be omitted. But we put it here to emphasize the
  82. // semantics.
  83. QualType LoadTy;
  84. if (const TypedValueRegion *TR =
  85. dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
  86. LoadTy = TR->getValueType();
  87. }
  88. Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(),
  89. state, location, &OSAtomicLoadTag, LoadTy);
  90. if (Tmp.empty()) {
  91. // If no nodes were generated, other checkers must generated sinks. But
  92. // since the builder state was restored, we set it manually to prevent
  93. // auto transition.
  94. // FIXME: there should be a better approach.
  95. C.getNodeBuilder().BuildSinks = true;
  96. return true;
  97. }
  98. for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
  99. I != E; ++I) {
  100. ExplodedNode *N = *I;
  101. const GRState *stateLoad = N->getState();
  102. // Use direct bindings from the environment since we are forcing a load
  103. // from a location that the Environment would typically not be used
  104. // to bind a value.
  105. SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, true);
  106. SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
  107. // FIXME: Issue an error.
  108. if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
  109. return false;
  110. }
  111. DefinedOrUnknownSVal theValueVal =
  112. cast<DefinedOrUnknownSVal>(theValueVal_untested);
  113. DefinedOrUnknownSVal oldValueVal =
  114. cast<DefinedOrUnknownSVal>(oldValueVal_untested);
  115. SValBuilder &svalBuilder = Engine.getSValBuilder();
  116. // Perform the comparison.
  117. DefinedOrUnknownSVal Cmp =
  118. svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
  119. const GRState *stateEqual = stateLoad->assume(Cmp, true);
  120. // Were they equal?
  121. if (stateEqual) {
  122. // Perform the store.
  123. ExplodedNodeSet TmpStore;
  124. SVal val = stateEqual->getSVal(newValueExpr);
  125. // Handle implicit value casts.
  126. if (const TypedValueRegion *R =
  127. dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
  128. val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
  129. }
  130. Engine.evalStore(TmpStore, NULL, theValueExpr, N,
  131. stateEqual, location, val, &OSAtomicStoreTag);
  132. if (TmpStore.empty()) {
  133. // If no nodes were generated, other checkers must generated sinks. But
  134. // since the builder state was restored, we set it manually to prevent
  135. // auto transition.
  136. // FIXME: there should be a better approach.
  137. C.getNodeBuilder().BuildSinks = true;
  138. return true;
  139. }
  140. // Now bind the result of the comparison.
  141. for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
  142. E2 = TmpStore.end(); I2 != E2; ++I2) {
  143. ExplodedNode *predNew = *I2;
  144. const GRState *stateNew = predNew->getState();
  145. // Check for 'void' return type if we have a bogus function prototype.
  146. SVal Res = UnknownVal();
  147. QualType T = CE->getType();
  148. if (!T->isVoidType())
  149. Res = Engine.getSValBuilder().makeTruthVal(true, T);
  150. C.generateNode(stateNew->BindExpr(CE, Res), predNew);
  151. }
  152. }
  153. // Were they not equal?
  154. if (const GRState *stateNotEqual = stateLoad->assume(Cmp, false)) {
  155. // Check for 'void' return type if we have a bogus function prototype.
  156. SVal Res = UnknownVal();
  157. QualType T = CE->getType();
  158. if (!T->isVoidType())
  159. Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType());
  160. C.generateNode(stateNotEqual->BindExpr(CE, Res), N);
  161. }
  162. }
  163. return true;
  164. }
  165. void ento::registerOSAtomicChecker(CheckerManager &mgr) {
  166. mgr.registerChecker<OSAtomicChecker>();
  167. }