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(
const ReturnStmt *RS,
172 registerCtorDtorCallInState(
false, C);
175 void VirtualCallChecker::checkPreCall(
const CallEvent &Call,
187 if (IsPureOnly && !MD->
isPure())
192 const MemRegion *Reg = MC->getCXXThisVal().getAsRegion();
193 const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
198 if (*ObState == ObjectState::CtorCalled) {
199 if (IsPureOnly && MD->
isPure())
200 reportBug(
"Call to pure virtual function during construction",
true, Reg,
203 reportBug(
"Call to virtual function during construction",
false, Reg, C);
205 reportBug(
"Call to pure virtual function during construction",
false, Reg,
209 if (*ObState == ObjectState::DtorCalled) {
210 if (IsPureOnly && MD->
isPure())
211 reportBug(
"Call to pure virtual function during destruction",
true, Reg,
214 reportBug(
"Call to virtual function during destruction",
false, Reg, C);
216 reportBug(
"Call to pure virtual function during construction",
false, Reg,
221 void VirtualCallChecker::registerCtorDtorCallInState(
bool IsBeginFunction,
224 const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl());
232 if (isa<CXXConstructorDecl>(MD)) {
234 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
235 const MemRegion *Reg = ThiSVal.getAsRegion();
237 State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled);
239 State = State->remove<CtorDtorMap>(Reg);
246 if (isa<CXXDestructorDecl>(MD)) {
248 State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
249 const MemRegion *Reg = ThiSVal.getAsRegion();
251 State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled);
253 State = State->remove<CtorDtorMap>(Reg);
260 void VirtualCallChecker::reportBug(StringRef Msg,
bool IsSink,
273 this,
"Call to virtual function during construction or destruction",
274 "C++ Object Lifecycle"));
276 auto Reporter = llvm::make_unique<BugReport>(*BT, Msg, N);
277 Reporter->addVisitor(llvm::make_unique<VirtualBugVisitor>(Reg));
282 VirtualCallChecker *checker = mgr.
registerChecker<VirtualCallChecker>();
284 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.
SValBuilder & getSValBuilder()
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.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
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.
CHECKER * registerChecker(AT... Args)
Used to register checkers.
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...
bool isPure() const
Whether this virtual function is pure, i.e.
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.
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
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.
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()