blob: e743528e23997874a15724a7c1fc3308d68781c9 [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
14#include "GRExprEngineInternalChecks.h"
Ted Kremenek1309f9a2010-01-25 04:41:41 +000015#include "clang/Checker/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;
19
20namespace {
21
22class OSAtomicChecker : public Checker {
23public:
24 static void *getTag() { static int tag = 0; return &tag; }
25 virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
26
27private:
28 bool EvalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
29};
30
31}
32
33void clang::RegisterOSAtomicChecker(GRExprEngine &Eng) {
34 Eng.registerCheck(new OSAtomicChecker());
35}
36
37bool OSAtomicChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE) {
38 const GRState *state = C.getState();
39 const Expr *Callee = CE->getCallee();
Ted Kremenek13976632010-02-08 16:18:51 +000040 SVal L = state->getSVal(Callee);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000041
42 const FunctionDecl* FD = L.getAsFunctionDecl();
43 if (!FD)
44 return false;
45
Ted Kremeneka0f77272009-12-16 06:03:24 +000046 const IdentifierInfo *II = FD->getIdentifier();
47 if (!II)
48 return false;
49
50 llvm::StringRef FName(II->getName());
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000051
52 // Check for compare and swap.
Ted Kremeneka0f77272009-12-16 06:03:24 +000053 if (FName.startswith("OSAtomicCompareAndSwap") ||
54 FName.startswith("objc_atomicCompareAndSwap"))
Zhongxing Xu1ec4e972009-12-09 12:23:28 +000055 return EvalOSAtomicCompareAndSwap(C, CE);
56
57 // FIXME: Other atomics.
58 return false;
59}
60
61bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
62 const CallExpr *CE) {
63 // Not enough arguments to match OSAtomicCompareAndSwap?
64 if (CE->getNumArgs() != 3)
65 return false;
66
67 ASTContext &Ctx = C.getASTContext();
68 const Expr *oldValueExpr = CE->getArg(0);
69 QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
70
71 const Expr *newValueExpr = CE->getArg(1);
72 QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
73
74 // Do the types of 'oldValue' and 'newValue' match?
75 if (oldValueType != newValueType)
76 return false;
77
78 const Expr *theValueExpr = CE->getArg(2);
79 const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
80
81 // theValueType not a pointer?
82 if (!theValueType)
83 return false;
84
85 QualType theValueTypePointee =
86 Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
87
88 // The pointee must match newValueType and oldValueType.
89 if (theValueTypePointee != newValueType)
90 return false;
91
92 static unsigned magic_load = 0;
93 static unsigned magic_store = 0;
94
95 const void *OSAtomicLoadTag = &magic_load;
96 const void *OSAtomicStoreTag = &magic_store;
97
98 // Load 'theValue'.
99 GRExprEngine &Engine = C.getEngine();
100 const GRState *state = C.getState();
101 ExplodedNodeSet Tmp;
Ted Kremenek13976632010-02-08 16:18:51 +0000102 SVal location = state->getSVal(theValueExpr);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000103 // Here we should use the value type of the region as the load type.
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000104 QualType LoadTy;
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000105 if (const TypedRegion *TR =
106 dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
107 LoadTy = TR->getValueType(Ctx);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000108 }
109 Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(),
110 state, location, OSAtomicLoadTag, LoadTy);
111
112 if (Tmp.empty()) {
113 // If no nodes were generated, other checkers must generated sinks. But
114 // since the builder state was restored, we set it manually to prevent
115 // auto transition.
116 // FIXME: there should be a better approach.
117 C.getNodeBuilder().BuildSinks = true;
118 return true;
119 }
120
121 for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
122 I != E; ++I) {
123
124 ExplodedNode *N = *I;
125 const GRState *stateLoad = N->getState();
Ted Kremenek13976632010-02-08 16:18:51 +0000126 SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
127 SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000128
129 // FIXME: Issue an error.
130 if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
131 return false;
132 }
133
134 DefinedOrUnknownSVal theValueVal =
135 cast<DefinedOrUnknownSVal>(theValueVal_untested);
136 DefinedOrUnknownSVal oldValueVal =
137 cast<DefinedOrUnknownSVal>(oldValueVal_untested);
138
139 SValuator &SVator = Engine.getSValuator();
140
141 // Perform the comparison.
142 DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad,theValueVal,oldValueVal);
143
144 const GRState *stateEqual = stateLoad->Assume(Cmp, true);
145
146 // Were they equal?
147 if (stateEqual) {
148 // Perform the store.
149 ExplodedNodeSet TmpStore;
Ted Kremenek13976632010-02-08 16:18:51 +0000150 SVal val = stateEqual->getSVal(newValueExpr);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000151
152 // Handle implicit value casts.
153 if (const TypedRegion *R =
154 dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
Zhongxing Xu814e6b92010-02-04 04:56:43 +0000155 val = SVator.EvalCast(val,R->getValueType(Ctx),newValueExpr->getType());
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000156 }
157
158 Engine.EvalStore(TmpStore, NULL, const_cast<Expr *>(theValueExpr), N,
159 stateEqual, location, val, OSAtomicStoreTag);
160
161 if (TmpStore.empty()) {
162 // If no nodes were generated, other checkers must generated sinks. But
163 // since the builder state was restored, we set it manually to prevent
164 // auto transition.
165 // FIXME: there should be a better approach.
166 C.getNodeBuilder().BuildSinks = true;
167 return true;
168 }
169
170 // Now bind the result of the comparison.
171 for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
172 E2 = TmpStore.end(); I2 != E2; ++I2) {
173 ExplodedNode *predNew = *I2;
174 const GRState *stateNew = predNew->getState();
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000175 // Check for 'void' return type if we have a bogus function prototype.
176 SVal Res = UnknownVal();
177 QualType T = CE->getType();
178 if (!T->isVoidType())
179 Res = Engine.getValueManager().makeTruthVal(true, T);
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000180 C.GenerateNode(stateNew->BindExpr(CE, Res), predNew);
181 }
182 }
183
184 // Were they not equal?
185 if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
Ted Kremenekc50e6df2010-01-11 02:33:26 +0000186 // Check for 'void' return type if we have a bogus function prototype.
187 SVal Res = UnknownVal();
188 QualType T = CE->getType();
189 if (!T->isVoidType())
190 Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
Zhongxing Xu1ec4e972009-12-09 12:23:28 +0000191 C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N);
192 }
193 }
194
195 return true;
196}