xazax.hun created this revision.
xazax.hun added reviewers: gribozavr, mgehre.
xazax.hun added a project: clang.
Herald added subscribers: Szelethus, Charusso, gamesh411, dkrupp, rnkovacs.

This patch relaxes some of the checks so we can detect more cases where local 
variable escapes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D66486

Files:
  clang/lib/Sema/SemaInit.cpp
  clang/test/Sema/warn-lifetime-analysis-nocfg.cpp

Index: clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
===================================================================
--- clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -141,6 +141,9 @@
 template <typename C>
 auto data(const C &c) -> decltype(c.data());
 
+template<typename T, int N>
+T *begin(T (&array)[N]);
+
 template <typename T>
 struct vector {
   typedef __gnu_cxx::basic_iterator<T> iterator;
@@ -188,6 +191,14 @@
 
 template<typename T>
 T any_cast(const any& operand);
+
+template<typename T>
+struct reference_wrapper {
+  reference_wrapper(T &&);
+};
+
+template<typename T>
+reference_wrapper<T> ref(T& t) noexcept;
 }
 
 void modelIterators() {
@@ -298,3 +309,45 @@
   const std::vector<int> &v = getVec();
   const int *val = v.data(); // Ok, it is lifetime extended.
 }
+
+std::reference_wrapper<int> danglingPtrFromNonOwnerLocal() {
+  int i = 5;
+  return i; // expected-warning {{address of stack memory associated with local variable 'i' returned}}
+}
+
+std::reference_wrapper<int> danglingPtrFromNonOwnerLocal2() {
+  int i = 5;
+  return std::ref(i); // expected-warning {{address of stack memory associated with local variable 'i' returned}}
+}
+
+int *returnPtrToLocalArray() {
+  int a[5];
+  return std::begin(a); // expected-warning {{address of stack memory associated with local variable 'a' returned}}
+}
+
+struct ptr_wrapper {
+  std::vector<int>::iterator member;
+};
+
+ptr_wrapper getPtrWrapper();
+
+std::vector<int>::iterator returnPtrFromWrapper() {
+  ptr_wrapper local = getPtrWrapper();
+  return local.member; // OK.
+}
+
+std::vector<int>::iterator returnPtrFromWrapperThroughRef() {
+  ptr_wrapper local = getPtrWrapper();
+  ptr_wrapper &local2 = local;
+  return local2.member; // OK.
+}
+
+std::vector<int>::iterator returnPtrFromWrapperThroughRef2() {
+  ptr_wrapper local = getPtrWrapper();
+  std::vector<int>::iterator &local2 = local.member;
+  return local2; // OK.
+}
+
+void checkPtrMemberFromAggregate() {
+  std::vector<int>::iterator local = getPtrWrapper().member; // OK.
+}
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -6551,6 +6551,15 @@
   });
 }
 
+static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
+  for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
+    if (It->Kind == IndirectLocalPathEntry::VarInit)
+      continue;
+    return It->Kind == IndirectLocalPathEntry::GslPointerInit;
+  }
+  return false;
+}
+
 static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
                                              Expr *Init, LocalVisitor Visit,
                                              bool RevisitSubinits);
@@ -6619,17 +6628,14 @@
 static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
   if (!FD->getIdentifier() || FD->getNumParams() != 1)
     return false;
-  const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
-  if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())
-    return false;
-  if (!isRecordWithAttr<PointerAttr>(QualType(RD->getTypeForDecl(), 0)) &&
-      !isRecordWithAttr<OwnerAttr>(QualType(RD->getTypeForDecl(), 0)))
+  if (!FD->isInStdNamespace())
     return false;
   if (FD->getReturnType()->isPointerType() ||
       isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
     return llvm::StringSwitch<bool>(FD->getName())
         .Cases("begin", "rbegin", "cbegin", "crbegin", true)
         .Cases("end", "rend", "cend", "crend", true)
+        .Cases("cref", "ref", true)
         .Case("data", true)
         .Default(false);
   } else if (FD->getReturnType()->isReferenceType()) {
@@ -6763,7 +6769,10 @@
 
     // Step over any subobject adjustments; we may have a materialized
     // temporary inside them.
-    Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
+    // We are not interested in the temporary base objects of gsl::Pointers:
+    //   Temp().ptr; // Here ptr might not dangle.
+    if (!pathOnlyInitializesGslPointer(Path))
+      Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
 
     // Per current approach for DR1376, look through casts to reference type
     // when performing lifetime extension.
@@ -6882,7 +6891,10 @@
       Init = FE->getSubExpr();
 
     // Dig out the expression which constructs the extended temporary.
-    Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
+    // We are not interested in the temporary base objects of gsl::Pointers:
+    //   Temp().ptr; // Here ptr might not dangle.
+    if (!pathOnlyInitializesGslPointer(Path))
+      Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
 
     if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
       Init = BTE->getSubExpr();
@@ -7129,15 +7141,6 @@
   return E->getSourceRange();
 }
 
-static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
-  for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
-    if (It->Kind == IndirectLocalPathEntry::VarInit)
-      continue;
-    return It->Kind == IndirectLocalPathEntry::GslPointerInit;
-  }
-  return false;
-}
-
 void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
                                     Expr *Init) {
   LifetimeResult LR = getEntityLifetime(&Entity);
@@ -7166,7 +7169,9 @@
         //   someContainer.add(std::move(localUniquePtr));
         //   return p;
         IsLocalGslOwner = isRecordWithAttr<OwnerAttr>(L->getType());
-        if (pathContainsInit(Path) || !IsLocalGslOwner)
+        if (pathContainsInit(Path) && IsLocalGslOwner)
+          return false;
+        if (isRecordWithAttr<PointerAttr>(L->getType()))
           return false;
       } else {
         IsGslPtrInitWithGslTempOwner = MTE && !MTE->getExtendingDecl() &&
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to