OSAtomicChecker.cpp 7.2 KB

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