| 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 | |
| 8 | using namespace clang; |
| 9 | using namespace ento; |
| 10 | |
| 11 | namespace { |
| 12 | class DanglingPtrDeref : public Checker<check::Location> { |
| 13 | public: |
| 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 | |
| 21 | class DanglingPtrDerefBRVisitor : public BugReporterVisitor { |
| 22 | const MemRegion *SourceRegion; |
| 23 | |
| 24 | public: |
| 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 | |
| 39 | void 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 | |
| 51 | void 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 | |
| 63 | PathDiagnosticPieceRef |
| 64 | DanglingPtrDerefBRVisitor::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 | |
| 89 | void ento::registerDanglingPtrDeref(CheckerManager &Mgr) { |
| 90 | Mgr.registerChecker<DanglingPtrDeref>(); |
| 91 | } |
| 92 | |
| 93 | bool ento::shouldRegisterDanglingPtrDeref(const CheckerManager &Mgr) { |
| 94 | return true; |
| 95 | } |
| 96 | |