1#include "LifetimeModeling.h"
2#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
3#include "clang/StaticAnalyzer/Core/Checker.h"
4
5using namespace clang;
6using namespace ento;
7
8namespace {
9class UseAfterLifetimeEnd : public Checker<check::EndFunction> {
10public:
11 void reportDanglingSource(const MemRegion *Source, ExplodedNode *N,
12 CheckerContext &C) const;
13 void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
14 const BugType BugMsg{this, "UseAfterLifetimeEnd", "LifetimeBound"};
15};
16
17} // namespace
18
19void UseAfterLifetimeEnd::checkEndFunction(const ReturnStmt *RS,
20 CheckerContext &C) const {
21 if (!RS)
22 return;
23
24 ProgramStateRef State = C.getState();
25
26 const Expr *RetExpr = RS->getRetValue();
27 if (!RetExpr)
28 return;
29
30 RetExpr = RetExpr->IgnoreParens();
31 SVal RetVal = C.getSVal(E: RetExpr);
32
33 std::vector<const MemRegion *> RetValRegion =
34 lifetime_modeling::getDanglingRegionsAfterReturn(Source: RetVal, State, C);
35 if (RetValRegion.empty())
36 return;
37
38 if (ExplodedNode *N =
39 C.generateNonFatalErrorNode(State, Pred: C.getPredecessor())) {
40 for (const MemRegion *R : RetValRegion)
41 reportDanglingSource(Source: R, N, C);
42 }
43}
44
45void UseAfterLifetimeEnd::reportDanglingSource(const MemRegion *Source,
46 ExplodedNode *N,
47 CheckerContext &C) const {
48 auto BR = std::make_unique<PathSensitiveBugReport>(
49 args: BugMsg,
50 args: (llvm::Twine("Returning value bound to '") + Source->getString() +
51 "' that will go out of scope"),
52 args&: N);
53 C.emitReport(R: std::move(BR));
54}
55
56void ento::registerUseAfterLifetimeEnd(CheckerManager &Mgr) {
57 Mgr.registerChecker<UseAfterLifetimeEnd>();
58}
59
60bool ento::shouldRegisterUseAfterLifetimeEnd(const CheckerManager &Mgr) {
61 return true;
62}
63