blob: 3d230ce76e7f6d93c617c2da138415610c5a9428 [file] [log] [blame]
Zhongxing Xu1ec4e972009-12-09 12:23:28 +00001//=== 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
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000014#include "ExprEngineInternalChecks.h"
Argyrios Kyrtzidis98cabba2010-12-22 18:51:49 +000015#include "clang/GR/PathSensitive/Checker.h"
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000016#include "clang/Basic/Builtins.h"
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000017
18using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000019using namespace ento;
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000020
21namespace {
22
23class OSAtomicChecker : public Checker {
24public:
25 static void *getTag() { static int tag = 0; return &tag; }
Ted Kremenek9c149532010-12-01 21:57:22 +000026 virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000027
28private:
Ted Kremenek9c149532010-12-01 21:57:22 +000029 bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000030};
31
32}
33
Ted Kremenek9ef65372010-12-23 07:20:52 +000034void ento::RegisterOSAtomicChecker(ExprEngine &Eng) {
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000035 Eng.registerCheck(new OSAtomicChecker());
36}
37
Ted Kremenek9c149532010-12-01 21:57:22 +000038bool OSAtomicChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE) {
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000039 const GRState *state = C.getState();
40 const Expr *Callee = CE->getCallee();
Ted Kremenek13976632010-02-08 16:18:51 +000041 SVal L = state->getSVal(Callee);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000042
43 const FunctionDecl* FD = L.getAsFunctionDecl();
44 if (!FD)
45 return false;
46
Ted Kremeneka0f77272009-12-16 06:03:24 +000047 const IdentifierInfo *II = FD->getIdentifier();
48 if (!II)
49 return false;
50
51 llvm::StringRef FName(II->getName());
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000052
53 // Check for compare and swap.
Ted Kremeneka0f77272009-12-16 06:03:24 +000054 if (FName.startswith("OSAtomicCompareAndSwap") ||
55 FName.startswith("objc_atomicCompareAndSwap"))
Ted Kremenek9c149532010-12-01 21:57:22 +000056 return evalOSAtomicCompareAndSwap(C, CE);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000057
58 // FIXME: Other atomics.
59 return false;
60}
61
Ted Kremenek9c149532010-12-01 21:57:22 +000062bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000063 const CallExpr *CE) {
64 // Not enough arguments to match OSAtomicCompareAndSwap?
65 if (CE->getNumArgs() != 3)
66 return false;
67
68 ASTContext &Ctx = C.getASTContext();
69 const Expr *oldValueExpr = CE->getArg(0);
70 QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
71
72 const Expr *newValueExpr = CE->getArg(1);
73 QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
74
75 // Do the types of 'oldValue' and 'newValue' match?
76 if (oldValueType != newValueType)
77 return false;
78
79 const Expr *theValueExpr = CE->getArg(2);
80 const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
81
82 // theValueType not a pointer?
83 if (!theValueType)
84 return false;
85
86 QualType theValueTypePointee =
87 Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
88
89 // The pointee must match newValueType and oldValueType.
90 if (theValueTypePointee != newValueType)
91 return false;
92
93 static unsigned magic_load = 0;
94 static unsigned magic_store = 0;
95
96 const void *OSAtomicLoadTag = &magic_load;
97 const void *OSAtomicStoreTag = &magic_store;
98
99 // Load 'theValue'.
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +0000100 ExprEngine &Engine = C.getEngine();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000101 const GRState *state = C.getState();
102 ExplodedNodeSet Tmp;
Ted Kremenek13976632010-02-08 16:18:51 +0000103 SVal location = state->getSVal(theValueExpr);
Zhongxing Xu71f219a2010-06-23 02:06:56 +0000104 // Here we should use the value type of the region as the load type, because
105 // we are simulating the semantics of the function, not the semantics of
Zhongxing Xu24704462010-06-23 02:12:00 +0000106 // passing argument. So the type of theValue expr is not we are loading.
107 // But usually the type of the varregion is not the type we want either,
108 // we still need to do a CastRetrievedVal in store manager. So actually this
109 // LoadTy specifying can be omitted. But we put it here to emphasize the
110 // semantics.
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000111 QualType LoadTy;
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000112 if (const TypedRegion *TR =
113 dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
Zhongxing Xu018220c2010-08-11 06:10:55 +0000114 LoadTy = TR->getValueType();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000115 }
Ted Kremenek9c149532010-12-01 21:57:22 +0000116 Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(),
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000117 state, location, OSAtomicLoadTag, LoadTy);
118
119 if (Tmp.empty()) {
120 // If no nodes were generated, other checkers must generated sinks. But
121 // since the builder state was restored, we set it manually to prevent
122 // auto transition.
123 // FIXME: there should be a better approach.
124 C.getNodeBuilder().BuildSinks = true;
125 return true;
126 }
127
128 for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
129 I != E; ++I) {
130
131 ExplodedNode *N = *I;
132 const GRState *stateLoad = N->getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000133 SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
134 SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000135
136 // FIXME: Issue an error.
137 if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
138 return false;
139 }
140
141 DefinedOrUnknownSVal theValueVal =
142 cast<DefinedOrUnknownSVal>(theValueVal_untested);
143 DefinedOrUnknownSVal oldValueVal =
144 cast<DefinedOrUnknownSVal>(oldValueVal_untested);
145
Ted Kremenek846eabd2010-12-01 21:28:31 +0000146 SValBuilder &svalBuilder = Engine.getSValBuilder();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000147
148 // Perform the comparison.
Ted Kremenek9c149532010-12-01 21:57:22 +0000149 DefinedOrUnknownSVal Cmp = svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000150
Ted Kremenek28f47b92010-12-01 22:16:56 +0000151 const GRState *stateEqual = stateLoad->assume(Cmp, true);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000152
153 // Were they equal?
154 if (stateEqual) {
155 // Perform the store.
156 ExplodedNodeSet TmpStore;
Ted Kremenek13976632010-02-08 16:18:51 +0000157 SVal val = stateEqual->getSVal(newValueExpr);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000158
159 // Handle implicit value casts.
160 if (const TypedRegion *R =
161 dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
Ted Kremenek9c149532010-12-01 21:57:22 +0000162 val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000163 }
164
Ted Kremenek9c149532010-12-01 21:57:22 +0000165 Engine.evalStore(TmpStore, NULL, theValueExpr, N,
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000166 stateEqual, location, val, OSAtomicStoreTag);
167
168 if (TmpStore.empty()) {
169 // If no nodes were generated, other checkers must generated sinks. But
170 // since the builder state was restored, we set it manually to prevent
171 // auto transition.
172 // FIXME: there should be a better approach.
173 C.getNodeBuilder().BuildSinks = true;
174 return true;
175 }
176
177 // Now bind the result of the comparison.
178 for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
179 E2 = TmpStore.end(); I2 != E2; ++I2) {
180 ExplodedNode *predNew = *I2;
181 const GRState *stateNew = predNew->getState();
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000182 // Check for 'void' return type if we have a bogus function prototype.
183 SVal Res = UnknownVal();
184 QualType T = CE->getType();
185 if (!T->isVoidType())
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000186 Res = Engine.getSValBuilder().makeTruthVal(true, T);
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000187 C.generateNode(stateNew->BindExpr(CE, Res), predNew);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000188 }
189 }
190
191 // Were they not equal?
Ted Kremenek28f47b92010-12-01 22:16:56 +0000192 if (const GRState *stateNotEqual = stateLoad->assume(Cmp, false)) {
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000193 // Check for 'void' return type if we have a bogus function prototype.
194 SVal Res = UnknownVal();
195 QualType T = CE->getType();
196 if (!T->isVoidType())
Ted Kremenekc8413fd2010-12-02 07:49:45 +0000197 Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType());
Ted Kremenekd048c6e2010-12-20 21:19:09 +0000198 C.generateNode(stateNotEqual->BindExpr(CE, Res), N);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000199 }
200 }
201
202 return true;
203}