25 using namespace clang;
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 {
104 const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
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);
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);
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 LangOptions &LO) {
231 bool ento::shouldRegisterPureVirtualCallChecker(
const LangOptions &LO) {
235 bool ento::shouldRegisterVirtualCallChecker(
const LangOptions &LO) {
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Represents a non-static C++ member function call.
static void Profile(ObjectState X, FoldingSetNodeID &ID)
This represents one expression.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
bool isPure() const
Whether this virtual function is pure, i.e.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
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...
Represents a static or instance method of a struct/union/class.
Dataflow Directional Tag Classes.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined...
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
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.
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
const char *const CXXObjectLifecycle
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
static bool isVirtualCall(const CallExpr *CE)