[analyzer] Refactoring: include/clang/Checker -> include/clang/GR
[clang.git] / lib / Checker / OSAtomicChecker.cpp
blob36b5335d88ab80a259c83f262dfdc0f48067e724
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.
12 //===----------------------------------------------------------------------===//
14 #include "GRExprEngineInternalChecks.h"
15 #include "clang/GR/PathSensitive/Checker.h"
16 #include "clang/Basic/Builtins.h"
18 using namespace clang;
20 namespace {
22 class OSAtomicChecker : public Checker {
23 public:
24 static void *getTag() { static int tag = 0; return &tag; }
25 virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
27 private:
28 bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
33 void clang::RegisterOSAtomicChecker(GRExprEngine &Eng) {
34 Eng.registerCheck(new OSAtomicChecker());
37 bool OSAtomicChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE) {
38 const GRState *state = C.getState();
39 const Expr *Callee = CE->getCallee();
40 SVal L = state->getSVal(Callee);
42 const FunctionDecl* FD = L.getAsFunctionDecl();
43 if (!FD)
44 return false;
46 const IdentifierInfo *II = FD->getIdentifier();
47 if (!II)
48 return false;
50 llvm::StringRef FName(II->getName());
52 // Check for compare and swap.
53 if (FName.startswith("OSAtomicCompareAndSwap") ||
54 FName.startswith("objc_atomicCompareAndSwap"))
55 return evalOSAtomicCompareAndSwap(C, CE);
57 // FIXME: Other atomics.
58 return false;
61 bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
62 const CallExpr *CE) {
63 // Not enough arguments to match OSAtomicCompareAndSwap?
64 if (CE->getNumArgs() != 3)
65 return false;
67 ASTContext &Ctx = C.getASTContext();
68 const Expr *oldValueExpr = CE->getArg(0);
69 QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
71 const Expr *newValueExpr = CE->getArg(1);
72 QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
74 // Do the types of 'oldValue' and 'newValue' match?
75 if (oldValueType != newValueType)
76 return false;
78 const Expr *theValueExpr = CE->getArg(2);
79 const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
81 // theValueType not a pointer?
82 if (!theValueType)
83 return false;
85 QualType theValueTypePointee =
86 Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
88 // The pointee must match newValueType and oldValueType.
89 if (theValueTypePointee != newValueType)
90 return false;
92 static unsigned magic_load = 0;
93 static unsigned magic_store = 0;
95 const void *OSAtomicLoadTag = &magic_load;
96 const void *OSAtomicStoreTag = &magic_store;
98 // Load 'theValue'.
99 GRExprEngine &Engine = C.getEngine();
100 const GRState *state = C.getState();
101 ExplodedNodeSet Tmp;
102 SVal location = state->getSVal(theValueExpr);
103 // Here we should use the value type of the region as the load type, because
104 // we are simulating the semantics of the function, not the semantics of
105 // passing argument. So the type of theValue expr is not we are loading.
106 // But usually the type of the varregion is not the type we want either,
107 // we still need to do a CastRetrievedVal in store manager. So actually this
108 // LoadTy specifying can be omitted. But we put it here to emphasize the
109 // semantics.
110 QualType LoadTy;
111 if (const TypedRegion *TR =
112 dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
113 LoadTy = TR->getValueType();
115 Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(),
116 state, location, OSAtomicLoadTag, LoadTy);
118 if (Tmp.empty()) {
119 // If no nodes were generated, other checkers must generated sinks. But
120 // since the builder state was restored, we set it manually to prevent
121 // auto transition.
122 // FIXME: there should be a better approach.
123 C.getNodeBuilder().BuildSinks = true;
124 return true;
127 for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
128 I != E; ++I) {
130 ExplodedNode *N = *I;
131 const GRState *stateLoad = N->getState();
132 SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
133 SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
135 // FIXME: Issue an error.
136 if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
137 return false;
140 DefinedOrUnknownSVal theValueVal =
141 cast<DefinedOrUnknownSVal>(theValueVal_untested);
142 DefinedOrUnknownSVal oldValueVal =
143 cast<DefinedOrUnknownSVal>(oldValueVal_untested);
145 SValBuilder &svalBuilder = Engine.getSValBuilder();
147 // Perform the comparison.
148 DefinedOrUnknownSVal Cmp = svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
150 const GRState *stateEqual = stateLoad->assume(Cmp, true);
152 // Were they equal?
153 if (stateEqual) {
154 // Perform the store.
155 ExplodedNodeSet TmpStore;
156 SVal val = stateEqual->getSVal(newValueExpr);
158 // Handle implicit value casts.
159 if (const TypedRegion *R =
160 dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
161 val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
164 Engine.evalStore(TmpStore, NULL, theValueExpr, N,
165 stateEqual, location, val, OSAtomicStoreTag);
167 if (TmpStore.empty()) {
168 // If no nodes were generated, other checkers must generated sinks. But
169 // since the builder state was restored, we set it manually to prevent
170 // auto transition.
171 // FIXME: there should be a better approach.
172 C.getNodeBuilder().BuildSinks = true;
173 return true;
176 // Now bind the result of the comparison.
177 for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
178 E2 = TmpStore.end(); I2 != E2; ++I2) {
179 ExplodedNode *predNew = *I2;
180 const GRState *stateNew = predNew->getState();
181 // Check for 'void' return type if we have a bogus function prototype.
182 SVal Res = UnknownVal();
183 QualType T = CE->getType();
184 if (!T->isVoidType())
185 Res = Engine.getSValBuilder().makeTruthVal(true, T);
186 C.generateNode(stateNew->BindExpr(CE, Res), predNew);
190 // Were they not equal?
191 if (const GRState *stateNotEqual = stateLoad->assume(Cmp, false)) {
192 // Check for 'void' return type if we have a bogus function prototype.
193 SVal Res = UnknownVal();
194 QualType T = CE->getType();
195 if (!T->isVoidType())
196 Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType());
197 C.generateNode(stateNotEqual->BindExpr(CE, Res), N);
201 return true;