1 //===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines the C++ expression evaluation engine.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
15 #include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
16 #include "clang/AST/DeclCXX.h"
18 using namespace clang
;
22 class CallExprWLItem
{
24 CallExpr::const_arg_iterator I
;
27 CallExprWLItem(const CallExpr::const_arg_iterator
&i
, ExplodedNode
*n
)
32 void ExprEngine::evalArguments(ConstExprIterator AI
, ConstExprIterator AE
,
33 const FunctionProtoType
*FnType
,
34 ExplodedNode
*Pred
, ExplodedNodeSet
&Dst
,
35 bool FstArgAsLValue
) {
38 llvm::SmallVector
<CallExprWLItem
, 20> WorkList
;
39 WorkList
.reserve(AE
- AI
);
40 WorkList
.push_back(CallExprWLItem(AI
, Pred
));
42 while (!WorkList
.empty()) {
43 CallExprWLItem Item
= WorkList
.back();
51 // Evaluate the argument.
53 bool VisitAsLvalue
= FstArgAsLValue
;
55 FstArgAsLValue
= false;
57 const unsigned ParamIdx
= Item
.I
- AI
;
58 VisitAsLvalue
= FnType
&& ParamIdx
< FnType
->getNumArgs()
59 ? FnType
->getArgType(ParamIdx
)->isReferenceType()
63 Visit(*Item
.I
, Item
.N
, Tmp
);
65 for (ExplodedNodeSet::iterator NI
=Tmp
.begin(), NE
=Tmp
.end(); NI
!= NE
; ++NI
)
66 WorkList
.push_back(CallExprWLItem(Item
.I
, *NI
));
70 const CXXThisRegion
*ExprEngine::getCXXThisRegion(const CXXRecordDecl
*D
,
71 const StackFrameContext
*SFC
) {
72 Type
*T
= D
->getTypeForDecl();
73 QualType PT
= getContext().getPointerType(QualType(T
, 0));
74 return svalBuilder
.getRegionManager().getCXXThisRegion(PT
, SFC
);
77 const CXXThisRegion
*ExprEngine::getCXXThisRegion(const CXXMethodDecl
*decl
,
78 const StackFrameContext
*frameCtx
) {
79 return svalBuilder
.getRegionManager().
80 getCXXThisRegion(decl
->getThisType(getContext()), frameCtx
);
83 void ExprEngine::CreateCXXTemporaryObject(const Expr
*Ex
, ExplodedNode
*Pred
,
84 ExplodedNodeSet
&Dst
) {
87 for (ExplodedNodeSet::iterator I
= Tmp
.begin(), E
= Tmp
.end(); I
!= E
; ++I
) {
88 const GRState
*state
= GetState(*I
);
90 // Bind the temporary object to the value of the expression. Then bind
91 // the expression to the location of the object.
92 SVal V
= state
->getSVal(Ex
);
95 svalBuilder
.getRegionManager().getCXXTempObjectRegion(Ex
,
96 Pred
->getLocationContext());
98 state
= state
->bindLoc(loc::MemRegionVal(R
), V
);
99 MakeNode(Dst
, Ex
, Pred
, state
->BindExpr(Ex
, loc::MemRegionVal(R
)));
103 void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr
*E
,
104 const MemRegion
*Dest
,
106 ExplodedNodeSet
&Dst
) {
108 Dest
= svalBuilder
.getRegionManager().getCXXTempObjectRegion(E
,
109 Pred
->getLocationContext());
111 if (E
->isElidable()) {
112 VisitAggExpr(E
->getArg(0), Dest
, Pred
, Dst
);
116 const CXXConstructorDecl
*CD
= E
->getConstructor();
119 if (!(CD
->isThisDeclarationADefinition() && AMgr
.shouldInlineCall()))
120 // FIXME: invalidate the object.
124 // Evaluate other arguments.
125 ExplodedNodeSet argsEvaluated
;
126 const FunctionProtoType
*FnType
= CD
->getType()->getAs
<FunctionProtoType
>();
127 evalArguments(E
->arg_begin(), E
->arg_end(), FnType
, Pred
, argsEvaluated
);
128 // The callee stack frame context used to create the 'this' parameter region.
129 const StackFrameContext
*SFC
= AMgr
.getStackFrame(CD
,
130 Pred
->getLocationContext(),
131 E
, Builder
->getBlock(),
132 Builder
->getIndex());
134 const CXXThisRegion
*ThisR
=getCXXThisRegion(E
->getConstructor()->getParent(),
137 CallEnter
Loc(E
, SFC
, Pred
->getLocationContext());
138 for (ExplodedNodeSet::iterator NI
= argsEvaluated
.begin(),
139 NE
= argsEvaluated
.end(); NI
!= NE
; ++NI
) {
140 const GRState
*state
= GetState(*NI
);
141 // Setup 'this' region, so that the ctor is evaluated on the object pointed
143 state
= state
->bindLoc(loc::MemRegionVal(ThisR
), loc::MemRegionVal(Dest
));
144 ExplodedNode
*N
= Builder
->generateNode(Loc
, state
, Pred
);
150 void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl
*DD
,
151 const MemRegion
*Dest
,
154 ExplodedNodeSet
&Dst
) {
155 if (!(DD
->isThisDeclarationADefinition() && AMgr
.shouldInlineCall()))
157 // Create the context for 'this' region.
158 const StackFrameContext
*SFC
= AMgr
.getStackFrame(DD
,
159 Pred
->getLocationContext(),
160 S
, Builder
->getBlock(),
161 Builder
->getIndex());
163 const CXXThisRegion
*ThisR
= getCXXThisRegion(DD
->getParent(), SFC
);
165 CallEnter
PP(S
, SFC
, Pred
->getLocationContext());
167 const GRState
*state
= Pred
->getState();
168 state
= state
->bindLoc(loc::MemRegionVal(ThisR
), loc::MemRegionVal(Dest
));
169 ExplodedNode
*N
= Builder
->generateNode(PP
, state
, Pred
);
174 void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr
*MCE
,
176 ExplodedNodeSet
&Dst
) {
177 // Get the method type.
178 const FunctionProtoType
*FnType
=
179 MCE
->getCallee()->getType()->getAs
<FunctionProtoType
>();
180 assert(FnType
&& "Method type not available");
182 // Evaluate explicit arguments with a worklist.
183 ExplodedNodeSet argsEvaluated
;
184 evalArguments(MCE
->arg_begin(), MCE
->arg_end(), FnType
, Pred
, argsEvaluated
);
186 // Evaluate the implicit object argument.
187 ExplodedNodeSet AllargsEvaluated
;
188 const MemberExpr
*ME
= dyn_cast
<MemberExpr
>(MCE
->getCallee()->IgnoreParens());
191 Expr
*ObjArgExpr
= ME
->getBase();
192 for (ExplodedNodeSet::iterator I
= argsEvaluated
.begin(),
193 E
= argsEvaluated
.end(); I
!= E
; ++I
) {
194 Visit(ObjArgExpr
, *I
, AllargsEvaluated
);
197 // Now evaluate the call itself.
198 const CXXMethodDecl
*MD
= cast
<CXXMethodDecl
>(ME
->getMemberDecl());
199 assert(MD
&& "not a CXXMethodDecl?");
200 evalMethodCall(MCE
, MD
, ObjArgExpr
, Pred
, AllargsEvaluated
, Dst
);
203 void ExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr
*C
,
205 ExplodedNodeSet
&Dst
) {
206 const CXXMethodDecl
*MD
= dyn_cast_or_null
<CXXMethodDecl
>(C
->getCalleeDecl());
208 // If the operator doesn't represent a method call treat as regural call.
209 VisitCall(C
, Pred
, C
->arg_begin(), C
->arg_end(), Dst
);
213 // Determine the type of function we're calling (if available).
214 const FunctionProtoType
*Proto
= NULL
;
215 QualType FnType
= C
->getCallee()->IgnoreParens()->getType();
216 if (const PointerType
*FnTypePtr
= FnType
->getAs
<PointerType
>())
217 Proto
= FnTypePtr
->getPointeeType()->getAs
<FunctionProtoType
>();
219 // Evaluate arguments treating the first one (object method is called on)
221 ExplodedNodeSet argsEvaluated
;
222 evalArguments(C
->arg_begin(), C
->arg_end(), Proto
, Pred
, argsEvaluated
, true);
224 // Now evaluate the call itself.
225 evalMethodCall(C
, MD
, C
->getArg(0), Pred
, argsEvaluated
, Dst
);
228 void ExprEngine::evalMethodCall(const CallExpr
*MCE
, const CXXMethodDecl
*MD
,
229 const Expr
*ThisExpr
, ExplodedNode
*Pred
,
230 ExplodedNodeSet
&Src
, ExplodedNodeSet
&Dst
) {
231 // Allow checkers to pre-visit the member call.
232 ExplodedNodeSet PreVisitChecks
;
233 CheckerVisit(MCE
, PreVisitChecks
, Src
, PreVisitStmtCallback
);
235 if (!(MD
->isThisDeclarationADefinition() && AMgr
.shouldInlineCall())) {
236 // FIXME: conservative method call evaluation.
237 CheckerVisit(MCE
, Dst
, PreVisitChecks
, PostVisitStmtCallback
);
241 const StackFrameContext
*SFC
= AMgr
.getStackFrame(MD
,
242 Pred
->getLocationContext(),
245 Builder
->getIndex());
246 const CXXThisRegion
*ThisR
= getCXXThisRegion(MD
, SFC
);
247 CallEnter
Loc(MCE
, SFC
, Pred
->getLocationContext());
248 for (ExplodedNodeSet::iterator I
= PreVisitChecks
.begin(),
249 E
= PreVisitChecks
.end(); I
!= E
; ++I
) {
250 // Set up 'this' region.
251 const GRState
*state
= GetState(*I
);
252 state
= state
->bindLoc(loc::MemRegionVal(ThisR
), state
->getSVal(ThisExpr
));
253 Dst
.Add(Builder
->generateNode(Loc
, state
, *I
));
257 void ExprEngine::VisitCXXNewExpr(const CXXNewExpr
*CNE
, ExplodedNode
*Pred
,
258 ExplodedNodeSet
&Dst
) {
259 if (CNE
->isArray()) {
260 // FIXME: allocating an array has not been handled.
264 unsigned Count
= Builder
->getCurrentBlockCount();
265 DefinedOrUnknownSVal symVal
=
266 svalBuilder
.getConjuredSymbolVal(NULL
, CNE
, CNE
->getType(), Count
);
267 const MemRegion
*NewReg
= cast
<loc::MemRegionVal
>(symVal
).getRegion();
269 QualType ObjTy
= CNE
->getType()->getAs
<PointerType
>()->getPointeeType();
271 const ElementRegion
*EleReg
=
272 getStoreManager().GetElementZeroRegion(NewReg
, ObjTy
);
274 // Evaluate constructor arguments.
275 const FunctionProtoType
*FnType
= NULL
;
276 const CXXConstructorDecl
*CD
= CNE
->getConstructor();
278 FnType
= CD
->getType()->getAs
<FunctionProtoType
>();
279 ExplodedNodeSet argsEvaluated
;
280 evalArguments(CNE
->constructor_arg_begin(), CNE
->constructor_arg_end(),
281 FnType
, Pred
, argsEvaluated
);
283 // Initialize the object region and bind the 'new' expression.
284 for (ExplodedNodeSet::iterator I
= argsEvaluated
.begin(),
285 E
= argsEvaluated
.end(); I
!= E
; ++I
) {
286 const GRState
*state
= GetState(*I
);
288 if (ObjTy
->isRecordType()) {
289 state
= state
->InvalidateRegion(EleReg
, CNE
, Count
);
291 if (CNE
->hasInitializer()) {
292 SVal V
= state
->getSVal(*CNE
->constructor_arg_begin());
293 state
= state
->bindLoc(loc::MemRegionVal(EleReg
), V
);
295 // Explicitly set to undefined, because currently we retrieve symbolic
296 // value from symbolic region.
297 state
= state
->bindLoc(loc::MemRegionVal(EleReg
), UndefinedVal());
300 state
= state
->BindExpr(CNE
, loc::MemRegionVal(EleReg
));
301 MakeNode(Dst
, CNE
, *I
, state
);
305 void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr
*CDE
,
306 ExplodedNode
*Pred
,ExplodedNodeSet
&Dst
) {
307 // Should do more checking.
308 ExplodedNodeSet Argevaluated
;
309 Visit(CDE
->getArgument(), Pred
, Argevaluated
);
310 for (ExplodedNodeSet::iterator I
= Argevaluated
.begin(),
311 E
= Argevaluated
.end(); I
!= E
; ++I
) {
312 const GRState
*state
= GetState(*I
);
313 MakeNode(Dst
, CDE
, *I
, state
);
317 void ExprEngine::VisitCXXThisExpr(const CXXThisExpr
*TE
, ExplodedNode
*Pred
,
318 ExplodedNodeSet
&Dst
) {
319 // Get the this object region from StoreManager.
321 svalBuilder
.getRegionManager().getCXXThisRegion(
322 getContext().getCanonicalType(TE
->getType()),
323 Pred
->getLocationContext());
325 const GRState
*state
= GetState(Pred
);
326 SVal V
= state
->getSVal(loc::MemRegionVal(R
));
327 MakeNode(Dst
, TE
, Pred
, state
->BindExpr(TE
, V
));