summaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/CoreEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core/CoreEngine.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp63
1 files changed, 57 insertions, 6 deletions
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 196854cb09da..94cf74de8293 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -1,9 +1,8 @@
//===- CoreEngine.cpp - Path-Sensitive Dataflow Engine --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -217,6 +216,25 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
LC->getDecl(),
LC->getCFG()->getNumBlockIDs());
+ // Display a prunable path note to the user if it's a virtual bases branch
+ // and we're taking the path that skips virtual base constructors.
+ if (L.getSrc()->getTerminator().isVirtualBaseBranch() &&
+ L.getDst() == *L.getSrc()->succ_begin()) {
+ ProgramPoint P = L.withTag(getNoteTags().makeNoteTag(
+ [](BugReporterContext &, BugReport &) -> std::string {
+ // TODO: Just call out the name of the most derived class
+ // when we know it.
+ return "Virtual base initialization skipped because "
+ "it has already been handled by the most derived class";
+ }, /*IsPrunable=*/true));
+ // Perform the transition.
+ ExplodedNodeSet Dst;
+ NodeBuilder Bldr(Pred, Dst, BuilderCtx);
+ Pred = Bldr.generateNode(P, Pred->getState(), Pred);
+ if (!Pred)
+ return;
+ }
+
// Check if we are entering the EXIT block.
if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
assert(L.getLocationContext()->getCFG()->getExit().empty() &&
@@ -276,14 +294,14 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
}
void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
- if (const Stmt *Term = B->getTerminator()) {
+ if (const Stmt *Term = B->getTerminatorStmt()) {
switch (Term->getStmtClass()) {
default:
llvm_unreachable("Analysis for this terminator not implemented.");
case Stmt::CXXBindTemporaryExprClass:
HandleCleanupTemporaryBranch(
- cast<CXXBindTemporaryExpr>(B->getTerminator().getStmt()), B, Pred);
+ cast<CXXBindTemporaryExpr>(Term), B, Pred);
return;
// Model static initializers.
@@ -378,9 +396,19 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
case Stmt::WhileStmtClass:
HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
return;
+
+ case Stmt::GCCAsmStmtClass:
+ assert(cast<GCCAsmStmt>(Term)->isAsmGoto() && "Encountered GCCAsmStmt without labels");
+ // TODO: Handle jumping to labels
+ return;
}
}
+ if (B->getTerminator().isVirtualBaseBranch()) {
+ HandleVirtualBaseBranch(B, Pred);
+ return;
+ }
+
assert(B->succ_size() == 1 &&
"Blocks with no terminator should have at most 1 successor.");
@@ -440,6 +468,29 @@ void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
}
}
+void CoreEngine::HandleVirtualBaseBranch(const CFGBlock *B,
+ ExplodedNode *Pred) {
+ const LocationContext *LCtx = Pred->getLocationContext();
+ if (const auto *CallerCtor = dyn_cast_or_null<CXXConstructExpr>(
+ LCtx->getStackFrame()->getCallSite())) {
+ switch (CallerCtor->getConstructionKind()) {
+ case CXXConstructExpr::CK_NonVirtualBase:
+ case CXXConstructExpr::CK_VirtualBase: {
+ BlockEdge Loc(B, *B->succ_begin(), LCtx);
+ HandleBlockEdge(Loc, Pred);
+ return;
+ }
+ default:
+ break;
+ }
+ }
+
+ // We either don't see a parent stack frame because we're in the top frame,
+ // or the parent stack frame doesn't initialize our virtual bases.
+ BlockEdge Loc(B, *(B->succ_begin() + 1), LCtx);
+ HandleBlockEdge(Loc, Pred);
+}
+
/// generateNode - Utility method to generate nodes, hook up successors,
/// and add nodes to the worklist.
void CoreEngine::generateNode(const ProgramPoint &Loc,