blob: 27d8fb5abbd1443a3c98c39621febd77cb575d19 [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
Anna Zaksb805c8f2011-12-01 05:57:37 +000038static StringRef getCalleeName(const ProgramState *State,
39 const CallExpr *CE) {
40 const Expr *Callee = CE->getCallee();
41 SVal L = State->getSVal(Callee);
42 const FunctionDecl *funDecl = L.getAsFunctionDecl();
43 if (!funDecl)
44 return StringRef();
45 IdentifierInfo *funI = funDecl->getIdentifier();
46 if (!funI)
47 return StringRef();
48 return funI->getName();
49}
50
Anna Zaksdff6ef92011-10-05 23:37:30 +000051bool OSAtomicChecker::inlineCall(const CallExpr *CE,
52 ExprEngine &Eng,
53 ExplodedNode *Pred,
54 ExplodedNodeSet &Dst) const {
Anna Zaksb805c8f2011-12-01 05:57:37 +000055 StringRef FName = getCalleeName(Pred->getState(), CE);
56 if (FName.empty())
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000057 return false;
58
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000059 // Check for compare and swap.
Ted Kremeneka0f77272009-12-16 06:03:24 +000060 if (FName.startswith("OSAtomicCompareAndSwap") ||
61 FName.startswith("objc_atomicCompareAndSwap"))
Anna Zaksdff6ef92011-10-05 23:37:30 +000062 return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000063
64 // FIXME: Other atomics.
65 return false;
66}
67
Anna Zaksdff6ef92011-10-05 23:37:30 +000068bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE,
69 ExprEngine &Eng,
70 ExplodedNode *Pred,
71 ExplodedNodeSet &Dst) const {
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000072 // Not enough arguments to match OSAtomicCompareAndSwap?
73 if (CE->getNumArgs() != 3)
74 return false;
75
Anna Zaksdff6ef92011-10-05 23:37:30 +000076 ASTContext &Ctx = Eng.getContext();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000077 const Expr *oldValueExpr = CE->getArg(0);
78 QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
79
80 const Expr *newValueExpr = CE->getArg(1);
81 QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
82
83 // Do the types of 'oldValue' and 'newValue' match?
84 if (oldValueType != newValueType)
85 return false;
86
87 const Expr *theValueExpr = CE->getArg(2);
88 const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
89
90 // theValueType not a pointer?
91 if (!theValueType)
92 return false;
93
94 QualType theValueTypePointee =
95 Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
96
97 // The pointee must match newValueType and oldValueType.
98 if (theValueTypePointee != newValueType)
99 return false;
100
Ted Kremenekca804532011-08-12 23:04:46 +0000101 static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load");
102 static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store");
103
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000104 // Load 'theValue'.
Anna Zaksdff6ef92011-10-05 23:37:30 +0000105 const ProgramState *state = Pred->getState();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000106 ExplodedNodeSet Tmp;
Ted Kremenek13976632010-02-08 16:18:51 +0000107 SVal location = state->getSVal(theValueExpr);
Zhongxing Xu71f219a2010-06-23 02:06:56 +0000108 // Here we should use the value type of the region as the load type, because
109 // we are simulating the semantics of the function, not the semantics of
Zhongxing Xu24704462010-06-23 02:12:00 +0000110 // passing argument. So the type of theValue expr is not we are loading.
111 // But usually the type of the varregion is not the type we want either,
112 // we still need to do a CastRetrievedVal in store manager. So actually this
113 // LoadTy specifying can be omitted. But we put it here to emphasize the
114 // semantics.
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000115 QualType LoadTy;
Ted Kremenek96979342011-08-12 20:02:48 +0000116 if (const TypedValueRegion *TR =
117 dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
Zhongxing Xu018220c2010-08-11 06:10:55 +0000118 LoadTy = TR->getValueType();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000119 }
Anna Zaksdff6ef92011-10-05 23:37:30 +0000120 Eng.evalLoad(Tmp, theValueExpr, Pred,
Ted Kremenekca804532011-08-12 23:04:46 +0000121 state, location, &OSAtomicLoadTag, LoadTy);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000122
123 if (Tmp.empty()) {
Anna Zaksf185cc12011-10-24 21:19:43 +0000124 // If no nodes were generated, other checkers must have generated sinks.
125 // We return an empty Dst.
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000126 return true;
127 }
128
129 for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
130 I != E; ++I) {
131
132 ExplodedNode *N = *I;
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000133 const ProgramState *stateLoad = N->getState();
Ted Kremenek6b4f5672011-04-27 05:34:09 +0000134
135 // Use direct bindings from the environment since we are forcing a load
136 // from a location that the Environment would typically not be used
137 // to bind a value.
138 SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, true);
139
Ted Kremenek13976632010-02-08 16:18:51 +0000140 SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000141
142 // FIXME: Issue an error.
143 if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
144 return false;
145 }
146
147 DefinedOrUnknownSVal theValueVal =
148 cast<DefinedOrUnknownSVal>(theValueVal_untested);
149 DefinedOrUnknownSVal oldValueVal =
150 cast<DefinedOrUnknownSVal>(oldValueVal_untested);
151
Anna Zaksdff6ef92011-10-05 23:37:30 +0000152 SValBuilder &svalBuilder = Eng.getSValBuilder();
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000153
154 // Perform the comparison.
Ted Kremenekca804532011-08-12 23:04:46 +0000155 DefinedOrUnknownSVal Cmp =
156 svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000157
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000158 const ProgramState *stateEqual = stateLoad->assume(Cmp, true);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000159
160 // Were they equal?
161 if (stateEqual) {
162 // Perform the store.
163 ExplodedNodeSet TmpStore;
Ted Kremenek13976632010-02-08 16:18:51 +0000164 SVal val = stateEqual->getSVal(newValueExpr);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000165
166 // Handle implicit value casts.
Ted Kremenek96979342011-08-12 20:02:48 +0000167 if (const TypedValueRegion *R =
168 dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) {
Ted Kremenek9c149532010-12-01 21:57:22 +0000169 val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000170 }
171
Anna Zaksdff6ef92011-10-05 23:37:30 +0000172 Eng.evalStore(TmpStore, NULL, theValueExpr, N,
Ted Kremenekca804532011-08-12 23:04:46 +0000173 stateEqual, location, val, &OSAtomicStoreTag);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000174
175 if (TmpStore.empty()) {
Anna Zaksf185cc12011-10-24 21:19:43 +0000176 // If no nodes were generated, other checkers must have generated sinks.
177 // We return an empty Dst.
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000178 return true;
179 }
Anna Zaksf185cc12011-10-24 21:19:43 +0000180
Anna Zaksaa0aeb12011-10-24 21:19:59 +0000181 StmtNodeBuilder B(TmpStore, Dst, Eng.getBuilderContext());
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000182 // Now bind the result of the comparison.
183 for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
184 E2 = TmpStore.end(); I2 != E2; ++I2) {
185 ExplodedNode *predNew = *I2;
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000186 const ProgramState *stateNew = predNew->getState();
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000187 // Check for 'void' return type if we have a bogus function prototype.
188 SVal Res = UnknownVal();
189 QualType T = CE->getType();
190 if (!T->isVoidType())
Anna Zaksdff6ef92011-10-05 23:37:30 +0000191 Res = Eng.getSValBuilder().makeTruthVal(true, T);
Anna Zaksf185cc12011-10-24 21:19:43 +0000192 B.generateNode(CE, predNew, stateNew->BindExpr(CE, Res), false, this);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000193 }
194 }
195
196 // Were they not equal?
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000197 if (const ProgramState *stateNotEqual = stateLoad->assume(Cmp, false)) {
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000198 // Check for 'void' return type if we have a bogus function prototype.
199 SVal Res = UnknownVal();
200 QualType T = CE->getType();
201 if (!T->isVoidType())
Anna Zaksdff6ef92011-10-05 23:37:30 +0000202 Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType());
Anna Zaksaa0aeb12011-10-24 21:19:59 +0000203 StmtNodeBuilder B(N, Dst, Eng.getBuilderContext());
Anna Zaksf185cc12011-10-24 21:19:43 +0000204 B.generateNode(CE, N, stateNotEqual->BindExpr(CE, Res), false, this);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000205 }
206 }
207
208 return true;
209}
Argyrios Kyrtzidisf0293662011-02-28 01:27:02 +0000210
211void ento::registerOSAtomicChecker(CheckerManager &mgr) {
212 mgr.registerChecker<OSAtomicChecker>();
213}