#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/Analysis/ConstructionContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/ParentMap.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
using namespace clang;
using namespace ento;
void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
const Expr *tempExpr = ME->getSubExpr()->IgnoreParens();
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
state = createTemporaryRegionIfNeeded(state, LCtx, tempExpr, ME);
Bldr.generateNode(ME, Pred, state);
}
void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
const CallEvent &Call) {
SVal ThisVal;
bool AlwaysReturnsLValue;
const CXXRecordDecl *ThisRD = nullptr;
if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
assert(Ctor->getDecl()->isTrivial());
assert(Ctor->getDecl()->isCopyOrMoveConstructor());
ThisVal = Ctor->getCXXThisVal();
ThisRD = Ctor->getDecl()->getParent();
AlwaysReturnsLValue = false;
} else {
assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial());
assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() ==
OO_Equal);
ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal();
ThisRD = cast<CXXMethodDecl>(Call.getDecl())->getParent();
AlwaysReturnsLValue = true;
}
assert(ThisRD);
if (ThisRD->isEmpty()) {
return;
}
const LocationContext *LCtx = Pred->getLocationContext();
ExplodedNodeSet Dst;
Bldr.takeNodes(Pred);
SVal V = Call.getArgSVal(0);
if (Optional<Loc> L = V.getAs<Loc>())
V = Pred->getState()->getSVal(*L);
else
assert(V.isUnknownOrUndef());
const Expr *CallExpr = Call.getOriginExpr();
evalBind(Dst, CallExpr, Pred, ThisVal, V, true);
PostStmt PS(CallExpr, LCtx);
for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end();
I != E; ++I) {
ProgramStateRef State = (*I)->getState();
if (AlwaysReturnsLValue)
State = State->BindExpr(CallExpr, LCtx, ThisVal);
else
State = bindReturnValue(Call, LCtx, State);
Bldr.generateNode(PS, State, *I);
}
}
SVal ExprEngine::makeElementRegion(ProgramStateRef State, SVal LValue,
QualType &Ty, bool &IsArray, unsigned Idx) {
SValBuilder &SVB = State->getStateManager().getSValBuilder();
ASTContext &Ctx = SVB.getContext();
if (const ArrayType *AT = Ctx.getAsArrayType(Ty)) {
while (AT) {
Ty = AT->getElementType();
AT = dyn_cast<ArrayType>(AT->getElementType());
}
LValue = State->getLValue(Ty, SVB.makeArrayIndex(Idx), LValue);
IsArray = true;
}
return LValue;
}
SVal ExprEngine::computeObjectUnderConstruction(
const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
const ConstructionContext *CC, EvalCallOptions &CallOpts, unsigned Idx) {
SValBuilder &SVB = getSValBuilder();
MemRegionManager &MRMgr = SVB.getRegionManager();
ASTContext &ACtx = SVB.getContext();
if (CC) {
switch (CC->getKind()) {
case ConstructionContext::CXX17ElidedCopyVariableKind:
case ConstructionContext::SimpleVariableKind: {
const auto *DSCC = cast<VariableConstructionContext>(CC);
const auto *DS = DSCC->getDeclStmt();
const auto *Var = cast<VarDecl>(DS->getSingleDecl());
QualType Ty = Var->getType();
return makeElementRegion(State, State->getLValue(Var, LCtx), Ty,
CallOpts.IsArrayCtorOrDtor, Idx);
}
case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
case ConstructionContext::SimpleConstructorInitializerKind: {
const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
const auto *Init = ICC->getCXXCtorInitializer();
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
Loc ThisPtr = SVB.getCXXThis(CurCtor, LCtx->getStackFrame());
SVal ThisVal = State->getSVal(ThisPtr);
if (Init->isBaseInitializer()) {
const auto *ThisReg = cast<SubRegion>(ThisVal.getAsRegion());
const CXXRecordDecl *BaseClass =
Init->getBaseClass()->getAsCXXRecordDecl();
const auto *BaseReg =
MRMgr.getCXXBaseObjectRegion(BaseClass, ThisReg,
Init->isBaseVirtual());
return SVB.makeLoc(BaseReg);
}
if (Init->isDelegatingInitializer())
return ThisVal;
const ValueDecl *Field;
SVal FieldVal;
if (Init->isIndirectMemberInitializer()) {
Field = Init->getIndirectMember();
FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal);
} else {
Field = Init->getMember();
FieldVal = State->getLValue(Init->getMember(), ThisVal);
}
QualType Ty = Field->getType();
return makeElementRegion(State, FieldVal, Ty, CallOpts.IsArrayCtorOrDtor,
Idx);
}
case ConstructionContext::NewAllocatedObjectKind: {
if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
const auto *NE = NECC->getCXXNewExpr();
SVal V = *getObjectUnderConstruction(State, NE, LCtx);
if (const SubRegion *MR =
dyn_cast_or_null<SubRegion>(V.getAsRegion())) {
if (NE->isArray()) {
CallOpts.IsArrayCtorOrDtor = true;
auto R = MRMgr.getElementRegion(NE->getType()->getPointeeType(),
svalBuilder.makeArrayIndex(Idx), MR,
SVB.getContext());
return loc::MemRegionVal(R);
}
return V;
}
}
break;
}
case ConstructionContext::SimpleReturnedValueKind:
case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
const StackFrameContext *SFC = LCtx->getStackFrame();
if (const LocationContext *CallerLCtx = SFC->getParent()) {
auto RTC = (*SFC->getCallSiteBlock())[SFC->getIndex()]
.getAs<CFGCXXRecordTypedCall>();
if (!RTC) {
break;
}
if (isa<BlockInvocationContext>(CallerLCtx)) {
CallerLCtx = CallerLCtx->getParent();
assert(!isa<BlockInvocationContext>(CallerLCtx));
}
return computeObjectUnderConstruction(
cast<Expr>(SFC->getCallSite()), State, CallerLCtx,
RTC->getConstructionContext(), CallOpts);
} else {
const auto *RCC = cast<ReturnedValueConstructionContext>(CC);
static const int TopLevelSymRegionTag = 0;
const Expr *RetE = RCC->getReturnStmt()->getRetValue();
assert(RetE && "Void returns should not have a construction context");
QualType ReturnTy = RetE->getType();
QualType RegionTy = ACtx.getPointerType(ReturnTy);
return SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC, RegionTy,
currBldrCtx->blockCount());
}
llvm_unreachable("Unhandled return value construction context!");
}
case ConstructionContext::ElidedTemporaryObjectKind: {
assert(AMgr.getAnalyzerOptions().ShouldElideConstructors);
const auto *TCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
ProgramStateRef PreElideState = State;
EvalCallOptions PreElideCallOpts = CallOpts;
SVal V = computeObjectUnderConstruction(
TCC->getConstructorAfterElision(), State, LCtx,
TCC->getConstructionContextAfterElision(), CallOpts);
if (!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion)
return V;
CallOpts = PreElideCallOpts;
CallOpts.IsElidableCtorThatHasNotBeenElided = true;
LLVM_FALLTHROUGH;
}
case ConstructionContext::SimpleTemporaryObjectKind: {
const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr();
CallOpts.IsTemporaryCtorOrDtor = true;
if (MTE) {
if (const ValueDecl *VD = MTE->getExtendingDecl()) {
assert(MTE->getStorageDuration() != SD_FullExpression);
if (!VD->getType()->isReferenceType()) {
CallOpts.IsTemporaryLifetimeExtendedViaAggregate = true;
}
}
if (MTE->getStorageDuration() == SD_Static ||
MTE->getStorageDuration() == SD_Thread)
return loc::MemRegionVal(MRMgr.getCXXStaticTempObjectRegion(E));
}
return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
}
case ConstructionContext::LambdaCaptureKind: {
CallOpts.IsTemporaryCtorOrDtor = true;
const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
SVal Base = loc::MemRegionVal(
MRMgr.getCXXTempObjectRegion(LCC->getInitializer(), LCtx));
const auto *CE = dyn_cast_or_null<CXXConstructExpr>(E);
if (getIndexOfElementToConstruct(State, CE, LCtx)) {
CallOpts.IsArrayCtorOrDtor = true;
Base = State->getLValue(E->getType(), svalBuilder.makeArrayIndex(Idx),
Base);
}
return Base;
}
case ConstructionContext::ArgumentKind: {
CallOpts.IsTemporaryCtorOrDtor = true;
const auto *ACC = cast<ArgumentConstructionContext>(CC);
const Expr *E = ACC->getCallLikeExpr();
unsigned Idx = ACC->getIndex();
CallEventManager &CEMgr = getStateManager().getCallEventManager();
auto getArgLoc = [&](CallEventRef<> Caller) -> Optional<SVal> {
const LocationContext *FutureSFC =
Caller->getCalleeStackFrame(currBldrCtx->blockCount());
if (!FutureSFC)
return None;
const Decl *CalleeD = FutureSFC->getDecl();
if (CallEvent::isVariadic(CalleeD))
return None;
const TypedValueRegion *TVR = Caller->getParameterLocation(
*Caller->getAdjustedParameterIndex(Idx), currBldrCtx->blockCount());
if (!TVR)
return None;
return loc::MemRegionVal(TVR);
};
if (const auto *CE = dyn_cast<CallExpr>(E)) {
CallEventRef<> Caller = CEMgr.getSimpleCall(CE, State, LCtx);
if (Optional<SVal> V = getArgLoc(Caller))
return *V;
else
break;
} else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) {
CallEventRef<> Caller =
CEMgr.getCXXConstructorCall(CCE, nullptr, State, LCtx);
if (Optional<SVal> V = getArgLoc(Caller))
return *V;
else
break;
} else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
CallEventRef<> Caller = CEMgr.getObjCMethodCall(ME, State, LCtx);
if (Optional<SVal> V = getArgLoc(Caller))
return *V;
else
break;
}
}
} }
CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
}
ProgramStateRef ExprEngine::updateObjectsUnderConstruction(
SVal V, const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
const ConstructionContext *CC, const EvalCallOptions &CallOpts) {
if (CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) {
return State;
}
assert(CC && "Computed target region without construction context?");
switch (CC->getKind()) {
case ConstructionContext::CXX17ElidedCopyVariableKind:
case ConstructionContext::SimpleVariableKind: {
const auto *DSCC = cast<VariableConstructionContext>(CC);
return addObjectUnderConstruction(State, DSCC->getDeclStmt(), LCtx, V);
}
case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
case ConstructionContext::SimpleConstructorInitializerKind: {
const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
const auto *Init = ICC->getCXXCtorInitializer();
assert(Init->isAnyMemberInitializer() &&
"Base and delegating initializers should have been handled by"
"computeObjectUnderConstruction()");
return addObjectUnderConstruction(State, Init, LCtx, V);
}
case ConstructionContext::NewAllocatedObjectKind: {
return State;
}
case ConstructionContext::SimpleReturnedValueKind:
case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
const StackFrameContext *SFC = LCtx->getStackFrame();
const LocationContext *CallerLCtx = SFC->getParent();
if (!CallerLCtx) {
return State;
}
auto RTC = (*SFC->getCallSiteBlock())[SFC->getIndex()]
.getAs<CFGCXXRecordTypedCall>();
assert(RTC && "Could not have had a target region without it");
if (isa<BlockInvocationContext>(CallerLCtx)) {
CallerLCtx = CallerLCtx->getParent();
assert(!isa<BlockInvocationContext>(CallerLCtx));
}
return updateObjectsUnderConstruction(V,
cast<Expr>(SFC->getCallSite()), State, CallerLCtx,
RTC->getConstructionContext(), CallOpts);
}
case ConstructionContext::ElidedTemporaryObjectKind: {
assert(AMgr.getAnalyzerOptions().ShouldElideConstructors);
if (!CallOpts.IsElidableCtorThatHasNotBeenElided) {
const auto *TCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
State = updateObjectsUnderConstruction(
V, TCC->getConstructorAfterElision(), State, LCtx,
TCC->getConstructionContextAfterElision(), CallOpts);
State = addObjectUnderConstruction(
State, TCC->getConstructorAfterElision(), LCtx, V);
if (const auto *BTE = TCC->getCXXBindTemporaryExpr())
State = elideDestructor(State, BTE, LCtx);
if (const auto *MTE = TCC->getMaterializedTemporaryExpr())
State = addObjectUnderConstruction(State, MTE, LCtx, V);
return State;
}
LLVM_FALLTHROUGH;
}
case ConstructionContext::SimpleTemporaryObjectKind: {
const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
if (const auto *BTE = TCC->getCXXBindTemporaryExpr())
State = addObjectUnderConstruction(State, BTE, LCtx, V);
if (const auto *MTE = TCC->getMaterializedTemporaryExpr())
State = addObjectUnderConstruction(State, MTE, LCtx, V);
return State;
}
case ConstructionContext::LambdaCaptureKind: {
const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
if (const auto *EL = dyn_cast_or_null<ElementRegion>(V.getAsRegion()))
V = loc::MemRegionVal(EL->getSuperRegion());
return addObjectUnderConstruction(
State, {LCC->getLambdaExpr(), LCC->getIndex()}, LCtx, V);
}
case ConstructionContext::ArgumentKind: {
const auto *ACC = cast<ArgumentConstructionContext>(CC);
if (const auto *BTE = ACC->getCXXBindTemporaryExpr())
State = addObjectUnderConstruction(State, BTE, LCtx, V);
return addObjectUnderConstruction(
State, {ACC->getCallLikeExpr(), ACC->getIndex()}, LCtx, V);
}
}
llvm_unreachable("Unhandled construction context!");
}
static ProgramStateRef
bindRequiredArrayElementToEnvironment(ProgramStateRef State,
const ArrayInitLoopExpr *AILE,
const LocationContext *LCtx, SVal Idx) {
const auto *CE = cast<CXXConstructExpr>(AILE->getSubExpr());
const auto *OVESrc = AILE->getCommonExpr()->getSourceExpr();
SVal Base = UnknownVal();
if (const auto *ME = dyn_cast<MemberExpr>(OVESrc))
Base = State->getSVal(ME, LCtx);
else if (const auto *DRE = cast<DeclRefExpr>(OVESrc))
Base = State->getLValue(cast<VarDecl>(DRE->getDecl()), LCtx);
else
llvm_unreachable("ArrayInitLoopExpr contains unexpected source expression");
SVal NthElem = State->getLValue(CE->getType(), Idx, Base);
return State->BindExpr(CE->getArg(0), LCtx, NthElem);
}
void ExprEngine::handleConstructor(const Expr *E,
ExplodedNode *Pred,
ExplodedNodeSet &destNodes) {
const auto *CE = dyn_cast<CXXConstructExpr>(E);
const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(E);
assert(CE || CIE);
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
SVal Target = UnknownVal();
if (CE) {
if (Optional<SVal> ElidedTarget =
getObjectUnderConstruction(State, CE, LCtx)) {
Target = *ElidedTarget;
StmtNodeBuilder Bldr(Pred, destNodes, *currBldrCtx);
State = finishObjectConstruction(State, CE, LCtx);
if (auto L = Target.getAs<Loc>())
State = State->BindExpr(CE, LCtx, State->getSVal(*L, CE->getType()));
Bldr.generateNode(CE, Pred, State);
return;
}
}
EvalCallOptions CallOpts;
auto C = getCurrentCFGElement().getAs<CFGConstructor>();
assert(C || getCurrentCFGElement().getAs<CFGStmt>());
const ConstructionContext *CC = C ? C->getConstructionContext() : nullptr;
const CXXConstructExpr::ConstructionKind CK =
CE ? CE->getConstructionKind() : CIE->getConstructionKind();
switch (CK) {
case CXXConstructExpr::CK_Complete: {
assert(CE && !CIE && "A complete constructor is inherited?!");
auto *AILE = CC ? CC->getArrayInitLoop() : nullptr;
unsigned Idx = 0;
if (CE->getType()->isArrayType() || AILE) {
Idx = getIndexOfElementToConstruct(State, CE, LCtx).value_or(0u);
State = setIndexOfElementToConstruct(State, CE, LCtx, Idx + 1);
}
if (AILE) {
if (!getPendingInitLoop(State, CE, LCtx))
State = setPendingInitLoop(State, CE, LCtx,
AILE->getArraySize().getLimitedValue());
State = bindRequiredArrayElementToEnvironment(
State, AILE, LCtx, svalBuilder.makeArrayIndex(Idx));
}
std::tie(State, Target) =
handleConstructionContext(CE, State, LCtx, CC, CallOpts, Idx);
break;
}
case CXXConstructExpr::CK_VirtualBase: {
const auto *OuterCtor = dyn_cast_or_null<CXXConstructExpr>(
LCtx->getStackFrame()->getCallSite());
assert(
(!OuterCtor ||
OuterCtor->getConstructionKind() == CXXConstructExpr::CK_Complete ||
OuterCtor->getConstructionKind() == CXXConstructExpr::CK_Delegating) &&
("This virtual base should have already been initialized by "
"the most derived class!"));
(void)OuterCtor;
LLVM_FALLTHROUGH;
}
case CXXConstructExpr::CK_NonVirtualBase:
if (isa_and_nonnull<InitListExpr>(LCtx->getParentMap().getParent(E))) {
MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
break;
}
LLVM_FALLTHROUGH;
case CXXConstructExpr::CK_Delegating: {
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
LCtx->getStackFrame());
SVal ThisVal = State->getSVal(ThisPtr);
if (CK == CXXConstructExpr::CK_Delegating) {
Target = ThisVal;
} else {
bool IsVirtual = (CK == CXXConstructExpr::CK_VirtualBase);
SVal BaseVal =
getStoreManager().evalDerivedToBase(ThisVal, E->getType(), IsVirtual);
Target = BaseVal;
}
break;
}
}
if (State != Pred->getState()) {
static SimpleProgramPointTag T("ExprEngine",
"Prepare for object construction");
ExplodedNodeSet DstPrepare;
StmtNodeBuilder BldrPrepare(Pred, DstPrepare, *currBldrCtx);
BldrPrepare.generateNode(E, Pred, State, &T, ProgramPoint::PreStmtKind);
assert(DstPrepare.size() <= 1);
if (DstPrepare.size() == 0)
return;
Pred = *BldrPrepare.begin();
}
const MemRegion *TargetRegion = Target.getAsRegion();
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<> Call =
CIE ? (CallEventRef<>)CEMgr.getCXXInheritedConstructorCall(
CIE, TargetRegion, State, LCtx)
: (CallEventRef<>)CEMgr.getCXXConstructorCall(
CE, TargetRegion, State, LCtx);
ExplodedNodeSet DstPreVisit;
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, E, *this);
ExplodedNodeSet PreInitialized;
if (CE) {
StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
for (ExplodedNodeSet::iterator I = DstPreVisit.begin(),
E = DstPreVisit.end();
I != E; ++I) {
ProgramStateRef State = (*I)->getState();
if (CE->requiresZeroInitialization()) {
State = State->bindDefaultZero(Target, LCtx);
}
Bldr.generateNode(CE, *I, State, nullptr,
ProgramPoint::PreStmtKind);
}
} else {
PreInitialized = DstPreVisit;
}
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized,
*Call, *this);
ExplodedNodeSet DstEvaluated;
if (CE && CE->getConstructor()->isTrivial() &&
CE->getConstructor()->isCopyOrMoveConstructor() &&
!CallOpts.IsArrayCtorOrDtor) {
StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx);
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
performTrivialCopy(Bldr, *I, *Call);
} else {
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, *this,
CallOpts);
}
ExplodedNodeSet DstEvaluatedPostProcessed;
StmtNodeBuilder Bldr(DstEvaluated, DstEvaluatedPostProcessed, *currBldrCtx);
const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext();
if (!ADC->getCFGBuildOptions().AddTemporaryDtors) {
if (llvm::isa_and_nonnull<CXXTempObjectRegion>(TargetRegion) &&
cast<CXXConstructorDecl>(Call->getDecl())
->getParent()
->isAnyDestructorNoReturn()) {
assert(!DstEvaluated.empty() &&
"We should not have inlined this constructor!");
for (ExplodedNode *N : DstEvaluated) {
Bldr.generateSink(E, N, N->getState());
}
return;
}
}
ExplodedNodeSet DstPostArgumentCleanup;
for (ExplodedNode *I : DstEvaluatedPostProcessed)
finishArgumentConstruction(DstPostArgumentCleanup, I, *Call);
ExplodedNodeSet DstPostCall;
getCheckerManager().runCheckersForPostCall(DstPostCall,
DstPostArgumentCleanup,
*Call, *this);
getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, E, *this);
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
handleConstructor(CE, Pred, Dst);
}
void ExprEngine::VisitCXXInheritedCtorInitExpr(
const CXXInheritedCtorInitExpr *CE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
handleConstructor(CE, Pred, Dst);
}
void ExprEngine::VisitCXXDestructor(QualType ObjectType,
const MemRegion *Dest,
const Stmt *S,
bool IsBaseDtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst,
EvalCallOptions &CallOpts) {
assert(S && "A destructor without a trigger!");
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
assert(RecordDecl && "Only CXXRecordDecls should have destructors");
const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor();
if (!DtorDecl) {
static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
PostImplicitCall PP(nullptr, S->getEndLoc(), LCtx, &T);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(PP, Pred->getState(), Pred);
return;
}
if (!Dest) {
CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
if (const Expr *E = dyn_cast_or_null<Expr>(S)) {
Dest = MRMgr.getCXXTempObjectRegion(E, Pred->getLocationContext());
} else {
static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateSink(Pred->getLocation().withTag(&T),
Pred->getState(), Pred);
return;
}
}
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXDestructorCall> Call =
CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx);
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Call->getSourceRange().getBegin(),
"Error evaluating destructor");
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
*Call, *this);
ExplodedNodeSet DstInvalidated;
StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
defaultEvalCall(Bldr, *I, *Call, CallOpts);
getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
*Call, *this);
}
void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ProgramStateRef State = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
CNE->getBeginLoc(),
"Error evaluating New Allocator Call");
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXAllocatorCall> Call =
CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
*Call, *this);
ExplodedNodeSet DstPostCall;
StmtNodeBuilder CallBldr(DstPreCall, DstPostCall, *currBldrCtx);
for (ExplodedNode *I : DstPreCall) {
defaultEvalCall(CallBldr, I, *Call);
}
ExplodedNodeSet DstPostValue;
StmtNodeBuilder ValueBldr(DstPostCall, DstPostValue, *currBldrCtx);
for (ExplodedNode *I : DstPostCall) {
ProgramStateRef State = I->getState();
SVal RetVal = State->getSVal(CNE, LCtx);
if (const FunctionDecl *FD = CNE->getOperatorNew()) {
QualType Ty = FD->getType();
if (const auto *ProtoType = Ty->getAs<FunctionProtoType>())
if (!ProtoType->isNothrow())
State = State->assume(RetVal.castAs<DefinedOrUnknownSVal>(), true);
}
ValueBldr.generateNode(
CNE, I, addObjectUnderConstruction(State, CNE, LCtx, RetVal));
}
ExplodedNodeSet DstPostPostCallCallback;
getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
DstPostValue, *Call, *this);
for (ExplodedNode *I : DstPostPostCallCallback) {
getCheckerManager().runCheckersForNewAllocator(*Call, Dst, I, *this);
}
}
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
unsigned blockCount = currBldrCtx->blockCount();
const LocationContext *LCtx = Pred->getLocationContext();
SVal symVal = UnknownVal();
FunctionDecl *FD = CNE->getOperatorNew();
bool IsStandardGlobalOpNewFunction =
FD->isReplaceableGlobalAllocationFunction();
ProgramStateRef State = Pred->getState();
if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
symVal = *getObjectUnderConstruction(State, CNE, LCtx);
State = finishObjectConstruction(State, CNE, LCtx);
}
if (symVal.isUnknown()) {
if (IsStandardGlobalOpNewFunction)
symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
else
symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(),
blockCount);
}
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXAllocatorCall> Call =
CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
if (!AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
State = Call->invalidateRegions(blockCount);
if (!State)
return;
if (const auto *ProtoType = FD->getType()->getAs<FunctionProtoType>())
if (!ProtoType->isNothrow())
if (auto dSymVal = symVal.getAs<DefinedOrUnknownSVal>())
State = State->assume(*dSymVal, true);
}
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
SVal Result = symVal;
if (CNE->isArray()) {
if (const auto *NewReg = cast_or_null<SubRegion>(symVal.getAsRegion())) {
auto *Init = CNE->getInitializer();
bool isInitList = isa_and_nonnull<InitListExpr>(Init);
QualType ObjTy =
isInitList ? Init->getType() : CNE->getType()->getPointeeType();
const ElementRegion *EleReg =
MRMgr.getElementRegion(ObjTy, svalBuilder.makeArrayIndex(0), NewReg,
svalBuilder.getContext());
Result = loc::MemRegionVal(EleReg);
if (isInitList) {
Bldr.takeNodes(Pred);
Pred = Bldr.generateNode(CNE, Pred, State);
SVal V = State->getSVal(Init, LCtx);
ExplodedNodeSet evaluated;
evalBind(evaluated, CNE, Pred, Result, V, true);
Bldr.takeNodes(Pred);
Bldr.addNodes(evaluated);
Pred = *evaluated.begin();
State = Pred->getState();
}
}
State = State->BindExpr(CNE, Pred->getLocationContext(), Result);
Bldr.generateNode(CNE, Pred, State);
return;
}
if (FD->isReservedGlobalPlacementOperator()) {
SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx);
Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(),
CNE->getPlacementArg(0)->getType());
}
State = State->BindExpr(CNE, LCtx, Result);
ExplodedNode *NewN = Bldr.generateNode(CNE, Pred, State);
if (!NewN)
return;
if (const Expr *Init = CNE->getInitializer()) {
if (!isa<CXXConstructExpr>(Init)) {
assert(Bldr.getResults().size() == 1);
Bldr.takeNodes(NewN);
evalBind(Dst, CNE, NewN, Result, State->getSVal(Init, LCtx),
IsStandardGlobalOpNewFunction);
}
}
}
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXDeallocatorCall> Call = CEMgr.getCXXDeallocatorCall(
CDE, Pred->getState(), Pred->getLocationContext());
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this);
ExplodedNodeSet DstPostCall;
if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
StmtNodeBuilder Bldr(DstPreCall, DstPostCall, *currBldrCtx);
for (ExplodedNode *I : DstPreCall) {
defaultEvalCall(Bldr, I, *Call);
}
} else {
DstPostCall = DstPreCall;
}
getCheckerManager().runCheckersForPostCall(Dst, DstPostCall, *Call, *this);
}
void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
const VarDecl *VD = CS->getExceptionDecl();
if (!VD) {
Dst.Add(Pred);
return;
}
const LocationContext *LCtx = Pred->getLocationContext();
SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(),
currBldrCtx->blockCount());
ProgramStateRef state = Pred->getState();
state = state->bindLoc(state->getLValue(VD, LCtx), V, LCtx);
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(CS, Pred, state);
}
void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
const LocationContext *LCtx = Pred->getLocationContext();
const MemRegion *R =
svalBuilder.getRegionManager().getCXXThisRegion(
getContext().getCanonicalType(TE->getType()),
LCtx);
ProgramStateRef state = Pred->getState();
SVal V = state->getSVal(loc::MemRegionVal(R));
Bldr.generateNode(TE, Pred, state->BindExpr(TE, LCtx, V));
}
void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
const LocationContext *LocCtxt = Pred->getLocationContext();
const MemRegion *R = svalBuilder.getRegionManager().getCXXTempObjectRegion(
LE, LocCtxt);
SVal V = loc::MemRegionVal(R);
ProgramStateRef State = Pred->getState();
unsigned Idx = 0;
CXXRecordDecl::field_iterator CurField = LE->getLambdaClass()->field_begin();
for (LambdaExpr::const_capture_init_iterator i = LE->capture_init_begin(),
e = LE->capture_init_end();
i != e; ++i, ++CurField, ++Idx) {
FieldDecl *FieldForCapture = *CurField;
SVal FieldLoc = State->getLValue(FieldForCapture, V);
SVal InitVal;
if (!FieldForCapture->hasCapturedVLAType()) {
Expr *InitExpr = *i;
if (const auto AILE = dyn_cast<ArrayInitLoopExpr>(InitExpr)) {
if (dyn_cast<CXXConstructExpr>(AILE->getSubExpr()))
InitExpr = AILE->getSubExpr();
}
assert(InitExpr && "Capture missing initialization expression");
if (dyn_cast<CXXConstructExpr>(InitExpr)) {
InitVal = *getObjectUnderConstruction(State, {LE, Idx}, LocCtxt);
InitVal = State->getSVal(InitVal.getAsRegion());
State = finishObjectConstruction(State, {LE, Idx}, LocCtxt);
} else
InitVal = State->getSVal(InitExpr, LocCtxt);
} else {
assert(!getObjectUnderConstruction(State, {LE, Idx}, LocCtxt) &&
"VLA capture by value is a compile time error!");
Expr *SizeExpr = FieldForCapture->getCapturedVLAType()->getSizeExpr();
InitVal = State->getSVal(SizeExpr, LocCtxt);
}
State = State->bindLoc(FieldLoc, InitVal, LocCtxt);
}
SVal LambdaRVal = State->getSVal(R);
ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
Bldr.generateNode(LE, Pred,
State->BindExpr(LE, LocCtxt, LambdaRVal),
nullptr, ProgramPoint::PostLValueKind);
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this);
}