aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-27 19:50:45 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-27 19:50:54 +0000
commit08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (patch)
tree041e72e32710b1e742516d8c9f1575bf0116d3e3 /clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
parent4b4fe385e49bd883fd183b5f21c1ea486c722e61 (diff)
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp91
1 files changed, 77 insertions, 14 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index d8f56f2f8cff..19149d079822 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -196,6 +196,14 @@ typedef llvm::ImmutableMap<
IndexOfElementToConstructMap;
REGISTER_TRAIT_WITH_PROGRAMSTATE(IndexOfElementToConstruct,
IndexOfElementToConstructMap)
+
+// This trait is responsible for holding our pending ArrayInitLoopExprs.
+// It pairs the LocationContext and the initializer CXXConstructExpr with
+// the size of the array that's being copy initialized.
+typedef llvm::ImmutableMap<
+ std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned>
+ PendingInitLoopMap;
+REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingInitLoop, PendingInitLoopMap)
//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
@@ -462,6 +470,34 @@ ProgramStateRef ExprEngine::setIndexOfElementToConstruct(
return State->set<IndexOfElementToConstruct>(Key, Idx);
}
+Optional<unsigned> ExprEngine::getPendingInitLoop(ProgramStateRef State,
+ const CXXConstructExpr *E,
+ const LocationContext *LCtx) {
+
+ return Optional<unsigned>::create(
+ State->get<PendingInitLoop>({E, LCtx->getStackFrame()}));
+}
+
+ProgramStateRef ExprEngine::removePendingInitLoop(ProgramStateRef State,
+ const CXXConstructExpr *E,
+ const LocationContext *LCtx) {
+ auto Key = std::make_pair(E, LCtx->getStackFrame());
+
+ assert(E && State->contains<PendingInitLoop>(Key));
+ return State->remove<PendingInitLoop>(Key);
+}
+
+ProgramStateRef ExprEngine::setPendingInitLoop(ProgramStateRef State,
+ const CXXConstructExpr *E,
+ const LocationContext *LCtx,
+ unsigned Size) {
+ auto Key = std::make_pair(E, LCtx->getStackFrame());
+
+ assert(!State->contains<PendingInitLoop>(Key) && Size > 0);
+
+ return State->set<PendingInitLoop>(Key, Size);
+}
+
Optional<unsigned>
ExprEngine::getIndexOfElementToConstruct(ProgramStateRef State,
const CXXConstructExpr *E,
@@ -487,17 +523,23 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
const LocationContext *LC, SVal V) {
ConstructedObjectKey Key(Item, LC->getStackFrame());
- const CXXConstructExpr *E = nullptr;
+ const Expr *Init = nullptr;
if (auto DS = dyn_cast_or_null<DeclStmt>(Item.getStmtOrNull())) {
if (auto VD = dyn_cast_or_null<VarDecl>(DS->getSingleDecl()))
- E = dyn_cast<CXXConstructExpr>(VD->getInit());
+ Init = VD->getInit();
}
- if (!E && !Item.getStmtOrNull()) {
- auto CtorInit = Item.getCXXCtorInitializer();
- E = dyn_cast<CXXConstructExpr>(CtorInit->getInit());
- }
+ if (auto LE = dyn_cast_or_null<LambdaExpr>(Item.getStmtOrNull()))
+ Init = *(LE->capture_init_begin() + Item.getIndex());
+
+ if (!Init && !Item.getStmtOrNull())
+ Init = Item.getCXXCtorInitializer()->getInit();
+
+ // In an ArrayInitLoopExpr the real initializer is returned by
+ // getSubExpr().
+ if (const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init))
+ Init = AILE->getSubExpr();
// FIXME: Currently the state might already contain the marker due to
// incorrect handling of temporaries bound to default parameters.
@@ -508,7 +550,8 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
assert((!State->get<ObjectsUnderConstruction>(Key) ||
Key.getItem().getKind() ==
ConstructionContextItem::TemporaryDestructorKind ||
- State->contains<IndexOfElementToConstruct>({E, LC})) &&
+ State->contains<IndexOfElementToConstruct>(
+ {dyn_cast_or_null<CXXConstructExpr>(Init), LC})) &&
"The object is already marked as `UnderConstruction`, when it's not "
"supposed to!");
return State->set<ObjectsUnderConstruction>(Key, V);
@@ -2744,7 +2787,10 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
SVal Base = state->getLValue(DD, LCtx);
if (DD->getType()->isReferenceType()) {
- Base = state->getSVal(Base.getAsRegion());
+ if (const MemRegion *R = Base.getAsRegion())
+ Base = state->getSVal(R);
+ else
+ Base = UnknownVal();
}
SVal V = UnknownVal();
@@ -2765,15 +2811,27 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
V = state->getLValue(BD->getType(), Idx, Base);
}
- // Handle binding to tuple-like strcutures
- else if (BD->getHoldingVar()) {
- // FIXME: handle tuples
- return;
+ // Handle binding to tuple-like structures
+ else if (const auto *HV = BD->getHoldingVar()) {
+ V = state->getLValue(HV, LCtx);
+
+ if (HV->getType()->isReferenceType()) {
+ if (const MemRegion *R = V.getAsRegion())
+ V = state->getSVal(R);
+ else
+ V = UnknownVal();
+ }
} else
llvm_unreachable("An unknown case of structured binding encountered!");
- if (BD->getType()->isReferenceType())
- V = state->getSVal(V.getAsRegion());
+ // In case of tuple-like types the references are already handled, so we
+ // don't want to handle them again.
+ if (BD->getType()->isReferenceType() && !BD->getHoldingVar()) {
+ if (const MemRegion *R = V.getAsRegion())
+ V = state->getSVal(R);
+ else
+ V = UnknownVal();
+ }
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
ProgramPoint::PostLValueKind);
@@ -2797,6 +2855,11 @@ void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex,
const Expr *Arr = Ex->getCommonExpr()->getSourceExpr();
for (auto *Node : CheckerPreStmt) {
+
+ // The constructor visitior has already taken care of everything.
+ if (auto *CE = dyn_cast<CXXConstructExpr>(Ex->getSubExpr()))
+ break;
+
const LocationContext *LCtx = Node->getLocationContext();
ProgramStateRef state = Node->getState();