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