================
@@ -0,0 +1,260 @@
+#include "clang/AST/Attr.h"
+#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, SVal, LifetimeSourceSet)
+
+namespace {
+class UseAfterLifetimeEnd
+    : public Checker<check::PostCall, check::EndFunction, check::DeadSymbols> {
+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,
+                            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);
+      }
+    }
+  }
----------------
steakhal wrote:

Thank you for the test. Could you also have a look at the exploded graph how 
that added test looks like.
I'm interested to know how are those error nodes relate to each other and to 
their parents.
It is just fairly uncommon to submit multiple error nodes in the same 
transition and I want to make sure that the graph looks correct.

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

Reply via email to