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 Checker<check::BeginFunction, check::EndFunction, check::PreCall> {
46 mutable std::unique_ptr<BugType> BT_Pure, BT_Impure;
47 bool ShowFixIts =
false;
54 void registerCtorDtorCallInState(
bool IsBeginFunction,
64 bool CallIsNonVirtual =
false;
66 if (
const MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
69 if (CME->getQualifier())
70 CallIsNonVirtual =
true;
72 if (
const Expr *
Base = CME->getBase()) {
74 if (
Base->getBestDynamicClassType()->hasAttr<FinalAttr>())
75 CallIsNonVirtual =
true;
80 dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
81 if (MD && MD->
isVirtual() && !CallIsNonVirtual && !MD->
hasAttr<FinalAttr>() &&
89 registerCtorDtorCallInState(
true,
C);
93void VirtualCallChecker::checkEndFunction(
const ReturnStmt *RS,
95 registerCtorDtorCallInState(
false,
C);
100 const auto MC = dyn_cast<CXXMemberCall>(&
Call);
110 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
114 const MemRegion *Reg = MC->getCXXThisVal().getAsRegion();
115 const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
124 llvm::raw_svector_ostream OS(Msg);
130 if (*ObState == ObjectState::CtorCalled)
131 OS <<
"construction ";
133 OS <<
"destruction ";
135 OS <<
"has undefined behavior";
137 OS <<
"bypasses virtual dispatch";
140 IsPure ?
C.generateErrorNode() :
C.generateNonFatalErrorNode();
144 const std::unique_ptr<BugType> &BT = IsPure ? BT_Pure : BT_Impure;
150 auto Report = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N);
152 if (ShowFixIts && !IsPure) {
159 Report->addFixItHint(Fixit);
162 C.emitReport(std::move(Report));
165void VirtualCallChecker::registerCtorDtorCallInState(
bool IsBeginFunction,
167 const auto *LCtx =
C.getLocationContext();
168 const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl());
173 auto &SVB =
C.getSValBuilder();
176 if (isa<CXXConstructorDecl>(MD)) {
178 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
179 const MemRegion *Reg = ThiSVal.getAsRegion();
181 State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled);
183 State = State->remove<CtorDtorMap>(Reg);
185 C.addTransition(State);
190 if (isa<CXXDestructorDecl>(MD)) {
192 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
193 const MemRegion *Reg = ThiSVal.getAsRegion();
195 State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled);
197 State = State->remove<CtorDtorMap>(Reg);
199 C.addTransition(State);
209 auto *Chk = Mgr.
getChecker<VirtualCallChecker>();
211 "Pure virtual method call",
216 auto *Chk = Mgr.
getChecker<VirtualCallChecker>();
219 Chk->BT_Impure = std::make_unique<BugType>(
227bool ento::shouldRegisterVirtualCallModeling(
const CheckerManager &mgr) {
232bool ento::shouldRegisterPureVirtualCallChecker(
const CheckerManager &mgr) {
237bool 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)
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
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]).
This represents one expression.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
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.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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...
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Represents an abstract call to a function or method along a particular path.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
const LangOptions & getLangOpts() const
CheckerNameRef getCurrentCheckerName() const
MemRegion - The root abstract class for all memory regions.
const char *const CXXObjectLifecycle
The JSON file list parser is used to communicate input to InstallAPI.
Diagnostic wrappers for TextAPI types for error reporting.
static void Profile(ObjectState X, FoldingSetNodeID &ID)