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;
55 void registerCtorDtorCallInState(
bool IsBeginFunction,
57 void reportBug(StringRef Msg,
bool PureError,
const MemRegion *Reg,
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,
85 std::shared_ptr<PathDiagnosticPiece>
86 VirtualCallChecker::VirtualBugVisitor::VisitNode(
const ExplodedNode *N,
98 dyn_cast_or_null<CXXConstructorDecl>(LCtx->
getDecl());
100 dyn_cast_or_null<CXXDestructorDecl>(LCtx->
getDecl());
115 if (Reg != ObjectRegion)
123 std::string InfoText;
125 InfoText =
"This constructor of an object of type '" +
127 "' has not returned when the virtual method was called";
129 InfoText =
"This destructor of an object of type '" +
130 DD->getNameAsString() +
131 "' has not returned when the virtual method was called";
136 return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText,
true);
141 bool CallIsNonVirtual =
false;
146 if (CME->getQualifier())
147 CallIsNonVirtual =
true;
149 if (
const Expr *
Base = CME->getBase()) {
151 if (
Base->getBestDynamicClassType()->hasAttr<FinalAttr>())
152 CallIsNonVirtual =
true;
158 if (MD && MD->
isVirtual() && !CallIsNonVirtual && !MD->
hasAttr<FinalAttr>() &&
165 void VirtualCallChecker::checkBeginFunction(
CheckerContext &C)
const {
166 registerCtorDtorCallInState(
true, C);
170 void VirtualCallChecker::checkEndFunction(
CheckerContext &C)
const {
171 registerCtorDtorCallInState(
false, C);
174 void VirtualCallChecker::checkPreCall(
const CallEvent &Call,
186 if (IsPureOnly && !MD->
isPure())
191 const MemRegion *Reg = MC->getCXXThisVal().getAsRegion();
192 const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
197 if (*ObState == ObjectState::CtorCalled) {
198 if (IsPureOnly && MD->
isPure())
199 reportBug(
"Call to pure virtual function during construction",
true, Reg,
202 reportBug(
"Call to virtual function during construction",
false, Reg, C);
204 reportBug(
"Call to pure virtual function during construction",
false, Reg,
208 if (*ObState == ObjectState::DtorCalled) {
209 if (IsPureOnly && MD->
isPure())
210 reportBug(
"Call to pure virtual function during destruction",
true, Reg,
213 reportBug(
"Call to virtual function during destruction",
false, Reg, C);
215 reportBug(
"Call to pure virtual function during construction",
false, Reg,
220 void VirtualCallChecker::registerCtorDtorCallInState(
bool IsBeginFunction,
223 const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl());
231 if (isa<CXXConstructorDecl>(MD)) {
233 State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame()));
234 const MemRegion *Reg = ThiSVal.getAsRegion();
236 State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled);
238 State = State->remove<CtorDtorMap>(Reg);
245 if (isa<CXXDestructorDecl>(MD)) {
247 State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame()));
248 const MemRegion *Reg = ThiSVal.getAsRegion();
250 State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled);
252 State = State->remove<CtorDtorMap>(Reg);
259 void VirtualCallChecker::reportBug(StringRef Msg,
bool IsSink,
272 this,
"Call to virtual function during construction or destruction",
273 "C++ Object Lifecycle"));
275 auto Reporter = llvm::make_unique<BugReport>(*BT, Msg, N);
276 Reporter->addVisitor(llvm::make_unique<VirtualBugVisitor>(Reg));
281 VirtualCallChecker *checker = mgr.
registerChecker<VirtualCallChecker>();
283 checker->IsPureOnly =
MemRegion - The root abstract class for all memory regions.
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
Stmt - This represents one statement.
A helper class which wraps a boolean value set to false by default.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
const ProgramStateRef & getState() const
Represents a C++ constructor within a class.
const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
This class provides a convenience implementation for clone() using the Curiously-Recurring Template P...
SValBuilder & getSValBuilder()
const StackFrameContext * getCurrentStackFrame() const
const LocationContext * getLocationContext() const
Represents a non-static C++ member function call.
static void Profile(ObjectState X, FoldingSetNodeID &ID)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Expr - This represents one expression.
Represents a C++ destructor within a class.
const Expr * getCallee() const
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called.
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
bool getBooleanOption(StringRef Name, bool DefaultVal, const ento::CheckerBase *C=nullptr, bool SearchInParents=false)
Interprets an option's string value as a boolean.
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
CHECKER * registerChecker()
Used to register checkers.
bool isPure() const
Whether this virtual function is pure, i.e.
std::string getNameAsString() const
getNameAsString - Get a human-readable name for the declaration, even if it is one of the special kin...
Represents a static or instance method of a struct/union/class.
Dataflow Directional Tag Classes.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
const CXXRecordDecl * getParent() const
Returns the parent of this method declaration, which is the class in which this method is defined...
Represents an abstract call to a function or method along a particular path.
AnalyzerOptions & getAnalyzerOptions()
const Decl * getDecl() const
const ProgramStateRef & getState() 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.
SValBuilder & getSValBuilder()
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
This class provides an interface through which checkers can create individual bug reports...
static bool isVirtualCall(const CallExpr *CE)
const LocationContext * getLocationContext() const
SourceManager & getSourceManager()