1 //===- ExprEngineCXX.cpp - ExprEngine support for C++ -----------*- 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 file defines the C++ expression evaluation engine.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
15 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
16 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
18 #include "clang/AST/DeclCXX.h"
19 
20 using namespace clang;
21 using namespace ento;
22 
23 namespace {
24 class CallExprWLItem {
25 public:
26   CallExpr::const_arg_iterator I;
27   ExplodedNode *N;
28 
29   CallExprWLItem(const CallExpr::const_arg_iterator &i, ExplodedNode *n)
30     : I(i), N(n) {}
31 };
32 }
33 
34 void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE,
35                                  const FunctionProtoType *FnType,
36                                  ExplodedNode *Pred, ExplodedNodeSet &Dst,
37                                  bool FstArgAsLValue) {
38 
39 
40   SmallVector<CallExprWLItem, 20> WorkList;
41   WorkList.reserve(AE - AI);
42   WorkList.push_back(CallExprWLItem(AI, Pred));
43 
44   while (!WorkList.empty()) {
45     CallExprWLItem Item = WorkList.back();
46     WorkList.pop_back();
47 
48     if (Item.I == AE) {
49       Dst.insert(Item.N);
50       continue;
51     }
52 
53     // Evaluate the argument.
54     ExplodedNodeSet Tmp;
55     if (FstArgAsLValue) {
56       FstArgAsLValue = false;
57     }
58 
59     Visit(*Item.I, Item.N, Tmp);
60     ++(Item.I);
61     for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
62       WorkList.push_back(CallExprWLItem(Item.I, *NI));
63   }
64 }
65 
66 void ExprEngine::evalCallee(const CallExpr *callExpr,
67                             const ExplodedNodeSet &src,
68                             ExplodedNodeSet &dest) {
69 
70   const Expr *callee = 0;
71 
72   switch (callExpr->getStmtClass()) {
73     case Stmt::CXXMemberCallExprClass: {
74       // Evaluate the implicit object argument that is the recipient of the
75       // call.
76       callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument();
77 
78       // FIXME: handle member pointers.
79       if (!callee)
80         return;
81 
82       break;
83     }
84     default: {
85       callee = callExpr->getCallee()->IgnoreParens();
86       break;
87     }
88   }
89 
90   for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i)
91     Visit(callee, *i, dest);
92 }
93 
94 const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D,
95                                                  const StackFrameContext *SFC) {
96   const Type *T = D->getTypeForDecl();
97   QualType PT = getContext().getPointerType(QualType(T, 0));
98   return svalBuilder.getRegionManager().getCXXThisRegion(PT, SFC);
99 }
100 
101 const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl,
102                                             const StackFrameContext *frameCtx) {
103   return svalBuilder.getRegionManager().
104                     getCXXThisRegion(decl->getThisType(getContext()), frameCtx);
105 }
106 
107 void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
108                                           ExplodedNode *Pred,
109                                           ExplodedNodeSet &Dst) {
110   ExplodedNodeSet Tmp;
111   Visit(ME->GetTemporaryExpr(), Pred, Tmp);
112   for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
113     const ProgramState *state = (*I)->getState();
114 
115     // Bind the temporary object to the value of the expression. Then bind
116     // the expression to the location of the object.
117     SVal V = state->getSVal(ME->GetTemporaryExpr());
118 
119     const MemRegion *R =
120       svalBuilder.getRegionManager().getCXXTempObjectRegion(ME,
121                                                    Pred->getLocationContext());
122 
123     state = state->bindLoc(loc::MemRegionVal(R), V);
124     MakeNode(Dst, ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R)));
125   }
126 }
127 
128 void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
129                                        const MemRegion *Dest,
130                                        ExplodedNode *Pred,
131                                        ExplodedNodeSet &destNodes) {
132 
133   const CXXConstructorDecl *CD = E->getConstructor();
134   assert(CD);
135 
136 #if 0
137   if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
138     // FIXME: invalidate the object.
139     return;
140 #endif
141 
142   // Evaluate other arguments.
143   ExplodedNodeSet argsEvaluated;
144   const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
145   evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated);
146 
147 #if 0
148   // Is the constructor elidable?
149   if (E->isElidable()) {
150     VisitAggExpr(E->getArg(0), destNodes, Pred, Dst);
151     // FIXME: this is here to force propagation if VisitAggExpr doesn't
152     if (destNodes.empty())
153       destNodes.Add(Pred);
154     return;
155   }
156 #endif
157 
158   // Perform the previsit of the constructor.
159   ExplodedNodeSet destPreVisit;
160   getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E,
161                                             *this);
162 
163   // Evaluate the constructor.  Currently we don't now allow checker-specific
164   // implementations of specific constructors (as we do with ordinary
165   // function calls.  We can re-evaluate this in the future.
166 
167 #if 0
168   // Inlining currently isn't fully implemented.
169 
170   if (AMgr.shouldInlineCall()) {
171     if (!Dest)
172       Dest =
173         svalBuilder.getRegionManager().getCXXTempObjectRegion(E,
174                                                   Pred->getLocationContext());
175 
176     // The callee stack frame context used to create the 'this'
177     // parameter region.
178     const StackFrameContext *SFC =
179       AMgr.getStackFrame(CD, Pred->getLocationContext(),
180                          E, Builder->getBlock(), Builder->getIndex());
181 
182     // Create the 'this' region.
183     const CXXThisRegion *ThisR =
184       getCXXThisRegion(E->getConstructor()->getParent(), SFC);
185 
186     CallEnter Loc(E, SFC, Pred->getLocationContext());
187 
188 
189     for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
190                                   NE = argsEvaluated.end(); NI != NE; ++NI) {
191       const ProgramState *state = (*NI)->getState();
192       // Setup 'this' region, so that the ctor is evaluated on the object pointed
193       // by 'Dest'.
194       state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
195       if (ExplodedNode *N = Builder->generateNode(Loc, state, *NI))
196         destNodes.Add(N);
197     }
198   }
199 #endif
200 
201   // Default semantics: invalidate all regions passed as arguments.
202   ExplodedNodeSet destCall;
203 
204   for (ExplodedNodeSet::iterator
205         i = destPreVisit.begin(), e = destPreVisit.end();
206        i != e; ++i)
207   {
208     ExplodedNode *Pred = *i;
209     const LocationContext *LC = Pred->getLocationContext();
210     const ProgramState *state = Pred->getState();
211 
212     state = invalidateArguments(state, CallOrObjCMessage(E, state), LC);
213     Builder->MakeNode(destCall, E, Pred, state);
214   }
215 
216   // Do the post visit.
217   getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this);
218 }
219 
220 void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
221                                       const MemRegion *Dest,
222                                       const Stmt *S,
223                                       ExplodedNode *Pred,
224                                       ExplodedNodeSet &Dst) {
225   if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
226     return;
227   // Create the context for 'this' region.
228   const StackFrameContext *SFC = AMgr.getStackFrame(DD,
229                                                     Pred->getLocationContext(),
230                                                     S, Builder->getBlock(),
231                                                     Builder->getIndex());
232 
233   const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC);
234 
235   CallEnter PP(S, SFC, Pred->getLocationContext());
236 
237   const ProgramState *state = Pred->getState();
238   state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
239   ExplodedNode *N = Builder->generateNode(PP, state, Pred);
240   if (N)
241     Dst.Add(N);
242 }
243 
244 void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
245                                    ExplodedNodeSet &Dst) {
246 
247   unsigned blockCount = Builder->getCurrentBlockCount();
248   DefinedOrUnknownSVal symVal =
249     svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount);
250   const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion();
251   QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
252   const ElementRegion *EleReg =
253     getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
254 
255   if (CNE->isArray()) {
256     // FIXME: allocating an array requires simulating the constructors.
257     // For now, just return a symbolicated region.
258     const ProgramState *state = Pred->getState();
259     state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
260     MakeNode(Dst, CNE, Pred, state);
261     return;
262   }
263 
264   // Evaluate constructor arguments.
265   const FunctionProtoType *FnType = NULL;
266   const CXXConstructorDecl *CD = CNE->getConstructor();
267   if (CD)
268     FnType = CD->getType()->getAs<FunctionProtoType>();
269   ExplodedNodeSet argsEvaluated;
270   evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(),
271                 FnType, Pred, argsEvaluated);
272 
273   // Initialize the object region and bind the 'new' expression.
274   for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
275                                  E = argsEvaluated.end(); I != E; ++I) {
276 
277     const ProgramState *state = (*I)->getState();
278 
279     // Accumulate list of regions that are invalidated.
280     // FIXME: Eventually we should unify the logic for constructor
281     // processing in one place.
282     SmallVector<const MemRegion*, 10> regionsToInvalidate;
283     for (CXXNewExpr::const_arg_iterator
284           ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end();
285           ai != ae; ++ai)
286     {
287       SVal val = state->getSVal(*ai);
288       if (const MemRegion *region = val.getAsRegion())
289         regionsToInvalidate.push_back(region);
290     }
291 
292     if (ObjTy->isRecordType()) {
293       regionsToInvalidate.push_back(EleReg);
294       // Invalidate the regions.
295       state = state->invalidateRegions(regionsToInvalidate,
296                                        CNE, blockCount, 0,
297                                        /* invalidateGlobals = */ true);
298 
299     } else {
300       // Invalidate the regions.
301       state = state->invalidateRegions(regionsToInvalidate,
302                                        CNE, blockCount, 0,
303                                        /* invalidateGlobals = */ true);
304 
305       if (CNE->hasInitializer()) {
306         SVal V = state->getSVal(*CNE->constructor_arg_begin());
307         state = state->bindLoc(loc::MemRegionVal(EleReg), V);
308       } else {
309         // Explicitly set to undefined, because currently we retrieve symbolic
310         // value from symbolic region.
311         state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal());
312       }
313     }
314     state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
315     MakeNode(Dst, CNE, *I, state);
316   }
317 }
318 
319 void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
320                                       ExplodedNode *Pred,ExplodedNodeSet &Dst) {
321   // Should do more checking.
322   ExplodedNodeSet Argevaluated;
323   Visit(CDE->getArgument(), Pred, Argevaluated);
324   for (ExplodedNodeSet::iterator I = Argevaluated.begin(),
325                                  E = Argevaluated.end(); I != E; ++I) {
326     const ProgramState *state = (*I)->getState();
327     MakeNode(Dst, CDE, *I, state);
328   }
329 }
330 
331 void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
332                                     ExplodedNodeSet &Dst) {
333   // Get the this object region from StoreManager.
334   const MemRegion *R =
335     svalBuilder.getRegionManager().getCXXThisRegion(
336                                   getContext().getCanonicalType(TE->getType()),
337                                                Pred->getLocationContext());
338 
339   const ProgramState *state = Pred->getState();
340   SVal V = state->getSVal(loc::MemRegionVal(R));
341   MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
342 }
343