ExprEngineCXX.cpp revision 5eca482fe895ea57bc82410222e6426c09e63284
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
20using namespace clang;
21using namespace ento;
22
23namespace {
24class CallExprWLItem {
25public:
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
34void 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
66void 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
94const 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
101const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl,
102                                            const StackFrameContext *frameCtx) {
103  return svalBuilder.getRegionManager().
104                    getCXXThisRegion(decl->getThisType(getContext()), frameCtx);
105}
106
107void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
108                                          ExplodedNode *Pred,
109                                          ExplodedNodeSet &Dst) {
110  StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
111  const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens();
112  const ProgramState *state = Pred->getState();
113  const LocationContext *LCtx = Pred->getLocationContext();
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(tempExpr, Pred->getLocationContext());
118
119  const MemRegion *R =
120    svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx);
121
122  state = state->bindLoc(loc::MemRegionVal(R), V);
123  Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, loc::MemRegionVal(R)));
124}
125
126void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
127                                       const MemRegion *Dest,
128                                       ExplodedNode *Pred,
129                                       ExplodedNodeSet &destNodes) {
130
131  const CXXConstructorDecl *CD = E->getConstructor();
132  assert(CD);
133
134#if 0
135  if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
136    // FIXME: invalidate the object.
137    return;
138#endif
139
140  // Evaluate other arguments.
141  ExplodedNodeSet argsEvaluated;
142  const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
143  evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated);
144
145#if 0
146  // Is the constructor elidable?
147  if (E->isElidable()) {
148    VisitAggExpr(E->getArg(0), destNodes, Pred, Dst);
149    // FIXME: this is here to force propagation if VisitAggExpr doesn't
150    if (destNodes.empty())
151      destNodes.Add(Pred);
152    return;
153  }
154#endif
155
156  // Perform the previsit of the constructor.
157  ExplodedNodeSet destPreVisit;
158  getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E,
159                                            *this);
160
161  // Evaluate the constructor.  Currently we don't now allow checker-specific
162  // implementations of specific constructors (as we do with ordinary
163  // function calls.  We can re-evaluate this in the future.
164
165#if 0
166  // Inlining currently isn't fully implemented.
167
168  if (AMgr.shouldInlineCall()) {
169    if (!Dest)
170      Dest =
171        svalBuilder.getRegionManager().getCXXTempObjectRegion(E,
172                                                  Pred->getLocationContext());
173
174    // The callee stack frame context used to create the 'this'
175    // parameter region.
176    const StackFrameContext *SFC =
177      AMgr.getStackFrame(CD, Pred->getLocationContext(),
178                         E, currentBuilderContext->getBlock(),
179                         currentStmtIdx);
180
181    // Create the 'this' region.
182    const CXXThisRegion *ThisR =
183      getCXXThisRegion(E->getConstructor()->getParent(), SFC);
184
185    CallEnter Loc(E, SFC, Pred->getLocationContext());
186
187    StmtNodeBuilder Bldr(argsEvaluated, destNodes, *currentBuilderContext);
188    for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
189                                  NE = argsEvaluated.end(); NI != NE; ++NI) {
190      const ProgramState *state = (*NI)->getState();
191      // Setup 'this' region, so that the ctor is evaluated on the object pointed
192      // by 'Dest'.
193      state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
194      Bldr.generateNode(Loc, *NI, state);
195    }
196  }
197#endif
198
199  // Default semantics: invalidate all regions passed as arguments.
200  ExplodedNodeSet destCall;
201  {
202    StmtNodeBuilder Bldr(destPreVisit, destCall, *currentBuilderContext);
203    for (ExplodedNodeSet::iterator
204        i = destPreVisit.begin(), e = destPreVisit.end();
205        i != e; ++i)
206    {
207      ExplodedNode *Pred = *i;
208      const LocationContext *LC = Pred->getLocationContext();
209      const ProgramState *state = Pred->getState();
210
211      state = invalidateArguments(state, CallOrObjCMessage(E, state, LC), LC);
212      Bldr.generateNode(E, Pred, state);
213    }
214  }
215  // Do the post visit.
216  getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this);
217}
218
219void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
220                                      const MemRegion *Dest,
221                                      const Stmt *S,
222                                      ExplodedNode *Pred,
223                                      ExplodedNodeSet &Dst) {
224  StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
225  if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
226    return;
227
228  // Create the context for 'this' region.
229  const StackFrameContext *SFC =
230    AnalysisDeclContexts.getContext(DD)->
231      getStackFrame(Pred->getLocationContext(), S,
232      currentBuilderContext->getBlock(), currentStmtIdx);
233
234  const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC);
235
236  CallEnter PP(S, SFC, Pred->getLocationContext());
237
238  const ProgramState *state = Pred->getState();
239  state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
240  Bldr.generateNode(PP, Pred, state);
241}
242
243void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
244                                   ExplodedNodeSet &Dst) {
245  StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
246
247  unsigned blockCount = currentBuilderContext->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, Pred->getLocationContext(),
260                            loc::MemRegionVal(EleReg));
261    Bldr.generateNode(CNE, Pred, state);
262    return;
263  }
264
265  // Evaluate constructor arguments.
266  const FunctionProtoType *FnType = NULL;
267  const CXXConstructorDecl *CD = CNE->getConstructor();
268  if (CD)
269    FnType = CD->getType()->getAs<FunctionProtoType>();
270  ExplodedNodeSet argsEvaluated;
271  Bldr.takeNodes(Pred);
272  evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(),
273                FnType, Pred, argsEvaluated);
274  Bldr.addNodes(argsEvaluated);
275
276  // Initialize the object region and bind the 'new' expression.
277  for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
278                                 E = argsEvaluated.end(); I != E; ++I) {
279
280    const ProgramState *state = (*I)->getState();
281
282    // Accumulate list of regions that are invalidated.
283    // FIXME: Eventually we should unify the logic for constructor
284    // processing in one place.
285    SmallVector<const MemRegion*, 10> regionsToInvalidate;
286    for (CXXNewExpr::const_arg_iterator
287          ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end();
288          ai != ae; ++ai)
289    {
290      SVal val = state->getSVal(*ai, (*I)->getLocationContext());
291      if (const MemRegion *region = val.getAsRegion())
292        regionsToInvalidate.push_back(region);
293    }
294
295    if (ObjTy->isRecordType()) {
296      regionsToInvalidate.push_back(EleReg);
297      // Invalidate the regions.
298      // TODO: Pass the call to new information as the last argument, to limit
299      // the globals which will get invalidated.
300      state = state->invalidateRegions(regionsToInvalidate,
301                                       CNE, blockCount, 0, 0);
302
303    } else {
304      // Invalidate the regions.
305      // TODO: Pass the call to new information as the last argument, to limit
306      // the globals which will get invalidated.
307      state = state->invalidateRegions(regionsToInvalidate,
308                                       CNE, blockCount, 0, 0);
309
310      if (CNE->hasInitializer()) {
311        SVal V = state->getSVal(*CNE->constructor_arg_begin(),
312                                (*I)->getLocationContext());
313        state = state->bindLoc(loc::MemRegionVal(EleReg), V);
314      } else {
315        // Explicitly set to undefined, because currently we retrieve symbolic
316        // value from symbolic region.
317        state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal());
318      }
319    }
320    state = state->BindExpr(CNE, (*I)->getLocationContext(),
321                            loc::MemRegionVal(EleReg));
322    Bldr.generateNode(CNE, *I, state);
323  }
324}
325
326void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
327                                    ExplodedNode *Pred, ExplodedNodeSet &Dst) {
328  // Should do more checking.
329  ExplodedNodeSet Argevaluated;
330  Visit(CDE->getArgument(), Pred, Argevaluated);
331  StmtNodeBuilder Bldr(Argevaluated, Dst, *currentBuilderContext);
332  for (ExplodedNodeSet::iterator I = Argevaluated.begin(),
333                                 E = Argevaluated.end(); I != E; ++I) {
334    const ProgramState *state = (*I)->getState();
335    Bldr.generateNode(CDE, *I, state);
336  }
337}
338
339void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
340                                    ExplodedNodeSet &Dst) {
341  StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
342
343  // Get the this object region from StoreManager.
344  const LocationContext *LCtx = Pred->getLocationContext();
345  const MemRegion *R =
346    svalBuilder.getRegionManager().getCXXThisRegion(
347                                  getContext().getCanonicalType(TE->getType()),
348                                                    LCtx);
349
350  const ProgramState *state = Pred->getState();
351  SVal V = state->getSVal(loc::MemRegionVal(R));
352  Bldr.generateNode(TE, Pred, state->BindExpr(TE, LCtx, V));
353}
354