diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 178 |
1 files changed, 19 insertions, 159 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 88dac4c8c8..bac5b70f69 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -92,191 +92,51 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, Bldr.generateNode(PP, Pred, state); } -static bool isPointerToConst(const ParmVarDecl *ParamDecl) { - // FIXME: Copied from ExprEngineCallAndReturn.cpp - QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType(); - if (PointeeTy != QualType() && PointeeTy.isConstQualified() && - !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) { - return true; - } - return false; -} - void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + // FIXME: Much of this should eventually migrate to CXXAllocatorCall. + // Also, we need to decide how allocators actually work -- they're not + // really part of the CXXNewExpr because they happen BEFORE the + // CXXConstructExpr subexpression. See PR12014 for some discussion. StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); unsigned blockCount = currentBuilderContext->getCurrentBlockCount(); const LocationContext *LCtx = Pred->getLocationContext(); DefinedOrUnknownSVal symVal = - svalBuilder.getConjuredSymbolVal(NULL, CNE, LCtx, CNE->getType(), blockCount); - const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion(); - QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); - const ElementRegion *EleReg = - getStoreManager().GetElementZeroRegion(NewReg, ObjTy); + svalBuilder.getConjuredSymbolVal(0, CNE, LCtx, CNE->getType(), blockCount); ProgramStateRef State = Pred->getState(); + // Invalidate placement args. + CXXAllocatorCall Call(CNE, State, LCtx); + State = Call.invalidateRegions(blockCount); + if (CNE->isArray()) { // FIXME: allocating an array requires simulating the constructors. // For now, just return a symbolicated region. + const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion(); + QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); + const ElementRegion *EleReg = + getStoreManager().GetElementZeroRegion(NewReg, ObjTy); State = State->BindExpr(CNE, Pred->getLocationContext(), loc::MemRegionVal(EleReg)); Bldr.generateNode(CNE, Pred, State); return; } + // FIXME: Once we have proper support for CXXConstructExprs inside + // CXXNewExpr, we need to make sure that the constructed object is not + // immediately invalidated here. (The placement call should happen before + // the constructor call anyway.) FunctionDecl *FD = CNE->getOperatorNew(); if (FD && FD->isReservedGlobalPlacementOperator()) { // Non-array placement new should always return the placement location. SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx); State = State->BindExpr(CNE, LCtx, PlacementLoc); - // FIXME: Once we have proper support for CXXConstructExprs inside - // CXXNewExpr, we need to make sure that the constructed object is not - // immediately invalidated here. (The placement call should happen before - // the constructor call anyway.) + } else { + State = State->BindExpr(CNE, LCtx, symVal); } - // Invalidate placement args. - - // FIXME: This is largely copied from invalidateArguments, because - // CallOrObjCMessage is not general enough to handle new-expressions yet. - SmallVector<const MemRegion *, 4> RegionsToInvalidate; - - unsigned Index = 0; - for (CXXNewExpr::const_arg_iterator I = CNE->placement_arg_begin(), - E = CNE->placement_arg_end(); - I != E; ++I) { - // Pre-increment the argument index to skip over the implicit size arg. - ++Index; - if (FD && Index < FD->getNumParams()) - if (isPointerToConst(FD->getParamDecl(Index))) - continue; - - SVal V = State->getSVal(*I, LCtx); - - // If we are passing a location wrapped as an integer, unwrap it and - // invalidate the values referred by the location. - if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V)) - V = Wrapped->getLoc(); - else if (!isa<Loc>(V)) - continue; - - if (const MemRegion *R = V.getAsRegion()) { - // Invalidate the value of the variable passed by reference. - - // Are we dealing with an ElementRegion? If the element type is - // a basic integer type (e.g., char, int) and the underlying region - // is a variable region then strip off the ElementRegion. - // FIXME: We really need to think about this for the general case - // as sometimes we are reasoning about arrays and other times - // about (char*), etc., is just a form of passing raw bytes. - // e.g., void *p = alloca(); foo((char*)p); - if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { - // Checking for 'integral type' is probably too promiscuous, but - // we'll leave it in for now until we have a systematic way of - // handling all of these cases. Eventually we need to come up - // with an interface to StoreManager so that this logic can be - // appropriately delegated to the respective StoreManagers while - // still allowing us to do checker-specific logic (e.g., - // invalidating reference counts), probably via callbacks. - if (ER->getElementType()->isIntegralOrEnumerationType()) { - const MemRegion *superReg = ER->getSuperRegion(); - if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) || - isa<ObjCIvarRegion>(superReg)) - R = cast<TypedRegion>(superReg); - } - // FIXME: What about layers of ElementRegions? - } - - // Mark this region for invalidation. We batch invalidate regions - // below for efficiency. - RegionsToInvalidate.push_back(R); - } else { - // Nuke all other arguments passed by reference. - // FIXME: is this necessary or correct? This handles the non-Region - // cases. Is it ever valid to store to these? - State = State->unbindLoc(cast<Loc>(V)); - } - } - - // Invalidate designated regions using the batch invalidation API. - - // FIXME: We can have collisions on the conjured symbol if the - // expression *I also creates conjured symbols. We probably want - // to identify conjured symbols by an expression pair: the enclosing - // expression (the context) and the expression itself. This should - // disambiguate conjured symbols. - unsigned Count = currentBuilderContext->getCurrentBlockCount(); - - // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate - // global variables. - State = State->invalidateRegions(RegionsToInvalidate, CNE, Count, LCtx); Bldr.generateNode(CNE, Pred, State); - return; - - // FIXME: The below code is long-since dead. However, constructor handling - // in new-expressions is far from complete. See PR12014 for more details. -#if 0 - // Evaluate constructor arguments. - const FunctionProtoType *FnType = NULL; - const CXXConstructorDecl *CD = CNE->getConstructor(); - if (CD) - FnType = CD->getType()->getAs<FunctionProtoType>(); - ExplodedNodeSet argsEvaluated; - Bldr.takeNodes(Pred); - evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), - FnType, Pred, argsEvaluated); - Bldr.addNodes(argsEvaluated); - - // Initialize the object region and bind the 'new' expression. - for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), - E = argsEvaluated.end(); I != E; ++I) { - - ProgramStateRef state = (*I)->getState(); - - // Accumulate list of regions that are invalidated. - // FIXME: Eventually we should unify the logic for constructor - // processing in one place. - SmallVector<const MemRegion*, 10> regionsToInvalidate; - for (CXXNewExpr::const_arg_iterator - ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end(); - ai != ae; ++ai) - { - SVal val = state->getSVal(*ai, (*I)->getLocationContext()); - if (const MemRegion *region = val.getAsRegion()) - regionsToInvalidate.push_back(region); - } - - if (ObjTy->isRecordType()) { - regionsToInvalidate.push_back(EleReg); - // Invalidate the regions. - // TODO: Pass the call to new information as the last argument, to limit - // the globals which will get invalidated. - state = state->invalidateRegions(regionsToInvalidate, - CNE, blockCount, 0, 0); - - } else { - // Invalidate the regions. - // TODO: Pass the call to new information as the last argument, to limit - // the globals which will get invalidated. - state = state->invalidateRegions(regionsToInvalidate, - CNE, blockCount, 0, 0); - - if (CNE->hasInitializer()) { - SVal V = state->getSVal(*CNE->constructor_arg_begin(), - (*I)->getLocationContext()); - state = state->bindLoc(loc::MemRegionVal(EleReg), V); - } else { - // Explicitly set to undefined, because currently we retrieve symbolic - // value from symbolic region. - state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); - } - } - state = state->BindExpr(CNE, (*I)->getLocationContext(), - loc::MemRegionVal(EleReg)); - Bldr.generateNode(CNE, *I, state); - } -#endif } void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, |