blob: bd4cd864cb768dbe184bbff65a31b4a81d07a286 [file] [edit]
#include "LifetimeModeling.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
using namespace clang;
using namespace ento;
namespace {
class DanglingPtrDeref : public Checker<check::Location, check::PostCall> {
public:
void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
CheckerContext &C) const;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
void reportUseAfterScope(const MemRegion *Region, const Stmt *S,
ExplodedNode *N, CheckerContext &C) const;
const BugType BugMsg{this, "ReportDanglingPtrDeref", "LifetimeBound"};
};
class DanglingPtrDerefBRVisitor : public BugReporterVisitor {
const MemRegion *SourceRegion;
public:
explicit DanglingPtrDerefBRVisitor(const MemRegion *Source)
: SourceRegion(Source) {}
void Profile(llvm::FoldingSetNodeID &ID) const override {
ID.AddPointer(SourceRegion);
}
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
PathSensitiveBugReport &BR) override;
};
} // namespace
void DanglingPtrDeref::checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
if (const MemRegion *LocRegion = Loc.getAsRegion()) {
if (lifetime_modeling::isDeallocated(State, LocRegion)) {
if (ExplodedNode *N = C.generateNonFatalErrorNode(State))
reportUseAfterScope(LocRegion, S, N, C);
}
}
}
void DanglingPtrDeref::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
// Only check calls arguments if it is not inlined by the engine. In case a
// function is inlined checkLocation handles any dereference in its body.
if (C.wasInlined)
return;
for (unsigned Idx = 0; Idx < Call.getNumArgs(); Idx++) {
if (const MemRegion *ArgRegion = Call.getArgSVal(Idx).getAsRegion())
if (lifetime_modeling::isDeallocated(State, ArgRegion))
if (ExplodedNode *N = C.generateNonFatalErrorNode())
reportUseAfterScope(ArgRegion, Call.getArgExpr(Idx), N, C);
}
}
void DanglingPtrDeref::reportUseAfterScope(const MemRegion *Region,
const Stmt *S, ExplodedNode *N,
CheckerContext &C) const {
auto BR = std::make_unique<PathSensitiveBugReport>(
BugMsg,
(llvm::Twine("Use of ") + lifetime_modeling::getRegionName(Region) +
" after its lifetime ended."),
N);
BR->addVisitor<DanglingPtrDerefBRVisitor>(Region);
if (S) {
if (const Expr *DerefExpr = bugreporter::getDerefExpr(S))
bugreporter::trackExpressionValue(N, DerefExpr, *BR);
}
C.emitReport(std::move(BR));
}
PathDiagnosticPieceRef
DanglingPtrDerefBRVisitor::VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
PathSensitiveBugReport &BR) {
using lifetime_modeling::isDeallocated;
const ExplodedNode *Pred = N->getFirstPred();
if (!Pred)
return nullptr;
if (!isDeallocated(N->getState(), SourceRegion) ||
isDeallocated(Pred->getState(), SourceRegion))
return nullptr;
const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;
PathDiagnosticLocation Pos = PathDiagnosticLocation::createEnd(
S, BRC.getSourceManager(), N->getStackFrame());
return std::make_shared<PathDiagnosticEventPiece>(
Pos,
(lifetime_modeling::getRegionName(SourceRegion) +
llvm::Twine(" is destroyed here"))
.str(),
true);
}
void ento::registerDanglingPtrDeref(CheckerManager &Mgr) {
Mgr.registerChecker<DanglingPtrDeref>();
}
bool ento::shouldRegisterDanglingPtrDeref(const CheckerManager &Mgr) {
return true;
}