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 MemRegion *Region,
48 const ExplodedNode *N) {
49 const CallExpr *Expr = dyn_cast_or_null<CallExpr>(RetExpr);
50 if (!Expr)
51 return nullptr;
52
53 const FunctionDecl *FD = Expr->getDirectCallee();
54 if (!FD)
55 return nullptr;
56
57 const MemRegion *BaseReg = Region->getBaseRegion();
58
59 for (const ParmVarDecl *PVD : FD->parameters()) {
60 if (!PVD->hasAttr<LifetimeBoundAttr>())
61 continue;
62 unsigned Idx = PVD->getFunctionScopeIndex();
63
64 if (Idx >= Expr->getNumArgs())
65 continue;
66
67 const MemRegion *R = N->getSVal(Expr->getArg(Idx)).getAsRegion();
68 if (R && R->getBaseRegion() == BaseReg)
69 return Expr->getArg(Idx);
70 }
71 return nullptr;
72}
73
74void UseAfterLifetimeEnd::checkEndFunction(const ReturnStmt *RS,
75 CheckerContext &C) const {
76 if (!RS)
77 return;
78
79 ProgramStateRef State = C.getState();
80
81 const Expr *RetExpr = RS->getRetValue();
82 if (!RetExpr)
83 return;
84
85 RetExpr = RetExpr->IgnoreParens();
86 SVal RetVal = C.getSVal(RetExpr);
87
88 std::vector<const MemRegion *> RetValRegion =
90 if (RetValRegion.empty())
91 return;
92
93 if (ExplodedNode *N =
94 C.generateNonFatalErrorNode(State, C.getPredecessor())) {
95 for (const MemRegion *R : RetValRegion)
96 reportDanglingSource(R, RetVal, N, C);
97 }
98}
99
101 if (const auto *VR = dyn_cast_or_null<VarRegion>(Source)) {
102 const VarDecl *VD = VR->getDecl();
103 return SourceRange(VD->getLocation());
104 }
105 return SourceRange();
106}
107
108void UseAfterLifetimeEnd::reportDanglingSource(const MemRegion *Source,
109 SVal RetVal, ExplodedNode *N,
110 CheckerContext &C) const {
111 auto BR = std::make_unique<PathSensitiveBugReport>(
112 BugMsg,
113 (llvm::Twine("Returning value bound to ") +
114 lifetime_modeling::getRegionName(Source) + " that will go out of scope"),
115 N);
116
117 if (SourceRange Range = getRegionDeclRange(Source); Range.isValid())
118 BR->addRange(Range);
119
120 BR->addVisitor<UseAfterLifetimeEndBRVisitor>(RetVal, Source);
121 bugreporter::trackStoredValue(RetVal, Source, *BR);
122 C.emitReport(std::move(BR));
123}
124
125PathDiagnosticPieceRef UseAfterLifetimeEndBRVisitor::createSourcePiece(
126 const ExplodedNode *N, BugReporterContext &BRC, StringRef Message) const {
127 const Stmt *S = N->getStmtForDiagnostics();
128 if (!S)
129 return nullptr;
130
131 const Expr *RetExpr = dyn_cast_or_null<Expr>(S);
132 const Expr *Arg = getLifetimeBoundArg(RetExpr, SourceRegion, N);
133
134 PathDiagnosticLocation Pos;
135
136 Pos = PathDiagnosticLocation(Arg ? Arg : S, BRC.getSourceManager(),
137 N->getStackFrame());
138
139 auto Note = std::make_shared<PathDiagnosticEventPiece>(Pos, Message, true);
140 if (SourceRange Range = getRegionDeclRange(SourceRegion); Range.isValid())
141 Note->addRange(Range);
142
143 return Note;
144}
145
147UseAfterLifetimeEndBRVisitor::VisitNode(const ExplodedNode *N,
148 BugReporterContext &BRC,
149 PathSensitiveBugReport &BR) {
150 const ExplodedNode *Pred = N->getFirstPred();
151 if (!Pred)
152 return nullptr;
153
156 return nullptr;
157
158 auto Piece = createSourcePiece(
159 N, BRC,
160 (llvm::Twine("Value's lifetime bound to the lifetime of ") +
161 lifetime_modeling::getRegionName(SourceRegion) + " here")
162 .str());
163 return Piece;
164}
165
167UseAfterLifetimeEndBRVisitor::getEndPath(const ExplodedNode *N,
168 BugReporterContext &BRC,
169 PathSensitiveBugReport &BR) {
170 auto Piece = createSourcePiece(
171 N, BRC,
172 (llvm::Twine("Lifetime of ") +
173 lifetime_modeling::getRegionName(SourceRegion) + " ended here")
174 .str());
175 return Piece;
176}
177
178void ento::registerUseAfterLifetimeEnd(CheckerManager &Mgr) {
179 Mgr.registerChecker<UseAfterLifetimeEnd>();
180}
181
182bool ento::shouldRegisterUseAfterLifetimeEnd(const CheckerManager &Mgr) {
183 return true;
184}
#define X(type, name)
Definition Value.h:97
static SourceRange getRegionDeclRange(const MemRegion *Source)
static const Expr * getLifetimeBoundArg(const Expr *RetExpr, const MemRegion *Region, const ExplodedNode *N)
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2987
SourceLocation getLocation() const
Definition DeclBase.h:447
This represents one expression.
Definition Expr.h:113
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3119
Represents a function declaration or definition.
Definition Decl.h:2059
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2905
Represents a parameter to a function.
Definition Decl.h:1820
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3172
Expr * getRetValue()
Definition Stmt.h:3199
A trivial tuple used to represent a source range.
Represents a variable declaration or definition.
Definition Decl.h:933
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
SVal getSVal(const Expr *E) const
Get the value of an arbitrary expression at this node.
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
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
const MemRegion * getAsRegion() const
Definition SVals.cpp:119
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
Top level wrappers for InstallAPI frontend operations.