1#include "LifetimeModeling.h"
2#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
3#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
4#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
5#include "clang/StaticAnalyzer/Core/Checker.h"
6#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
7
8using namespace clang;
9using namespace ento;
10
11namespace {
12class DanglingPtrDeref : public Checker<check::Location> {
13public:
14 void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
15 CheckerContext &C) const;
16 void reportUseAfterScope(const MemRegion *Region, ExplodedNode *N,
17 CheckerContext &C) const;
18 const BugType BugMsg{this, "ReportDanglingPtrDeref", "LifetimeBound"};
19};
20
21class DanglingPtrDerefBRVisitor : public BugReporterVisitor {
22 const MemRegion *SourceRegion;
23
24public:
25 explicit DanglingPtrDerefBRVisitor(const MemRegion *Source)
26 : SourceRegion(Source) {}
27
28 void Profile(llvm::FoldingSetNodeID &ID) const override {
29 ID.AddPointer(Ptr: SourceRegion);
30 }
31
32 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
33 BugReporterContext &BRC,
34 PathSensitiveBugReport &BR) override;
35};
36
37} // namespace
38
39void DanglingPtrDeref::checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
40 CheckerContext &C) const {
41 ProgramStateRef State = C.getState();
42
43 if (const MemRegion *LocRegion = Loc.getAsRegion()) {
44 if (lifetime_modeling::isDeallocated(State, Region: LocRegion)) {
45 if (ExplodedNode *N = C.generateNonFatalErrorNode(State))
46 reportUseAfterScope(Region: LocRegion, N, C);
47 }
48 }
49}
50
51void DanglingPtrDeref::reportUseAfterScope(const MemRegion *Region,
52 ExplodedNode *N,
53 CheckerContext &C) const {
54 auto BR = std::make_unique<PathSensitiveBugReport>(
55 args: BugMsg,
56 args: (llvm::Twine("Use of '") + Region->getString() +
57 "' after its lifetime ended."),
58 args&: N);
59 BR->addVisitor<DanglingPtrDerefBRVisitor>(ConstructorArgs&: Region);
60 C.emitReport(R: std::move(BR));
61}
62
63PathDiagnosticPieceRef
64DanglingPtrDerefBRVisitor::VisitNode(const ExplodedNode *N,
65 BugReporterContext &BRC,
66 PathSensitiveBugReport &BR) {
67 using lifetime_modeling::isDeallocated;
68 const ExplodedNode *Pred = N->getFirstPred();
69 if (!Pred)
70 return nullptr;
71
72 if (!isDeallocated(State: N->getState(), Region: SourceRegion) ||
73 isDeallocated(State: Pred->getState(), Region: SourceRegion))
74 return nullptr;
75
76 const Stmt *S = N->getStmtForDiagnostics();
77 if (!S)
78 return nullptr;
79
80 PathDiagnosticLocation Pos = PathDiagnosticLocation::createEnd(
81 S, SM: BRC.getSourceManager(), SFAC: N->getStackFrame());
82 return std::make_shared<PathDiagnosticEventPiece>(
83 args&: Pos,
84 args: (llvm::Twine("'") + SourceRegion->getString() + "' is destroyed here")
85 .str(),
86 args: true);
87}
88
89void ento::registerDanglingPtrDeref(CheckerManager &Mgr) {
90 Mgr.registerChecker<DanglingPtrDeref>();
91}
92
93bool ento::shouldRegisterDanglingPtrDeref(const CheckerManager &Mgr) {
94 return true;
95}
96