| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 1 | //===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- 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/Checker/PathSensitive/AnalysisManager.h" | 
|  | 15 | #include "clang/Checker/PathSensitive/GRExprEngine.h" | 
|  | 16 | #include "clang/AST/DeclCXX.h" | 
|  | 17 |  | 
|  | 18 | using namespace clang; | 
|  | 19 |  | 
| Zhongxing Xu | b17b1b3 | 2010-04-20 03:37:34 +0000 | [diff] [blame] | 20 | void GRExprEngine::EvalArguments(ExprIterator AI, ExprIterator AE, | 
|  | 21 | const FunctionProtoType *FnType, | 
|  | 22 | ExplodedNode *Pred, ExplodedNodeSet &Dst) { | 
|  | 23 | llvm::SmallVector<CallExprWLItem, 20> WorkList; | 
|  | 24 | WorkList.reserve(AE - AI); | 
|  | 25 | WorkList.push_back(CallExprWLItem(AI, Pred)); | 
|  | 26 |  | 
|  | 27 | while (!WorkList.empty()) { | 
|  | 28 | CallExprWLItem Item = WorkList.back(); | 
|  | 29 | WorkList.pop_back(); | 
|  | 30 |  | 
|  | 31 | if (Item.I == AE) { | 
|  | 32 | Dst.insert(Item.N); | 
|  | 33 | continue; | 
|  | 34 | } | 
|  | 35 |  | 
|  | 36 | ExplodedNodeSet Tmp; | 
|  | 37 | const unsigned ParamIdx = Item.I - AI; | 
|  | 38 | bool VisitAsLvalue = FnType? FnType->getArgType(ParamIdx)->isReferenceType() | 
|  | 39 | : false; | 
|  | 40 | if (VisitAsLvalue) | 
|  | 41 | VisitLValue(*Item.I, Item.N, Tmp); | 
|  | 42 | else | 
|  | 43 | Visit(*Item.I, Item.N, Tmp); | 
|  | 44 |  | 
|  | 45 | ++(Item.I); | 
|  | 46 | for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) | 
|  | 47 | WorkList.push_back(CallExprWLItem(Item.I, *NI)); | 
|  | 48 | } | 
|  | 49 | } | 
|  | 50 |  | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 51 | const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, | 
|  | 52 | const StackFrameContext *SFC) { | 
|  | 53 | Type *T = D->getParent()->getTypeForDecl(); | 
|  | 54 | QualType PT = getContext().getPointerType(QualType(T,0)); | 
|  | 55 | return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); | 
|  | 56 | } | 
|  | 57 |  | 
|  | 58 | void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, | 
|  | 59 | ExplodedNodeSet &Dst) { | 
|  | 60 | ExplodedNodeSet Tmp; | 
|  | 61 | Visit(Ex, Pred, Tmp); | 
|  | 62 | for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { | 
|  | 63 | const GRState *state = GetState(*I); | 
|  | 64 |  | 
|  | 65 | // Bind the temporary object to the value of the expression. Then bind | 
|  | 66 | // the expression to the location of the object. | 
|  | 67 | SVal V = state->getSVal(Ex); | 
|  | 68 |  | 
|  | 69 | const MemRegion *R = | 
|  | 70 | ValMgr.getRegionManager().getCXXObjectRegion(Ex, | 
|  | 71 | Pred->getLocationContext()); | 
|  | 72 |  | 
|  | 73 | state = state->bindLoc(loc::MemRegionVal(R), V); | 
|  | 74 | MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); | 
|  | 75 | } | 
|  | 76 | } | 
|  | 77 |  | 
|  | 78 | void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, | 
|  | 79 | ExplodedNode *Pred, | 
|  | 80 | ExplodedNodeSet &Dst) { | 
|  | 81 | if (E->isElidable()) { | 
|  | 82 | VisitAggExpr(E->getArg(0), Dest, Pred, Dst); | 
|  | 83 | return; | 
|  | 84 | } | 
|  | 85 |  | 
|  | 86 | const CXXConstructorDecl *CD = E->getConstructor(); | 
|  | 87 | assert(CD); | 
|  | 88 |  | 
| Zhongxing Xu | 7b99d12 | 2010-05-06 02:59:29 +0000 | [diff] [blame] | 89 | if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 90 | // FIXME: invalidate the object. | 
|  | 91 | return; | 
|  | 92 |  | 
|  | 93 |  | 
|  | 94 | // Evaluate other arguments. | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 95 | ExplodedNodeSet ArgsEvaluated; | 
| Zhongxing Xu | 107ccd1 | 2010-04-20 05:40:40 +0000 | [diff] [blame] | 96 | const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>(); | 
|  | 97 | EvalArguments(const_cast<CXXConstructExpr*>(E)->arg_begin(), | 
|  | 98 | const_cast<CXXConstructExpr*>(E)->arg_end(), | 
|  | 99 | FnType, Pred, ArgsEvaluated); | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 100 | // The callee stack frame context used to create the 'this' parameter region. | 
|  | 101 | const StackFrameContext *SFC = AMgr.getStackFrame(CD, | 
|  | 102 | Pred->getLocationContext(), | 
|  | 103 | E, Builder->getBlock(), Builder->getIndex()); | 
|  | 104 |  | 
|  | 105 | const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); | 
|  | 106 |  | 
|  | 107 | CallEnter Loc(E, CD, Pred->getLocationContext()); | 
|  | 108 | for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), | 
|  | 109 | NE = ArgsEvaluated.end(); NI != NE; ++NI) { | 
|  | 110 | const GRState *state = GetState(*NI); | 
|  | 111 | // Setup 'this' region. | 
|  | 112 | state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); | 
|  | 113 | ExplodedNode *N = Builder->generateNode(Loc, state, Pred); | 
|  | 114 | if (N) | 
|  | 115 | Dst.Add(N); | 
|  | 116 | } | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, | 
|  | 120 | ExplodedNode *Pred, | 
|  | 121 | ExplodedNodeSet &Dst) { | 
|  | 122 | // Get the method type. | 
|  | 123 | const FunctionProtoType *FnType = | 
|  | 124 | MCE->getCallee()->getType()->getAs<FunctionProtoType>(); | 
|  | 125 | assert(FnType && "Method type not available"); | 
|  | 126 |  | 
|  | 127 | // Evaluate explicit arguments with a worklist. | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 128 | ExplodedNodeSet ArgsEvaluated; | 
| Zhongxing Xu | 107ccd1 | 2010-04-20 05:40:40 +0000 | [diff] [blame] | 129 | EvalArguments(const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(), | 
|  | 130 | const_cast<CXXMemberCallExpr*>(MCE)->arg_end(), | 
|  | 131 | FnType, Pred, ArgsEvaluated); | 
|  | 132 |  | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 133 | // Evaluate the implicit object argument. | 
|  | 134 | ExplodedNodeSet AllArgsEvaluated; | 
|  | 135 | const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens()); | 
|  | 136 | if (!ME) | 
|  | 137 | return; | 
|  | 138 | Expr *ObjArgExpr = ME->getBase(); | 
|  | 139 | for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), | 
|  | 140 | E = ArgsEvaluated.end(); I != E; ++I) { | 
|  | 141 | if (ME->isArrow()) | 
|  | 142 | Visit(ObjArgExpr, *I, AllArgsEvaluated); | 
|  | 143 | else | 
|  | 144 | VisitLValue(ObjArgExpr, *I, AllArgsEvaluated); | 
|  | 145 | } | 
|  | 146 |  | 
|  | 147 | const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); | 
|  | 148 | assert(MD && "not a CXXMethodDecl?"); | 
|  | 149 |  | 
| Zhongxing Xu | 7b99d12 | 2010-05-06 02:59:29 +0000 | [diff] [blame] | 150 | if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 151 | // FIXME: conservative method call evaluation. | 
|  | 152 | return; | 
|  | 153 |  | 
|  | 154 | const StackFrameContext *SFC = AMgr.getStackFrame(MD, | 
|  | 155 | Pred->getLocationContext(), | 
|  | 156 | MCE, | 
|  | 157 | Builder->getBlock(), | 
|  | 158 | Builder->getIndex()); | 
|  | 159 | const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); | 
|  | 160 | CallEnter Loc(MCE, MD, Pred->getLocationContext()); | 
|  | 161 | for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), | 
|  | 162 | E = AllArgsEvaluated.end(); I != E; ++I) { | 
|  | 163 | // Set up 'this' region. | 
|  | 164 | const GRState *state = GetState(*I); | 
|  | 165 | state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); | 
|  | 166 | ExplodedNode *N = Builder->generateNode(Loc, state, *I); | 
|  | 167 | if (N) | 
|  | 168 | Dst.Add(N); | 
|  | 169 | } | 
|  | 170 | } | 
|  | 171 |  | 
|  | 172 | void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred, | 
|  | 173 | ExplodedNodeSet &Dst) { | 
|  | 174 | if (CNE->isArray()) { | 
|  | 175 | // FIXME: allocating an array has not been handled. | 
|  | 176 | return; | 
|  | 177 | } | 
|  | 178 |  | 
|  | 179 | unsigned Count = Builder->getCurrentBlockCount(); | 
|  | 180 | DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE, | 
|  | 181 | CNE->getType(), Count); | 
|  | 182 | const MemRegion *NewReg = cast<loc::MemRegionVal>(SymVal).getRegion(); | 
|  | 183 |  | 
|  | 184 | QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); | 
|  | 185 |  | 
|  | 186 | const ElementRegion *EleReg = | 
|  | 187 | getStoreManager().GetElementZeroRegion(NewReg, ObjTy); | 
|  | 188 |  | 
| Zhongxing Xu | b17b1b3 | 2010-04-20 03:37:34 +0000 | [diff] [blame] | 189 | // Evaluate constructor arguments. | 
|  | 190 | const FunctionProtoType *FnType = NULL; | 
|  | 191 | const CXXConstructorDecl *CD = CNE->getConstructor(); | 
|  | 192 | if (CD) | 
|  | 193 | FnType = CD->getType()->getAs<FunctionProtoType>(); | 
|  | 194 | ExplodedNodeSet ArgsEvaluated; | 
|  | 195 | EvalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), | 
|  | 196 | FnType, Pred, ArgsEvaluated); | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 197 |  | 
| Zhongxing Xu | b17b1b3 | 2010-04-20 03:37:34 +0000 | [diff] [blame] | 198 | // Initialize the object region and bind the 'new' expression. | 
|  | 199 | for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), | 
|  | 200 | E = ArgsEvaluated.end(); I != E; ++I) { | 
|  | 201 | const GRState *state = GetState(*I); | 
|  | 202 |  | 
|  | 203 | if (ObjTy->isRecordType()) { | 
|  | 204 | Store store = state->getStore(); | 
|  | 205 | StoreManager::InvalidatedSymbols IS; | 
|  | 206 | store = getStoreManager().InvalidateRegion(store, EleReg, CNE, Count, &IS); | 
|  | 207 | state = state->makeWithStore(store); | 
|  | 208 | } else { | 
|  | 209 | if (CNE->hasInitializer()) { | 
|  | 210 | SVal V = state->getSVal(*CNE->constructor_arg_begin()); | 
|  | 211 | state = state->bindLoc(loc::MemRegionVal(EleReg), V); | 
|  | 212 | } else { | 
|  | 213 | // Explicitly set to undefined, because currently we retrieve symbolic | 
|  | 214 | // value from symbolic region. | 
|  | 215 | state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); | 
|  | 216 | } | 
|  | 217 | } | 
|  | 218 | state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); | 
| Zhongxing Xu | 978b935 | 2010-04-21 02:20:10 +0000 | [diff] [blame] | 219 | MakeNode(Dst, CNE, *I, state); | 
| Zhongxing Xu | b17b1b3 | 2010-04-20 03:37:34 +0000 | [diff] [blame] | 220 | } | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 221 | } | 
|  | 222 |  | 
| Zhongxing Xu | 6b85138 | 2010-04-21 02:17:31 +0000 | [diff] [blame] | 223 | void GRExprEngine::VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred, | 
|  | 224 | ExplodedNodeSet &Dst) { | 
|  | 225 | // Should do more checking. | 
|  | 226 | ExplodedNodeSet ArgEvaluated; | 
|  | 227 | Visit(CDE->getArgument(), Pred, ArgEvaluated); | 
|  | 228 | for (ExplodedNodeSet::iterator I = ArgEvaluated.begin(), | 
|  | 229 | E = ArgEvaluated.end(); I != E; ++I) { | 
|  | 230 | const GRState *state = GetState(*I); | 
|  | 231 | MakeNode(Dst, CDE, *I, state); | 
|  | 232 | } | 
|  | 233 | } | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 234 |  | 
|  | 235 | void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, | 
| Zhongxing Xu | 6b85138 | 2010-04-21 02:17:31 +0000 | [diff] [blame] | 236 | ExplodedNodeSet &Dst) { | 
| Zhongxing Xu | cb7464a | 2010-04-19 12:51:02 +0000 | [diff] [blame] | 237 | // Get the this object region from StoreManager. | 
|  | 238 | const MemRegion *R = | 
|  | 239 | ValMgr.getRegionManager().getCXXThisRegion( | 
|  | 240 | getContext().getCanonicalType(TE->getType()), | 
|  | 241 | Pred->getLocationContext()); | 
|  | 242 |  | 
|  | 243 | const GRState *state = GetState(Pred); | 
|  | 244 | SVal V = state->getSVal(loc::MemRegionVal(R)); | 
|  | 245 | MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); | 
|  | 246 | } |