aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-07-02 22:21:47 +0000
committerJordan Rose <jordan_rose@apple.com>2012-07-02 22:21:47 +0000
commit70cbf3cc09eb21db1108396d30a414ea66d842cc (patch)
tree616162322cc763100a3285634585fcadab7c6b2c /lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
parent879a4334e4c4cab0c22ba91492ffc2838bbc21fc (diff)
[analyzer] Introduce CXXAllocatorCall to handle placement arg invalidation.
This is NOT full-blown support for operator new, but removes some nasty duplicated code introduced in r158784. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159608 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp178
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,