25 using namespace clang;
29 enum class ObjectState :
bool { CtorCalled, DtorCalled };
35 static inline void Profile(ObjectState
X, FoldingSetNodeID &
ID) {
36 ID.AddInteger(
static_cast<int>(
X));
42 class VirtualCallChecker
43 :
public Checker<check::BeginFunction, check::EndFunction, check::PreCall> {
46 mutable std::unique_ptr<BugType> BT_Pure, BT_Impure;
47 bool ShowFixIts =
false;
49 void checkBeginFunction(CheckerContext &C)
const;
50 void checkEndFunction(
const ReturnStmt *RS, CheckerContext &C)
const;
51 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
54 void registerCtorDtorCallInState(
bool IsBeginFunction,
55 CheckerContext &C)
const;
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>() &&
88 void VirtualCallChecker::checkBeginFunction(CheckerContext &C)
const {
89 registerCtorDtorCallInState(
true, C);
93 void VirtualCallChecker::checkEndFunction(
const ReturnStmt *RS,
94 CheckerContext &C)
const {
95 registerCtorDtorCallInState(
false, C);
98 void VirtualCallChecker::checkPreCall(
const CallEvent &Call,
99 CheckerContext &C)
const {
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);
119 bool IsPure = MD->
isPure();
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));
165 void VirtualCallChecker::registerCtorDtorCallInState(
bool IsBeginFunction,
166 CheckerContext &C)
const {
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);
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);
204 void ento::registerVirtualCallModeling(CheckerManager &Mgr) {
205 Mgr.registerChecker<VirtualCallChecker>();
208 void ento::registerPureVirtualCallChecker(CheckerManager &Mgr) {
209 auto *Chk = Mgr.getChecker<VirtualCallChecker>();
210 Chk->BT_Pure = std::make_unique<BugType>(Mgr.getCurrentCheckerName(),
211 "Pure virtual method call",
215 void ento::registerVirtualCallChecker(CheckerManager &Mgr) {
216 auto *Chk = Mgr.getChecker<VirtualCallChecker>();
217 if (!Mgr.getAnalyzerOptions().getCheckerBooleanOption(
218 Mgr.getCurrentCheckerName(),
"PureOnly")) {
219 Chk->BT_Impure = std::make_unique<BugType>(
220 Mgr.getCurrentCheckerName(),
"Unexpected loss of virtual dispatch",
222 Chk->ShowFixIts = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
223 Mgr.getCurrentCheckerName(),
"ShowFixIts");
227 bool ento::shouldRegisterVirtualCallModeling(
const CheckerManager &mgr) {
232 bool ento::shouldRegisterPureVirtualCallChecker(
const CheckerManager &mgr) {
237 bool ento::shouldRegisterVirtualCallChecker(
const CheckerManager &mgr) {