[clang] [clang][bytecode] Destroy local variables in reverse order (PR #125727)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 4 10:06:43 PST 2025


https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/125727

>From 58faf5d42f02fc570a72c9af2d90282bae9fe834 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 4 Feb 2025 18:08:00 +0100
Subject: [PATCH] [clang][bytecode] Destroy local variables in reverse order

See the attached test case.
---
 clang/lib/AST/ByteCode/Function.h      |  5 +++++
 clang/lib/AST/ByteCode/InterpFrame.cpp |  2 +-
 clang/test/AST/ByteCode/cxx20.cpp      | 23 +++++++++++++++++++++++
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ByteCode/Function.h b/clang/lib/AST/ByteCode/Function.h
index 2d3421e5e612950..e17183eef9eac64 100644
--- a/clang/lib/AST/ByteCode/Function.h
+++ b/clang/lib/AST/ByteCode/Function.h
@@ -51,6 +51,11 @@ class Scope final {
     return llvm::make_range(Descriptors.begin(), Descriptors.end());
   }
 
+  llvm::iterator_range<LocalVectorTy::const_reverse_iterator>
+  locals_reverse() const {
+    return llvm::reverse(Descriptors);
+  }
+
 private:
   /// Object descriptors in this block.
   LocalVectorTy Descriptors;
diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp
index 89fc7a4515d6416..c383b2bc7f95ce1 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -99,7 +99,7 @@ void InterpFrame::initScope(unsigned Idx) {
 }
 
 void InterpFrame::destroy(unsigned Idx) {
-  for (auto &Local : Func->getScope(Idx).locals()) {
+  for (auto &Local : Func->getScope(Idx).locals_reverse()) {
     S.deallocate(localBlock(Local.Offset));
   }
 }
diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp
index 268226a7c143ed8..a63aea1ea5548bc 100644
--- a/clang/test/AST/ByteCode/cxx20.cpp
+++ b/clang/test/AST/ByteCode/cxx20.cpp
@@ -908,3 +908,26 @@ namespace TemporaryInNTTP {
                // expected-note {{created here}}
   B<2> j2; /// Ok.
 }
+
+namespace LocalDestroy {
+  /// This is reduced from a libc++ test case.
+  /// The local f.TI.copied points to the local variable Copied, and we used to
+  /// destroy Copied before f, causing problems later on when a DeadBlock had a
+  /// pointer pointing to it that was already destroyed.
+  struct TrackInitialization {
+    bool *copied_;
+  };
+  struct TrackingPred : TrackInitialization {
+    constexpr TrackingPred(bool *copied) : TrackInitialization(copied) {}
+  };
+  struct F {
+    const TrackingPred &TI;
+  };
+  constexpr int f() {
+    bool Copied = false;
+    TrackingPred TI(&Copied);
+    F f{TI};
+    return 1;
+  }
+  static_assert(f() == 1);
+}



More information about the cfe-commits mailing list