aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp287
1 files changed, 0 insertions, 287 deletions
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
deleted file mode 100644
index 762c9c1c8d7a..000000000000
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
-//=======- VirtualCallChecker.cpp --------------------------------*- C++ -*-==//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a checker that checks virtual function calls during
-// construction or destruction of C++ objects.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-enum class ObjectState : bool { CtorCalled, DtorCalled };
-} // end namespace
- // FIXME: Ascending over StackFrameContext maybe another method.
-
-namespace llvm {
-template <> struct FoldingSetTrait<ObjectState> {
- static inline void Profile(ObjectState X, FoldingSetNodeID &ID) {
- ID.AddInteger(static_cast<int>(X));
- }
-};
-} // end namespace llvm
-
-namespace {
-class VirtualCallChecker
- : public Checker<check::BeginFunction, check::EndFunction, check::PreCall> {
- mutable std::unique_ptr<BugType> BT;
-
-public:
- // The flag to determine if pure virtual functions should be issued only.
- DefaultBool IsPureOnly;
-
- void checkBeginFunction(CheckerContext &C) const;
- void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
-
-private:
- void registerCtorDtorCallInState(bool IsBeginFunction,
- CheckerContext &C) const;
- void reportBug(StringRef Msg, bool PureError, const MemRegion *Reg,
- CheckerContext &C) const;
-
- class VirtualBugVisitor : public BugReporterVisitor {
- private:
- const MemRegion *ObjectRegion;
- bool Found;
-
- public:
- VirtualBugVisitor(const MemRegion *R) : ObjectRegion(R), Found(false) {}
-
- void Profile(llvm::FoldingSetNodeID &ID) const override {
- static int X = 0;
- ID.AddPointer(&X);
- ID.AddPointer(ObjectRegion);
- }
-
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
- };
-};
-} // end namespace
-
-// GDM (generic data map) to the memregion of this for the ctor and dtor.
-REGISTER_MAP_WITH_PROGRAMSTATE(CtorDtorMap, const MemRegion *, ObjectState)
-
-std::shared_ptr<PathDiagnosticPiece>
-VirtualCallChecker::VirtualBugVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &) {
- // We need the last ctor/dtor which call the virtual function.
- // The visitor walks the ExplodedGraph backwards.
- if (Found)
- return nullptr;
-
- ProgramStateRef State = N->getState();
- const LocationContext *LCtx = N->getLocationContext();
- const CXXConstructorDecl *CD =
- dyn_cast_or_null<CXXConstructorDecl>(LCtx->getDecl());
- const CXXDestructorDecl *DD =
- dyn_cast_or_null<CXXDestructorDecl>(LCtx->getDecl());
-
- if (!CD && !DD)
- return nullptr;
-
- ProgramStateManager &PSM = State->getStateManager();
- auto &SVB = PSM.getSValBuilder();
- const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
- if (!MD)
- return nullptr;
- auto ThiSVal =
- State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
- const MemRegion *Reg = ThiSVal.castAs<loc::MemRegionVal>().getRegion();
- if (!Reg)
- return nullptr;
- if (Reg != ObjectRegion)
- return nullptr;
-
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
- if (!S)
- return nullptr;
- Found = true;
-
- std::string InfoText;
- if (CD)
- InfoText = "This constructor of an object of type '" +
- CD->getNameAsString() +
- "' has not returned when the virtual method was called";
- else
- InfoText = "This destructor of an object of type '" +
- DD->getNameAsString() +
- "' has not returned when the virtual method was called";
-
- // Generate the extra diagnostic.
- PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
- N->getLocationContext());
- return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText, true);
-}
-
-// The function to check if a callexpr is a virtual function.
-static bool isVirtualCall(const CallExpr *CE) {
- bool CallIsNonVirtual = false;
-
- if (const MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
- // The member access is fully qualified (i.e., X::F).
- // Treat this as a non-virtual call and do not warn.
- if (CME->getQualifier())
- CallIsNonVirtual = true;
-
- if (const Expr *Base = CME->getBase()) {
- // The most derived class is marked final.
- if (Base->getBestDynamicClassType()->hasAttr<FinalAttr>())
- CallIsNonVirtual = true;
- }
- }
-
- const CXXMethodDecl *MD =
- dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
- if (MD && MD->isVirtual() && !CallIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
- !MD->getParent()->hasAttr<FinalAttr>())
- return true;
- return false;
-}
-
-// The BeginFunction callback when enter a constructor or a destructor.
-void VirtualCallChecker::checkBeginFunction(CheckerContext &C) const {
- registerCtorDtorCallInState(true, C);
-}
-
-// The EndFunction callback when leave a constructor or a destructor.
-void VirtualCallChecker::checkEndFunction(const ReturnStmt *RS,
- CheckerContext &C) const {
- registerCtorDtorCallInState(false, C);
-}
-
-void VirtualCallChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
- const auto MC = dyn_cast<CXXMemberCall>(&Call);
- if (!MC)
- return;
-
- const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
- if (!MD)
- return;
- ProgramStateRef State = C.getState();
- const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
-
- if (IsPureOnly && !MD->isPure())
- return;
- if (!isVirtualCall(CE))
- return;
-
- const MemRegion *Reg = MC->getCXXThisVal().getAsRegion();
- const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
- if (!ObState)
- return;
- // Check if a virtual method is called.
- // The GDM of constructor and destructor should be true.
- if (*ObState == ObjectState::CtorCalled) {
- if (IsPureOnly && MD->isPure())
- reportBug("Call to pure virtual function during construction", true, Reg,
- C);
- else if (!MD->isPure())
- reportBug("Call to virtual function during construction", false, Reg, C);
- else
- reportBug("Call to pure virtual function during construction", false, Reg,
- C);
- }
-
- if (*ObState == ObjectState::DtorCalled) {
- if (IsPureOnly && MD->isPure())
- reportBug("Call to pure virtual function during destruction", true, Reg,
- C);
- else if (!MD->isPure())
- reportBug("Call to virtual function during destruction", false, Reg, C);
- else
- reportBug("Call to pure virtual function during construction", false, Reg,
- C);
- }
-}
-
-void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction,
- CheckerContext &C) const {
- const auto *LCtx = C.getLocationContext();
- const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl());
- if (!MD)
- return;
-
- ProgramStateRef State = C.getState();
- auto &SVB = C.getSValBuilder();
-
- // Enter a constructor, set the corresponding memregion be true.
- if (isa<CXXConstructorDecl>(MD)) {
- auto ThiSVal =
- State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
- const MemRegion *Reg = ThiSVal.getAsRegion();
- if (IsBeginFunction)
- State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled);
- else
- State = State->remove<CtorDtorMap>(Reg);
-
- C.addTransition(State);
- return;
- }
-
- // Enter a Destructor, set the corresponding memregion be true.
- if (isa<CXXDestructorDecl>(MD)) {
- auto ThiSVal =
- State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
- const MemRegion *Reg = ThiSVal.getAsRegion();
- if (IsBeginFunction)
- State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled);
- else
- State = State->remove<CtorDtorMap>(Reg);
-
- C.addTransition(State);
- return;
- }
-}
-
-void VirtualCallChecker::reportBug(StringRef Msg, bool IsSink,
- const MemRegion *Reg,
- CheckerContext &C) const {
- ExplodedNode *N;
- if (IsSink)
- N = C.generateErrorNode();
- else
- N = C.generateNonFatalErrorNode();
-
- if (!N)
- return;
- if (!BT)
- BT.reset(new BugType(
- this, "Call to virtual function during construction or destruction",
- "C++ Object Lifecycle"));
-
- auto Reporter = llvm::make_unique<BugReport>(*BT, Msg, N);
- Reporter->addVisitor(llvm::make_unique<VirtualBugVisitor>(Reg));
- C.emitReport(std::move(Reporter));
-}
-
-void ento::registerVirtualCallChecker(CheckerManager &mgr) {
- VirtualCallChecker *checker = mgr.registerChecker<VirtualCallChecker>();
-
- checker->IsPureOnly =
- mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "PureOnly");
-}
-
-bool ento::shouldRegisterVirtualCallChecker(const LangOptions &LO) {
- return true;
-}