clang 24.0.0git
UseAfterLifetimeEnd.cpp
Go to the documentation of this file.
1#include "LifetimeModeling.h"
5
6using namespace clang;
7using namespace ento;
8
9namespace {
10class UseAfterLifetimeEnd : public Checker<check::EndFunction> {
11public:
12 void reportDanglingSource(const MemRegion *Source, SVal Val, ExplodedNode *N,
13 CheckerContext &C) const;
14 void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
15 const BugType BugMsg{this, "UseAfterLifetimeEnd", "LifetimeBound"};
16};
17
18class UseAfterLifetimeEndBRVisitor : public BugReporterVisitor {
19 SVal BoundVal;
20 const MemRegion *SourceRegion;
21
22public:
23 explicit UseAfterLifetimeEndBRVisitor(SVal Val, const MemRegion *Source)
24 : BoundVal(Val), SourceRegion(Source) {}
25
26 void Profile(llvm::FoldingSetNodeID &ID) const override {
27 static int X = 0;
28 ID.AddPointer(&X);
29 BoundVal.Profile(ID);
30 SourceRegion->Profile(ID);
31 }
32
33 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
34 BugReporterContext &BRC,
35 PathSensitiveBugReport &BR) override;
36 PathDiagnosticPieceRef getEndPath(const ExplodedNode *N,
37 BugReporterContext &BRC,
38 PathSensitiveBugReport &BR) override;
39 PathDiagnosticPieceRef createSourcePiece(const ExplodedNode *N,
40 BugReporterContext &BRC,
41 StringRef Message) const;
42};
43
44} // namespace
45
46static const Expr *getLifetimeBoundArg(const Expr *RetExpr) {
47 const CallExpr *Expr = dyn_cast_or_null<CallExpr>(RetExpr);
48 if (!Expr)
49 return nullptr;
50 const FunctionDecl *FD = Expr->getDirectCallee();
51 if (!FD)
52 return nullptr;
53
54 for (const ParmVarDecl *PVD : FD->parameters()) {
55 if (PVD->hasAttr<LifetimeBoundAttr>()) {
56 unsigned Idx = PVD->getFunctionScopeIndex();
57 if (Idx < Expr->getNumArgs())
58 return Expr->getArg(Idx);
59 }
60 }
61 return nullptr;
62}
63
64void UseAfterLifetimeEnd::checkEndFunction(const ReturnStmt *RS,
65 CheckerContext &C) const {
66 if (!RS)
67 return;
68
69 ProgramStateRef State = C.getState();
70
71 const Expr *RetExpr = RS->getRetValue();
72 if (!RetExpr)
73 return;
74
75 RetExpr = RetExpr->IgnoreParens();
76 SVal RetVal = C.getSVal(RetExpr);
77
78 std::vector<const MemRegion *> RetValRegion =
80 if (RetValRegion.empty())
81 return;
82
83 if (ExplodedNode *N =
84 C.generateNonFatalErrorNode(State, C.getPredecessor())) {
85 for (const MemRegion *R : RetValRegion)
86 reportDanglingSource(R, RetVal, N, C);
87 }
88}
89
91 if (const auto *VR = dyn_cast_or_null<VarRegion>(Source))
92 return VR->getDecl()->getSourceRange();
93 return SourceRange();
94}
95
96void UseAfterLifetimeEnd::reportDanglingSource(const MemRegion *Source,
97 SVal RetVal, ExplodedNode *N,
98 CheckerContext &C) const {
99 auto BR = std::make_unique<PathSensitiveBugReport>(
100 BugMsg,
101 (llvm::Twine("Returning value bound to ") +
102 lifetime_modeling::getRegionName(Source) + " that will go out of scope"),
103 N);
104
105 if (SourceRange Range = getRegionDeclRange(Source); Range.isValid())
106 BR->addRange(Range);
107
108 BR->addVisitor<UseAfterLifetimeEndBRVisitor>(RetVal, Source);
109 bugreporter::trackStoredValue(RetVal, Source, *BR);
110 C.emitReport(std::move(BR));
111}
112
113PathDiagnosticPieceRef UseAfterLifetimeEndBRVisitor::createSourcePiece(
114 const ExplodedNode *N, BugReporterContext &BRC, StringRef Message) const {
115 const Stmt *S = N->getStmtForDiagnostics();
116 if (!S)
117 return nullptr;
118
119 const Expr *RetExpr = dyn_cast_or_null<Expr>(S);
120 const Expr *Arg = getLifetimeBoundArg(RetExpr);
121
122 PathDiagnosticLocation Pos;
123
124 Pos = PathDiagnosticLocation(Arg ? Arg : S, BRC.getSourceManager(),
125 N->getStackFrame());
126
127 auto Note = std::make_shared<PathDiagnosticEventPiece>(Pos, Message, true);
128 if (SourceRange Range = getRegionDeclRange(SourceRegion); Range.isValid())
129 Note->addRange(Range);
130
131 return Note;
132}
133
135UseAfterLifetimeEndBRVisitor::VisitNode(const ExplodedNode *N,
136 BugReporterContext &BRC,
137 PathSensitiveBugReport &BR) {
138 const ExplodedNode *Pred = N->getFirstPred();
139 if (!Pred)
140 return nullptr;
141
144 return nullptr;
145
146 auto Piece = createSourcePiece(
147 N, BRC,
148 (llvm::Twine("Value's lifetime bound to the lifetime of ") +
149 lifetime_modeling::getRegionName(SourceRegion) + " here")
150 .str());
151 return Piece;
152}
153
155UseAfterLifetimeEndBRVisitor::getEndPath(const ExplodedNode *N,
156 BugReporterContext &BRC,
157 PathSensitiveBugReport &BR) {
158 auto Piece = createSourcePiece(
159 N, BRC,
160 (llvm::Twine("Lifetime of ") +
161 lifetime_modeling::getRegionName(SourceRegion) + " ended here")
162 .str());
163 return Piece;
164}
165
166void ento::registerUseAfterLifetimeEnd(CheckerManager &Mgr) {
167 Mgr.registerChecker<UseAfterLifetimeEnd>();
168}
169
170bool ento::shouldRegisterUseAfterLifetimeEnd(const CheckerManager &Mgr) {
171 return true;
172}
#define X(type, name)
Definition Value.h:97
static SourceRange getRegionDeclRange(const MemRegion *Source)
static const Expr * getLifetimeBoundArg(const Expr *RetExpr)
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2949
This represents one expression.
Definition Expr.h:112
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3097
Represents a function declaration or definition.
Definition Decl.h:2029
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2814
Represents a parameter to a function.
Definition Decl.h:1819
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3169
Expr * getRetValue()
Definition Stmt.h:3196
A trivial tuple used to represent a source range.
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
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:97
void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts={}, const StackFrame *Origin=nullptr)
Track how the value got stored into the given region and where it came from.
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 isBoundToLifetimeSource(ProgramStateRef State, SVal Val)
Returns true if Val is a key in the LifetimeBoundMap.
std::vector< const MemRegion * > getDanglingRegionsAfterReturn(SVal Source, ProgramStateRef State, CheckerContext &C)
Returns the set of lifetime sources bound to Source that are dangling stack regions.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
The JSON file list parser is used to communicate input to InstallAPI.