================
@@ -0,0 +1,273 @@
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(LifetimeSourceSet, const MemRegion *)
+REGISTER_MAP_WITH_PROGRAMSTATE(LifetimeBoundMap, SymbolRef, LifetimeSourceSet)
+
+REGISTER_MAP_WITH_PROGRAMSTATE(LifetimeBoundMapVal, const MemRegion *,
+ LifetimeSourceSet)
+
+namespace {
+class LifetimeAnnotations
+ : public Checker<check::PostCall, check::EndFunction, eval::Call> {
+public:
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+ void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+ const char *Sep) const override;
+ bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+ void analyzerLifetimeBound(const CallEvent &Call, const CallExpr *,
+ CheckerContext &C) const;
+ ProgramStateRef bindValues(ProgramStateRef State, SymbolRef RetValSym,
+ SVal RetVal, const MemRegion *Source) const;
+ bool isSourceDangle(const MemRegion *Source, ProgramStateRef State,
+ CheckerContext &C) const;
+ void reportDanglingSource(const MemRegion *Region, ExplodedNode *N,
+ CheckerContext &C) const;
+
+ template <typename MapTy, typename KeyTy>
+ void checkReturnedBorrower(const MapTy &Map, const KeyTy RetKey,
+ ProgramStateRef State, ExplodedNode *N,
+ CheckerContext &C) const;
+ void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
+
+ const BugType BugMsg{this, "LifetimeAnnotations", "LifetimeBound"};
+
+ using FnCheck = void (LifetimeAnnotations::*)(const CallEvent &Call,
+ const CallExpr *,
+ CheckerContext &C) const;
+
+ const CallDescriptionMap<FnCheck> Callbacks = {
+ {{CDM::SimpleFunc, {"clang_analyzer_lifetime_bound"}},
+ &LifetimeAnnotations::analyzerLifetimeBound},
+ };
+};
+
+} // namespace
+
+ProgramStateRef LifetimeAnnotations::bindValues(ProgramStateRef State,
+ SymbolRef RetValSym,
+ SVal RetVal,
+ const MemRegion *Source) const
{
+ LifetimeSourceSet::Factory &F =
+ State->getStateManager().get_context<LifetimeSourceSet>();
+
+ if (RetValSym) {
+ const LifetimeSourceSet *LBSet = State->get<LifetimeBoundMap>(RetValSym);
+ LifetimeSourceSet Set = LBSet ? *LBSet : F.getEmptySet();
+ Set = F.add(Set, Source);
+ State = State->set<LifetimeBoundMap>(RetValSym, Set);
+ } else if (const MemRegion *RetValRegion = RetVal.getAsRegion()) {
+ const LifetimeSourceSet *LBValSet =
+ State->get<LifetimeBoundMapVal>(RetValRegion);
+ LifetimeSourceSet Set = LBValSet ? *LBValSet : F.getEmptySet();
+ Set = F.add(Set, Source);
+ State = State->set<LifetimeBoundMapVal>(RetValRegion, Set);
+ }
+ return State;
+}
+
+void LifetimeAnnotations::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ const auto *FC = dyn_cast<AnyFunctionCall>(&Call);
+ if (!FC)
+ return;
+
+ const FunctionDecl *FD = FC->getDecl();
+ if (!FD)
+ return;
+
+ SVal RetVal = Call.getReturnValue();
+ SymbolRef RetValSym = RetVal.getAsSymbol(/*IncludeBaseRegions=*/true);
+
+ for (const ParmVarDecl *PVD : FD->parameters()) {
+ if (PVD->hasAttr<LifetimeBoundAttr>()) {
+ unsigned Idx = PVD->getFunctionScopeIndex();
+ SVal Arg = Call.getArgSVal(Idx);
+ if (const MemRegion *ArgValRegion = Arg.getAsRegion())
+ State = bindValues(State, RetValSym, RetVal, ArgValRegion);
+ }
+ }
+
+ if (const auto *IC = dyn_cast<CXXInstanceCall>(&Call)) {
+ if (clang::lifetimes::implicitObjectParamIsLifetimeBound(FD)) {
----------------
isuckatcs wrote:
JFYI: when LLVM is built with dynamic linking (e.g.: `-DBUILD_SHARED_LIBS=On`),
the linker cannot resolve the
`clang::lifetimes::implicitObjectParamIsLifetimeBound(FD)` symbol. We probably
should explicitly link the checkers against `libClangAnalysisLifetimeSafety` if
we intent to reuse its logic.
```diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 8a0621077b97..7026f764978e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -146,6 +146,7 @@ add_clang_library(clangStaticAnalyzerCheckers
clangAST
clangASTMatchers
clangAnalysis
+ clangAnalysisLifetimeSafety
clangBasic
clangLex
clangStaticAnalyzerCore
```
I haven't opened a PR for this yet, as this is the only checker that would use
that library, and it is still under development.
cc @Xazax-hun
https://github.com/llvm/llvm-project/pull/200145
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits