29enum class ObjectState :
bool { CtorCalled, DtorCalled };
35 static inline void Profile(ObjectState
X, FoldingSetNodeID &ID) {
36 ID.AddInteger(
static_cast<int>(
X));
42class VirtualCallChecker
43 :
public CheckerFamily<check::BeginFunction, check::EndFunction,
46 CheckerFrontendWithBugType PureChecker{
"Pure virtual method call",
48 CheckerFrontendWithBugType ImpureChecker{
51 bool ShowFixIts =
false;
53 void checkBeginFunction(CheckerContext &
C)
const;
54 void checkEndFunction(
const ReturnStmt *RS, CheckerContext &
C)
const;
55 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
58 StringRef getDebugTag()
const override {
return "VirtualCallChecker"; }
61 void registerCtorDtorCallInState(
bool IsBeginFunction,
62 CheckerContext &
C)
const;
71 bool CallIsNonVirtual =
false;
73 if (
const MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
76 if (CME->getQualifier())
77 CallIsNonVirtual = true;
79 if (const Expr *Base = CME->getBase()) {
81 if (Base->getBestDynamicClassType()->hasAttr<FinalAttr>())
82 CallIsNonVirtual = true;
87 dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
88 if (MD && MD->
isVirtual() && !CallIsNonVirtual && !MD->
hasAttr<FinalAttr>() &&
96 registerCtorDtorCallInState(
true,
C);
100void VirtualCallChecker::checkEndFunction(
const ReturnStmt *RS,
101 CheckerContext &
C)
const {
102 registerCtorDtorCallInState(
false,
C);
105void VirtualCallChecker::checkPreCall(
const CallEvent &
Call,
106 CheckerContext &
C)
const {
107 const auto MC = dyn_cast<CXXMemberCall>(&
Call);
111 const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(
Call.getDecl());
123 if (
C.getSourceManager().isInSystemHeader(CE->getBeginLoc()))
126 const MemRegion *Reg = MC->getCXXThisVal().getAsRegion();
127 const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
135 SmallString<128> Msg;
136 llvm::raw_svector_ostream
OS(Msg);
142 if (*ObState == ObjectState::CtorCalled)
143 OS <<
"construction ";
145 OS <<
"destruction ";
147 OS <<
"has undefined behavior";
149 OS <<
"bypasses virtual dispatch";
152 IsPure ?
C.generateErrorNode() :
C.generateNonFatalErrorNode();
156 const CheckerFrontendWithBugType &Part = IsPure ? PureChecker : ImpureChecker;
163 auto Report = std::make_unique<PathSensitiveBugReport>(Part,
OS.str(), N);
165 if (ShowFixIts && !IsPure) {
172 Report->addFixItHint(Fixit);
175 C.emitReport(std::move(
Report));
178void VirtualCallChecker::registerCtorDtorCallInState(
bool IsBeginFunction,
179 CheckerContext &
C)
const {
180 const auto *LCtx =
C.getLocationContext();
181 const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl());
186 auto &SVB =
C.getSValBuilder();
191 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
192 const MemRegion *Reg = ThiSVal.getAsRegion();
194 State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled);
196 State = State->remove<CtorDtorMap>(Reg);
198 C.addTransition(State);
205 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
206 const MemRegion *Reg = ThiSVal.getAsRegion();
208 State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled);
210 State = State->remove<CtorDtorMap>(Reg);
212 C.addTransition(State);
217void ento::registerPureVirtualCallChecker(CheckerManager &Mgr) {
218 Mgr.
getChecker<VirtualCallChecker>()->PureChecker.enable(Mgr);
221bool ento::shouldRegisterPureVirtualCallChecker(
const CheckerManager &Mgr) {
225void ento::registerVirtualCallChecker(CheckerManager &Mgr) {
226 auto *Chk = Mgr.
getChecker<VirtualCallChecker>();
227 Chk->ImpureChecker.enable(Mgr);
232bool ento::shouldRegisterVirtualCallChecker(
const CheckerManager &Mgr) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
static bool isVirtualCall(const CallExpr *CE)
Represents a static or instance method of a struct/union/class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
bool isPureVirtual() const
Whether this virtual function is pure, i.e.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Checker families (where a single backend class implements multiple related frontends) should derive f...
const AnalyzerOptions & getAnalyzerOptions() const
const LangOptions & getLangOpts() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
MemRegion - The root abstract class for all memory regions.
const char *const CXXObjectLifecycle
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.
static void Profile(ObjectState X, FoldingSetNodeID &ID)