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