blob: dc806c5463f8599520a00556f0dab4a25021cb98 [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 Kyrtzidisf0293662011-02-28 01:27:02 +000014#include "ClangSACheckers.h"
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000015#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidisf0293662011-02-28 01:27:02 +000016#include "clang/StaticAnalyzer/Core/CheckerManager.h"
17#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000018#include "clang/Basic/Builtins.h"
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000019
20using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000021using namespace ento;
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000022
23namespace {
24
Anna Zaksdff6ef92011-10-05 23:37:30 +000025class OSAtomicChecker : public Checker<eval::InlineCall> {
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000026public:
Anna Zaksdff6ef92011-10-05 23:37:30 +000027 bool inlineCall(const CallExpr *CE, ExprEngine &Eng,
28 ExplodedNode *Pred, ExplodedNodeSet &Dst) const;
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000029
30private:
Anna Zaksdff6ef92011-10-05 23:37:30 +000031 bool evalOSAtomicCompareAndSwap(const CallExpr *CE,
32 ExprEngine &Eng,
33 ExplodedNode *Pred,
34 ExplodedNodeSet &Dst) const;
Anna Zaksdff6ef92011-10-05 23:37:30 +000035};
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000036}
37
Ted Kremenek8bef8232012-01-26 21:29:00 +000038static StringRef getCalleeName(ProgramStateRef State,
Ted Kremenek5eca4822012-01-06 22:09:28 +000039 const CallExpr *CE,
40 const LocationContext *LCtx) {
Anna Zaksb805c8f2011-12-01 05:57:37 +000041 const Expr *Callee = CE->getCallee();
Ted Kremenek5eca4822012-01-06 22:09:28 +000042 SVal L = State->getSVal(Callee, LCtx);
Anna Zaksb805c8f2011-12-01 05:57:37 +000043 const FunctionDecl *funDecl = L.getAsFunctionDecl();
44 if (!funDecl)
45 return StringRef();
46 IdentifierInfo *funI = funDecl->getIdentifier();
47 if (!funI)
48 return StringRef();
49 return funI->getName();
50}
51
Anna Zaksdff6ef92011-10-05 23:37:30 +000052bool OSAtomicChecker::inlineCall(const CallExpr *CE,
53 ExprEngine &Eng,
54 ExplodedNode *Pred,
55 ExplodedNodeSet &Dst) const {
Ted Kremenek5eca4822012-01-06 22:09:28 +000056 StringRef FName = getCalleeName(Pred->getState(),
57 CE, Pred->getLocationContext());
Anna Zaksb805c8f2011-12-01 05:57:37 +000058 if (FName.empty())
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000059 return false;
60
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000061 // Check for compare and swap.
Ted Kremeneka0f77272009-12-16 06:03:24 +000062 if (FName.startswith("OSAtomicCompareAndSwap") ||
63 FName.startswith("objc_atomicCompareAndSwap"))
Anna Zaksdff6ef92011-10-05 23:37:30 +000064 return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000065
66 // FIXME: Other atomics.
67 return false;
68}
69
Anna Zaksdff6ef92011-10-05 23:37:30 +000070bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
71 ExprEngine &Eng,
72 ExplodedNode *Pred,
73 ExplodedNodeSet &Dst) const {
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000074 // Not enough arguments to match OSAtomicCompareAndSwap?
75 if (CE->getNumArgs() != 3)
76 return false;
77
Anna Zaksdff6ef92011-10-05 23:37:30 +000078 ASTContext &Ctx = Eng.getContext();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000079 const Expr *oldValueExpr = CE->getArg(0);
80 QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
81
82 const Expr *newValueExpr = CE->getArg(1);
83 QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
84
85 // Do the types of 'oldValue' and 'newValue' match?
86 if (oldValueType != newValueType)
87 return false;
88
89 const Expr *theValueExpr = CE->getArg(2);
90 const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
91
92 // theValueType not a pointer?
93 if (!theValueType)
94 return false;
95
96 QualType theValueTypePointee =
97 Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
98
99 // The pointee must match newValueType and oldValueType.
100 if (theValueTypePointee != newValueType)
101 return false;
102
Ted Kremenekca804532011-08-12 23:04:46 +0000103 static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load");
104 static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
105
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000106 // Load 'theValue'.
Ted Kremenek8bef8232012-01-26 21:29:00 +0000107 ProgramStateRef state = Pred->getState();
Ted Kremenek5eca4822012-01-06 22:09:28 +0000108 const LocationContext *LCtx = Pred->getLocationContext();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000109 ExplodedNodeSet Tmp;
Ted Kremenek5eca4822012-01-06 22:09:28 +0000110 SVal location = state->getSVal(theValueExpr, LCtx);
Zhongxing Xu71f219a2010-06-23 02:06:56 +0000111 // Here we should use the value type of the region as the load type, because
112 // we are simulating the semantics of the function, not the semantics of
Zhongxing Xu24704462010-06-23 02:12:00 +0000113 // passing argument. So the type of theValue expr is not we are loading.
114 // But usually the type of the varregion is not the type we want either,
115 // we still need to do a CastRetrievedVal in store manager. So actually this
116 // LoadTy specifying can be omitted. But we put it here to emphasize the
117 // semantics.
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000118 QualType LoadTy;
Ted Kremenek96979342011-08-12 20:02:48 +0000119 if (const TypedValueRegion *TR =
120 dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
Zhongxing Xu018220c2010-08-11 06:10:55 +0000121 LoadTy = TR->getValueType();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000122 }
Anna Zaksdff6ef92011-10-05 23:37:30 +0000123 Eng.evalLoad(Tmp, theValueExpr, Pred,
Ted Kremenekca804532011-08-12 23:04:46 +0000124 state, location, &OSAtomicLoadTag, LoadTy);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000125
126 if (Tmp.empty()) {
Anna Zaksf185cc12011-10-24 21:19:43 +0000127 // If no nodes were generated, other checkers must have generated sinks.
128 // We return an empty Dst.
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000129 return true;
130 }
131
132 for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
133 I != E; ++I) {
134
135 ExplodedNode *N = *I;
Ted Kremenek8bef8232012-01-26 21:29:00 +0000136 ProgramStateRef stateLoad = N->getState();
Ted Kremenek6b4f5672011-04-27 05:34:09 +0000137
138 // Use direct bindings from the environment since we are forcing a load
139 // from a location that the Environment would typically not be used
140 // to bind a value.
Ted Kremenek5eca4822012-01-06 22:09:28 +0000141 SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, LCtx, true);
Ted Kremenek6b4f5672011-04-27 05:34:09 +0000142
Ted Kremenek5eca4822012-01-06 22:09:28 +0000143 SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr, LCtx);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000144
145 // FIXME: Issue an error.
146 if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
147 return false;
148 }
149
150 DefinedOrUnknownSVal theValueVal =
151 cast<DefinedOrUnknownSVal>(theValueVal_untested);
152 DefinedOrUnknownSVal oldValueVal =
153 cast<DefinedOrUnknownSVal>(oldValueVal_untested);
154
Anna Zaksdff6ef92011-10-05 23:37:30 +0000155 SValBuilder &svalBuilder = Eng.getSValBuilder();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000156
157 // Perform the comparison.
Ted Kremenekca804532011-08-12 23:04:46 +0000158 DefinedOrUnknownSVal Cmp =
159 svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000160
Ted Kremenek8bef8232012-01-26 21:29:00 +0000161 ProgramStateRef stateEqual = stateLoad->assume(Cmp, true);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000162
163 // Were they equal?
164 if (stateEqual) {
165 // Perform the store.
166 ExplodedNodeSet TmpStore;
Ted Kremenek5eca4822012-01-06 22:09:28 +0000167 SVal val = stateEqual->getSVal(newValueExpr, LCtx);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000168
169 // Handle implicit value casts.
Ted Kremenek96979342011-08-12 20:02:48 +0000170 if (const TypedValueRegion *R =
171 dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
Ted Kremenek9c149532010-12-01 21:57:22 +0000172 val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000173 }
174
Anna Zaksdff6ef92011-10-05 23:37:30 +0000175 Eng.evalStore(TmpStore, NULL, theValueExpr, N,
Ted Kremenekca804532011-08-12 23:04:46 +0000176 stateEqual, location, val, &OSAtomicStoreTag);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000177
178 if (TmpStore.empty()) {
Anna Zaksf185cc12011-10-24 21:19:43 +0000179 // If no nodes were generated, other checkers must have generated sinks.
180 // We return an empty Dst.
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000181 return true;
182 }
Anna Zaksf185cc12011-10-24 21:19:43 +0000183
Anna Zaksaa0aeb12011-10-24 21:19:59 +0000184 StmtNodeBuilder B(TmpStore, Dst, Eng.getBuilderContext());
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000185 // Now bind the result of the comparison.
186 for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
187 E2 = TmpStore.end(); I2 != E2; ++I2) {
188 ExplodedNode *predNew = *I2;
Ted Kremenek8bef8232012-01-26 21:29:00 +0000189 ProgramStateRef stateNew = predNew->getState();
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000190 // Check for 'void' return type if we have a bogus function prototype.
191 SVal Res = UnknownVal();
192 QualType T = CE->getType();
193 if (!T->isVoidType())
Anna Zaksdff6ef92011-10-05 23:37:30 +0000194 Res = Eng.getSValBuilder().makeTruthVal(true, T);
Ted Kremenek5eca4822012-01-06 22:09:28 +0000195 B.generateNode(CE, predNew, stateNew->BindExpr(CE, LCtx, Res),
196 false, this);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000197 }
198 }
199
200 // Were they not equal?
Ted Kremenek8bef8232012-01-26 21:29:00 +0000201 if (ProgramStateRef stateNotEqual = stateLoad->assume(Cmp, false)) {
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000202 // Check for 'void' return type if we have a bogus function prototype.
203 SVal Res = UnknownVal();
204 QualType T = CE->getType();
205 if (!T->isVoidType())
Anna Zaksdff6ef92011-10-05 23:37:30 +0000206 Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType());
Anna Zaksaa0aeb12011-10-24 21:19:59 +0000207 StmtNodeBuilder B(N, Dst, Eng.getBuilderContext());
Ted Kremenek5eca4822012-01-06 22:09:28 +0000208 B.generateNode(CE, N, stateNotEqual->BindExpr(CE, LCtx, Res),
209 false, this);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000210 }
211 }
212
213 return true;
214}
Argyrios Kyrtzidisf0293662011-02-28 01:27:02 +0000215
216void ento::registerOSAtomicChecker(CheckerManager &mgr) {
217 mgr.registerChecker<OSAtomicChecker>();
218}