1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
24 | #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" |
25 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
26 | #include "clang/StaticAnalyzer/Core/Checker.h" |
27 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
28 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
29 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
30 | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" |
31 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" |
32 | |
33 | using namespace clang; |
34 | using namespace ento; |
35 | |
36 | namespace { |
37 | class DeleteWithNonVirtualDtorChecker |
38 | : public Checker<check::PreStmt<CXXDeleteExpr>> { |
39 | mutable std::unique_ptr<BugType> BT; |
40 | |
41 | class DeleteBugVisitor : public BugReporterVisitor { |
42 | public: |
43 | DeleteBugVisitor() : Satisfied(false) {} |
44 | void Profile(llvm::FoldingSetNodeID &ID) const override { |
45 | static int X = 0; |
46 | ID.AddPointer(&X); |
47 | } |
48 | std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, |
49 | BugReporterContext &BRC, |
50 | BugReport &BR) override; |
51 | |
52 | private: |
53 | bool Satisfied; |
54 | }; |
55 | |
56 | public: |
57 | void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const; |
58 | }; |
59 | } |
60 | |
61 | void DeleteWithNonVirtualDtorChecker::checkPreStmt(const CXXDeleteExpr *DE, |
62 | CheckerContext &C) const { |
63 | const Expr *DeletedObj = DE->getArgument(); |
64 | const MemRegion *MR = C.getSVal(DeletedObj).getAsRegion(); |
65 | if (!MR) |
66 | return; |
67 | |
68 | const auto *BaseClassRegion = MR->getAs<TypedValueRegion>(); |
69 | const auto *DerivedClassRegion = MR->getBaseRegion()->getAs<SymbolicRegion>(); |
70 | if (!BaseClassRegion || !DerivedClassRegion) |
71 | return; |
72 | |
73 | const auto *BaseClass = BaseClassRegion->getValueType()->getAsCXXRecordDecl(); |
74 | const auto *DerivedClass = |
75 | DerivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl(); |
76 | if (!BaseClass || !DerivedClass) |
77 | return; |
78 | |
79 | if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition()) |
80 | return; |
81 | |
82 | if (BaseClass->getDestructor()->isVirtual()) |
83 | return; |
84 | |
85 | if (!DerivedClass->isDerivedFrom(BaseClass)) |
86 | return; |
87 | |
88 | if (!BT) |
89 | BT.reset(new BugType(this, |
90 | "Destruction of a polymorphic object with no " |
91 | "virtual destructor", |
92 | "Logic error")); |
93 | |
94 | ExplodedNode *N = C.generateNonFatalErrorNode(); |
95 | auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N); |
96 | |
97 | |
98 | R->markInteresting(BaseClassRegion); |
99 | R->addVisitor(llvm::make_unique<DeleteBugVisitor>()); |
100 | C.emitReport(std::move(R)); |
101 | } |
102 | |
103 | std::shared_ptr<PathDiagnosticPiece> |
104 | DeleteWithNonVirtualDtorChecker::DeleteBugVisitor::VisitNode( |
105 | const ExplodedNode *N, BugReporterContext &BRC, |
106 | BugReport &BR) { |
107 | |
108 | if (Satisfied) |
109 | return nullptr; |
110 | |
111 | const Stmt *S = PathDiagnosticLocation::getStmt(N); |
112 | if (!S) |
113 | return nullptr; |
114 | |
115 | const auto *CastE = dyn_cast<CastExpr>(S); |
116 | if (!CastE) |
117 | return nullptr; |
118 | |
119 | |
120 | |
121 | if (const auto *ImplCastE = dyn_cast<ImplicitCastExpr>(CastE)) { |
122 | if (ImplCastE->getCastKind() != CK_DerivedToBase) |
123 | return nullptr; |
124 | } |
125 | |
126 | |
127 | const MemRegion *M = N->getSVal(CastE).getAsRegion(); |
128 | if (!M) |
129 | return nullptr; |
130 | |
131 | |
132 | if (!BR.isInteresting(M)) |
133 | return nullptr; |
134 | |
135 | |
136 | Satisfied = true; |
137 | |
138 | SmallString<256> Buf; |
139 | llvm::raw_svector_ostream OS(Buf); |
140 | OS << "Conversion from derived to base happened here"; |
141 | PathDiagnosticLocation Pos(S, BRC.getSourceManager(), |
142 | N->getLocationContext()); |
143 | return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true, |
144 | nullptr); |
145 | } |
146 | |
147 | void ento::registerDeleteWithNonVirtualDtorChecker(CheckerManager &mgr) { |
148 | mgr.registerChecker<DeleteWithNonVirtualDtorChecker>(); |
149 | } |
150 | |
151 | bool ento::shouldRegisterDeleteWithNonVirtualDtorChecker( |
152 | const LangOptions &LO) { |
153 | return true; |
154 | } |
155 | |