clang 24.0.0git
DanglingPtrDeref.cpp
Go to the documentation of this file.
1#include "LifetimeModeling.h"
8
9using namespace clang;
10using namespace ento;
11
12namespace {
13class DanglingPtrDeref : public Checker<check::Location, check::PostCall> {
14public:
15 void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
16 CheckerContext &C) const;
17 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
18 void reportUseAfterScope(const MemRegion *Region, const Stmt *S,
19 ExplodedNode *N, CheckerContext &C) const;
20 const BugType BugMsg{this, "ReportDanglingPtrDeref", "LifetimeBound"};
21};
22
23class DanglingPtrDerefBRVisitor : public BugReporterVisitor {
24 const MemRegion *SourceRegion;
25
26public:
27 explicit DanglingPtrDerefBRVisitor(const MemRegion *Source)
28 : SourceRegion(Source) {}
29
30 void Profile(llvm::FoldingSetNodeID &ID) const override {
31 ID.AddPointer(SourceRegion);
32 }
33
34 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
35 BugReporterContext &BRC,
36 PathSensitiveBugReport &BR) override;
37};
38
39} // namespace
40
41void DanglingPtrDeref::checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
42 CheckerContext &C) const {
43 ProgramStateRef State = C.getState();
44
45 if (const MemRegion *LocRegion = Loc.getAsRegion()) {
46 if (lifetime_modeling::isDeallocated(State, LocRegion)) {
47 if (ExplodedNode *N = C.generateNonFatalErrorNode(State))
48 reportUseAfterScope(LocRegion, S, N, C);
49 }
50 }
51}
52
53void DanglingPtrDeref::checkPostCall(const CallEvent &Call,
54 CheckerContext &C) const {
55 ProgramStateRef State = C.getState();
56 // Only check calls arguments if it is not inlined by the engine. In case a
57 // function is inlined checkLocation handles any dereference in its body.
58 if (C.wasInlined)
59 return;
60
61 for (unsigned Idx = 0; Idx < Call.getNumArgs(); Idx++) {
62 if (const MemRegion *ArgRegion = Call.getArgSVal(Idx).getAsRegion())
63 if (lifetime_modeling::isDeallocated(State, ArgRegion))
64 if (ExplodedNode *N = C.generateNonFatalErrorNode())
65 reportUseAfterScope(ArgRegion, Call.getArgExpr(Idx), N, C);
66 }
67}
68
69void DanglingPtrDeref::reportUseAfterScope(const MemRegion *Region,
70 const Stmt *S, ExplodedNode *N,
71 CheckerContext &C) const {
72 auto BR = std::make_unique<PathSensitiveBugReport>(
73 BugMsg,
74 (llvm::Twine("Use of ") + lifetime_modeling::getRegionName(Region) +
75 " after its lifetime ended."),
76 N);
77 BR->addVisitor<DanglingPtrDerefBRVisitor>(Region);
78 if (S) {
79 if (const Expr *DerefExpr = bugreporter::getDerefExpr(S))
80 bugreporter::trackExpressionValue(N, DerefExpr, *BR);
81 }
82 C.emitReport(std::move(BR));
83}
84
86DanglingPtrDerefBRVisitor::VisitNode(const ExplodedNode *N,
87 BugReporterContext &BRC,
88 PathSensitiveBugReport &BR) {
90 const ExplodedNode *Pred = N->getFirstPred();
91 if (!Pred)
92 return nullptr;
93
94 if (!isDeallocated(N->getState(), SourceRegion) ||
95 isDeallocated(Pred->getState(), SourceRegion))
96 return nullptr;
97
98 const Stmt *S = N->getStmtForDiagnostics();
99 if (!S)
100 return nullptr;
101
102 PathDiagnosticLocation Pos = PathDiagnosticLocation::createEnd(
103 S, BRC.getSourceManager(), N->getStackFrame());
104 return std::make_shared<PathDiagnosticEventPiece>(
105 Pos,
106 (lifetime_modeling::getRegionName(SourceRegion) +
107 llvm::Twine(" is destroyed here"))
108 .str(),
109 true);
110}
111
112void ento::registerDanglingPtrDeref(CheckerManager &Mgr) {
113 Mgr.registerChecker<DanglingPtrDeref>();
114}
115
116bool ento::shouldRegisterDanglingPtrDeref(const CheckerManager &Mgr) {
117 return true;
118}
Stmt - This represents one statement.
Definition Stmt.h:85
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
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.
Definition Checker.h:565
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ExplodedNode * getFirstPred()
const StackFrame * getStackFrame() const
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const StackFrameOrAnalysisDeclContext SFAC)
Create a location for the end of the statement.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:57
const MemRegion * getAsRegion() const
Definition SVals.cpp:119
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
std::string getRegionName(const MemRegion *Reg)
Returns the descriptive name of the memory region or a placeholder if a descriptive name cannot be co...
bool isDeallocated(ProgramStateRef State, const MemRegion *Region)
Returns true if the underlying MemRegion is deallocated.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
The JSON file list parser is used to communicate input to InstallAPI.