diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp | 287 |
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; -} |