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());
121 const MemRegion *Reg = MC->getCXXThisVal().getAsRegion();
122 const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
130 SmallString<128> Msg;
131 llvm::raw_svector_ostream
OS(Msg);
137 if (*ObState == ObjectState::CtorCalled)
138 OS <<
"construction ";
140 OS <<
"destruction ";
142 OS <<
"has undefined behavior";
144 OS <<
"bypasses virtual dispatch";
147 IsPure ?
C.generateErrorNode() :
C.generateNonFatalErrorNode();
151 const CheckerFrontendWithBugType &Part = IsPure ? PureChecker : ImpureChecker;
158 auto Report = std::make_unique<PathSensitiveBugReport>(Part,
OS.str(), N);
160 if (ShowFixIts && !IsPure) {
167 Report->addFixItHint(Fixit);
170 C.emitReport(std::move(
Report));
173void VirtualCallChecker::registerCtorDtorCallInState(
bool IsBeginFunction,
174 CheckerContext &
C)
const {
175 const auto *LCtx =
C.getLocationContext();
176 const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl());
181 auto &SVB =
C.getSValBuilder();
186 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
187 const MemRegion *Reg = ThiSVal.getAsRegion();
189 State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled);
191 State = State->remove<CtorDtorMap>(Reg);
193 C.addTransition(State);
200 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
201 const MemRegion *Reg = ThiSVal.getAsRegion();
203 State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled);
205 State = State->remove<CtorDtorMap>(Reg);
207 C.addTransition(State);
212void ento::registerPureVirtualCallChecker(CheckerManager &Mgr) {
213 Mgr.
getChecker<VirtualCallChecker>()->PureChecker.enable(Mgr);
216bool ento::shouldRegisterPureVirtualCallChecker(
const CheckerManager &Mgr) {
220void ento::registerVirtualCallChecker(CheckerManager &Mgr) {
221 auto *Chk = Mgr.
getChecker<VirtualCallChecker>();
222 Chk->ImpureChecker.enable(Mgr);
227bool 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)