42class CXXDeleteChecker :
public Checker<check::PreStmt<CXXDeleteExpr>> {
44 class PtrCastVisitor :
public BugReporterVisitor {
46 void Profile(llvm::FoldingSetNodeID &ID)
const override {
51 BugReporterContext &BRC,
52 PathSensitiveBugReport &BR)
override;
56 checkTypedDeleteExpr(
const CXXDeleteExpr *DE, CheckerContext &
C,
57 const TypedValueRegion *BaseClassRegion,
58 const SymbolicRegion *DerivedClassRegion)
const = 0;
61 void checkPreStmt(
const CXXDeleteExpr *DE, CheckerContext &
C)
const;
64class DeleteWithNonVirtualDtorChecker :
public CXXDeleteChecker {
66 this,
"Destruction of a polymorphic object with no virtual destructor"};
69 checkTypedDeleteExpr(
const CXXDeleteExpr *DE, CheckerContext &
C,
70 const TypedValueRegion *BaseClassRegion,
71 const SymbolicRegion *DerivedClassRegion)
const override;
74class CXXArrayDeleteChecker :
public CXXDeleteChecker {
75 const BugType BT{
this,
76 "Deleting an array of polymorphic objects is undefined"};
79 checkTypedDeleteExpr(
const CXXDeleteExpr *DE, CheckerContext &
C,
80 const TypedValueRegion *BaseClassRegion,
81 const SymbolicRegion *DerivedClassRegion)
const override;
88 const MemRegion *MR =
C.getSVal(DeletedObj).getAsRegion();
95 if (DeleteKind != OO_Delete && DeleteKind != OO_Array_Delete)
98 const auto *BaseClassRegion = MR->
getAs<TypedValueRegion>();
100 if (!BaseClassRegion || !DerivedClassRegion)
103 checkTypedDeleteExpr(DE,
C, BaseClassRegion, DerivedClassRegion);
106void DeleteWithNonVirtualDtorChecker::checkTypedDeleteExpr(
107 const CXXDeleteExpr *DE, CheckerContext &
C,
108 const TypedValueRegion *BaseClassRegion,
109 const SymbolicRegion *DerivedClassRegion)
const {
111 const auto *DerivedClass =
113 if (!BaseClass || !DerivedClass)
116 if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition())
119 if (BaseClass->getDestructor()->isVirtual())
122 if (!DerivedClass->isDerivedFrom(BaseClass))
125 ExplodedNode *N =
C.generateNonFatalErrorNode();
128 auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.
getDescription(), N);
131 R->markInteresting(BaseClassRegion);
132 R->addVisitor<PtrCastVisitor>();
133 C.emitReport(std::move(R));
136void CXXArrayDeleteChecker::checkTypedDeleteExpr(
137 const CXXDeleteExpr *DE, CheckerContext &
C,
138 const TypedValueRegion *BaseClassRegion,
139 const SymbolicRegion *DerivedClassRegion)
const {
141 const auto *DerivedClass =
143 if (!BaseClass || !DerivedClass)
146 if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition())
152 if (!DerivedClass->isDerivedFrom(BaseClass))
155 ExplodedNode *N =
C.generateNonFatalErrorNode();
159 SmallString<256> Buf;
160 llvm::raw_svector_ostream
OS(Buf);
163 QualType TargetType =
167 <<
"' objects as their base class '"
168 << SourceType.
getAsString(
C.getASTContext().getPrintingPolicy())
171 auto R = std::make_unique<PathSensitiveBugReport>(BT,
OS.str(), N);
174 R->markInteresting(BaseClassRegion);
175 R->addVisitor<PtrCastVisitor>();
176 C.emitReport(std::move(R));
180CXXDeleteChecker::PtrCastVisitor::VisitNode(
const ExplodedNode *N,
181 BugReporterContext &BRC,
182 PathSensitiveBugReport &BR) {
187 const auto *CastE = dyn_cast<CastExpr>(S);
192 QualType SourceType = CastE->getSubExpr()->getType()->
getPointeeType();
195 if (SourceType.
isNull() || TargetType.
isNull() || SourceType == TargetType)
207 SmallString<256> Buf;
208 llvm::raw_svector_ostream
OS(Buf);
210 OS <<
"Casting from '" << SourceType.
getAsString() <<
"' to '"
215 return std::make_shared<PathDiagnosticEventPiece>(Pos,
OS.str(),
219void ento::registerArrayDeleteChecker(CheckerManager &mgr) {
223bool ento::shouldRegisterArrayDeleteChecker(
const CheckerManager &mgr) {
227void ento::registerDeleteWithNonVirtualDtorChecker(CheckerManager &mgr) {
231bool ento::shouldRegisterDeleteWithNonVirtualDtorChecker(
232 const CheckerManager &mgr) {
Represents a delete expression for memory deallocation and destructor calls, e.g.
FunctionDecl * getOperatorDelete() const
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const SourceManager & getSourceManager() const
StringRef getDescription() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
const LocationContext * getLocationContext() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
const RegionTy * getAs() const
bool isInteresting(SymbolRef sym) const
const MemRegion * getAsRegion() const
virtual QualType getType() const =0
SymbolRef getSymbol() const
It might return null.
virtual QualType getValueType() const =0
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.