================
@@ -1,258 +1,63 @@
-#include "clang/AST/Attr.h"
-#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Checkers/LifetimeModeling.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, SVal, LifetimeSourceSet)
-
 namespace {
-class UseAfterLifetimeEnd
-    : public Checker<check::PostCall, check::EndFunction, check::DeadSymbols> {
+class UseAfterLifetimeEnd : public Checker<check::EndFunction> {
 public:
-  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
-  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
-                  const char *Sep) const override;
-  void reportDanglingSource(const MemRegion *Region, ExplodedNode *N,
+  void reportDanglingSource(const MemRegion *Source, ExplodedNode *N,
                             CheckerContext &C) const;
-  void checkReturnedBorrower(SVal Val, ProgramStateRef State,
-                             CheckerContext &C) const;
   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
-  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
   const BugType BugMsg{this, "UseAfterLifetimeEnd", "LifetimeBound"};
 };
 
 } // namespace
 
-static ProgramStateRef bindValues(ProgramStateRef State, SVal RetVal,
-                                  const MemRegion *Source) {
-  LifetimeSourceSet::Factory &F = State->get_context<LifetimeSourceSet>();
-
-  const LifetimeSourceSet *LSet = State->get<LifetimeBoundMap>(RetVal);
-  LifetimeSourceSet Set = LSet ? *LSet : F.getEmptySet();
-  Set = F.add(Set, Source);
-  State = State->set<LifetimeBoundMap>(RetVal, Set);
-  return State;
-}
-
-void UseAfterLifetimeEnd::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();
-
-  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, RetVal, ArgValRegion);
-    }
-  }
-
-  if (const auto *IC = dyn_cast<CXXInstanceCall>(&Call)) {
-    if (lifetimes::implicitObjectParamIsLifetimeBound(FD)) {
-      if (const MemRegion *AttrRegion = IC->getCXXThisVal().getAsRegion()) {
-        State = bindValues(State, RetVal, AttrRegion);
-      }
-    }
-  }
-  C.addTransition(State);
-}
-
-static bool hasDanglingSource(const MemRegion *Source, ProgramStateRef State,
-                              CheckerContext &C) {
-  // FIXME: The checker currently handles stack-region sources. Other
-  // region kinds require separate methodology. For example, heap
-  // regions do not go out of scope at the end of a stack frame, so
-  // in order to detect those type of dangling sources the function
-  // needs to be expanded to an event-driven approach as well.
-  if (const auto *StackSpace =
-          Source->getMemorySpaceAs<StackSpaceRegion>(State)) {
-    const StackFrame *SF = StackSpace->getStackFrame();
-    const StackFrame *CurrentSF = C.getStackFrame();
-    if (SF == CurrentSF || !SF->isParentOf(CurrentSF))
-      return true;
-  }
-  return false;
-}
-
-void UseAfterLifetimeEnd::checkReturnedBorrower(SVal Val, ProgramStateRef 
State,
-                                                CheckerContext &C) const {
-  if (auto *SourceSet = State->get<LifetimeBoundMap>(Val)) {
-    ExplodedNode *N = nullptr;
-    for (const MemRegion *Region : *SourceSet) {
-      if (hasDanglingSource(Region, State, C)) {
-        if (!N)
-          N = C.generateNonFatalErrorNode();
-        if (!N)
-          return;
-        reportDanglingSource(Region, N, C);
-      }
-    }
-  }
-}
-
 void UseAfterLifetimeEnd::checkEndFunction(const ReturnStmt *RS,
                                            CheckerContext &C) const {
   if (!RS)
     return;
 
   ProgramStateRef State = C.getState();
-  auto LBMap = State->get<LifetimeBoundMap>();
-
-  if (LBMap.isEmpty())
-    return;
 
   const Expr *RetExpr = RS->getRetValue();
   if (!RetExpr)
     return;
 
   RetExpr = RetExpr->IgnoreParens();
   SVal RetVal = C.getSVal(RetExpr);
-  checkReturnedBorrower(RetVal, State, C);
+  ExplodedNode *N = nullptr;
+
+  std::vector<const MemRegion *> RetValRegion =
+      lifetime_modeling::checkReturnedBorrower(RetVal, State, C);
+  for (const MemRegion *Region : RetValRegion) {
+    if (!N)
+      N = C.generateNonFatalErrorNode();
----------------
Xazax-hun wrote:

I think we might bifurcate the path here if we generate multiple errors. By 
default `C.generateNonFatalErrorNode` should add a new node rooted at the 
current state. I think there might be an overload that takes a predecessor. If 
we generate multiple nodes, the previously generated ones should be the 
predecessors to avoid creating a branch in the exploded graph. 

https://github.com/llvm/llvm-project/pull/205951
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to