25 using namespace clang;
36 ID.AddInteger(static_cast<int>(X));
42 class VirtualCallChecker
43 :
public Checker<check::BeginFunction, check::EndFunction, check::PreCall> {
44 mutable std::unique_ptr<BugType> BT;
48 DefaultBool IsPureOnly;
50 void checkBeginFunction(CheckerContext &C)
const;
51 void checkEndFunction(
const ReturnStmt *RS, CheckerContext &C)
const;
52 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
55 void registerCtorDtorCallInState(
bool IsBeginFunction,
56 CheckerContext &C)
const;
57 void reportBug(StringRef Msg,
bool PureError,
const MemRegion *Reg,
58 CheckerContext &C)
const;
62 const MemRegion *ObjectRegion;
66 VirtualBugVisitor(
const MemRegion *R) : ObjectRegion(R), Found(
false) {}
68 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
71 ID.AddPointer(ObjectRegion);
74 std::shared_ptr<PathDiagnosticPiece> VisitNode(
const ExplodedNode *N,
75 BugReporterContext &BRC,
76 BugReport &BR)
override;
84 std::shared_ptr<PathDiagnosticPiece>
85 VirtualCallChecker::VirtualBugVisitor::VisitNode(
const ExplodedNode *N,
86 BugReporterContext &BRC,
96 dyn_cast_or_null<CXXConstructorDecl>(LCtx->
getDecl());
98 dyn_cast_or_null<CXXDestructorDecl>(LCtx->
getDecl());
103 ProgramStateManager &PSM = State->getStateManager();
104 auto &SVB = PSM.getSValBuilder();
110 const MemRegion *Reg = ThiSVal.castAs<loc::MemRegionVal>().getRegion();
113 if (Reg != ObjectRegion)
121 std::string InfoText;
123 InfoText =
"This constructor of an object of type '" +
125 "' has not returned when the virtual method was called";
127 InfoText =
"This destructor of an object of type '" +
128 DD->getNameAsString() +
129 "' has not returned when the virtual method was called";
132 PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
133 N->getLocationContext());
134 return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText,
true);
139 bool CallIsNonVirtual =
false;
144 if (CME->getQualifier())
145 CallIsNonVirtual =
true;
147 if (
const Expr *
Base = CME->getBase()) {
149 if (
Base->getBestDynamicClassType()->hasAttr<FinalAttr>())
150 CallIsNonVirtual =
true;
156 if (MD && MD->
isVirtual() && !CallIsNonVirtual && !MD->
hasAttr<FinalAttr>() &&
163 void VirtualCallChecker::checkBeginFunction(CheckerContext &C)
const {
164 registerCtorDtorCallInState(
true, C);
168 void VirtualCallChecker::checkEndFunction(
const ReturnStmt *RS,
169 CheckerContext &C)
const {
170 registerCtorDtorCallInState(
false, C);
173 void VirtualCallChecker::checkPreCall(
const CallEvent &Call,
174 CheckerContext &C)
const {
179 const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
183 const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
185 if (IsPureOnly && !MD->
isPure())
190 const MemRegion *Reg = MC->getCXXThisVal().getAsRegion();
191 const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
196 if (*ObState == ObjectState::CtorCalled) {
197 if (IsPureOnly && MD->
isPure())
198 reportBug(
"Call to pure virtual function during construction",
true, Reg,
201 reportBug(
"Call to virtual function during construction",
false, Reg, C);
203 reportBug(
"Call to pure virtual function during construction",
false, Reg,
207 if (*ObState == ObjectState::DtorCalled) {
208 if (IsPureOnly && MD->
isPure())
209 reportBug(
"Call to pure virtual function during destruction",
true, Reg,
212 reportBug(
"Call to virtual function during destruction",
false, Reg, C);
214 reportBug(
"Call to pure virtual function during construction",
false, Reg,
219 void VirtualCallChecker::registerCtorDtorCallInState(
bool IsBeginFunction,
220 CheckerContext &C)
const {
221 const auto *LCtx = C.getLocationContext();
222 const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl());
227 auto &SVB = C.getSValBuilder();
230 if (isa<CXXConstructorDecl>(MD)) {
232 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
233 const MemRegion *Reg = ThiSVal.getAsRegion();
235 State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled);
237 State = State->remove<CtorDtorMap>(Reg);
239 C.addTransition(State);
244 if (isa<CXXDestructorDecl>(MD)) {
246 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
247 const MemRegion *Reg = ThiSVal.getAsRegion();
249 State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled);
251 State = State->remove<CtorDtorMap>(Reg);
253 C.addTransition(State);
258 void VirtualCallChecker::reportBug(StringRef Msg,
bool IsSink,
259 const MemRegion *Reg,
260 CheckerContext &C)
const {
263 N = C.generateErrorNode();
265 N = C.generateNonFatalErrorNode();
270 BT.reset(
new BugType(
271 this,
"Call to virtual function during construction or destruction",
272 "C++ Object Lifecycle"));
274 auto Reporter = llvm::make_unique<BugReport>(*BT, Msg, N);
275 Reporter->addVisitor(llvm::make_unique<VirtualBugVisitor>(Reg));
276 C.emitReport(std::move(Reporter));
279 void ento::registerVirtualCallChecker(CheckerManager &mgr) {
280 VirtualCallChecker *checker = mgr.registerChecker<VirtualCallChecker>();
282 checker->IsPureOnly =
283 mgr.getAnalyzerOptions().getCheckerBooleanOption(
"PureOnly",
false,
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
Stmt - This represents one statement.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Represents a C++ constructor within a class.
Represents a non-static C++ member function call.
static void Profile(ObjectState X, FoldingSetNodeID &ID)
This represents one expression.
Represents a C++ destructor within a class.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
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
Returns the parent of this method declaration, which is the class in which this method is defined...
const Decl * getDecl() const
const StackFrameContext * getStackFrame() const
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]).
static bool isVirtualCall(const CallExpr *CE)