Skip to content

[lldb] Remove UnwindPlan::Row shared_ptrs, lite #134081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Conversation

labath
Copy link
Collaborator

@labath labath commented Apr 2, 2025

Replace with std::unique_ptr. Previous attempt at replacing them with values failed because x86AssemblyInspectionEngine was storing pointers to the rows while modifying the plan. Changing that is relatively easy, but I'm not sure if that's an improvement.

Replace with std::unique_ptr. Previous attempt at replacing them with
values failed because x86AssemblyInspectionEngine was storing pointers
to the rows while modifying the plan. Changing that is relatively easy,
but I'm not sure if that's an improvement.
@labath labath requested review from bulbazord and clayborg April 2, 2025 13:25
@labath labath requested a review from JDevlieghere as a code owner April 2, 2025 13:25
@llvmbot llvmbot added the lldb label Apr 2, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 2, 2025

@llvm/pr-subscribers-lldb

Author: Pavel Labath (labath)

Changes

Replace with std::unique_ptr. Previous attempt at replacing them with values failed because x86AssemblyInspectionEngine was storing pointers to the rows while modifying the plan. Changing that is relatively easy, but I'm not sure if that's an improvement.


Full diff: https://github.com/llvm/llvm-project/pull/134081.diff

2 Files Affected:

  • (modified) lldb/include/lldb/Symbol/UnwindPlan.h (+4-4)
  • (modified) lldb/source/Symbol/UnwindPlan.cpp (+6-6)
diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h b/lldb/include/lldb/Symbol/UnwindPlan.h
index 9adda27b8f928..a0032d6e777c7 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -428,7 +428,7 @@ class UnwindPlan {
     bool m_unspecified_registers_are_undefined = false;
   }; // class Row
 
-  typedef std::shared_ptr<Row> RowSP;
+  typedef std::unique_ptr<Row> RowUP;
 
   UnwindPlan(lldb::RegisterKind reg_kind)
       : m_register_kind(reg_kind), m_return_addr_register(LLDB_INVALID_REGNUM),
@@ -449,8 +449,8 @@ class UnwindPlan {
         m_lsda_address(rhs.m_lsda_address),
         m_personality_func_addr(rhs.m_personality_func_addr) {
     m_row_list.reserve(rhs.m_row_list.size());
-    for (const RowSP &row_sp : rhs.m_row_list)
-      m_row_list.emplace_back(new Row(*row_sp));
+    for (const RowUP &row_up : rhs.m_row_list)
+      m_row_list.emplace_back(new Row(*row_up));
   }
   UnwindPlan(UnwindPlan &&rhs) = default;
   UnwindPlan &operator=(const UnwindPlan &rhs) {
@@ -570,7 +570,7 @@ class UnwindPlan {
   }
 
 private:
-  std::vector<RowSP> m_row_list;
+  std::vector<RowUP> m_row_list;
   std::vector<AddressRange> m_plan_valid_ranges;
   lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers
                                       // are in terms of - will need to be
diff --git a/lldb/source/Symbol/UnwindPlan.cpp b/lldb/source/Symbol/UnwindPlan.cpp
index f2846eb927bf8..6cf96e66a7771 100644
--- a/lldb/source/Symbol/UnwindPlan.cpp
+++ b/lldb/source/Symbol/UnwindPlan.cpp
@@ -392,16 +392,16 @@ bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
 
 void UnwindPlan::AppendRow(Row row) {
   if (m_row_list.empty() || m_row_list.back()->GetOffset() != row.GetOffset())
-    m_row_list.push_back(std::make_shared<Row>(std::move(row)));
+    m_row_list.push_back(std::make_unique<Row>(std::move(row)));
   else
     *m_row_list.back() = std::move(row);
 }
 
 struct RowLess {
-  bool operator()(addr_t a, const UnwindPlan::RowSP &b) const {
+  bool operator()(addr_t a, const UnwindPlan::RowUP &b) const {
     return a < b->GetOffset();
   }
-  bool operator()(const UnwindPlan::RowSP &a, addr_t b) const {
+  bool operator()(const UnwindPlan::RowUP &a, addr_t b) const {
     return a->GetOffset() < b;
   }
 };
@@ -409,7 +409,7 @@ struct RowLess {
 void UnwindPlan::InsertRow(Row row, bool replace_existing) {
   auto it = llvm::lower_bound(m_row_list, row.GetOffset(), RowLess());
   if (it == m_row_list.end() || it->get()->GetOffset() > row.GetOffset())
-    m_row_list.insert(it, std::make_shared<Row>(std::move(row)));
+    m_row_list.insert(it, std::make_unique<Row>(std::move(row)));
   else {
     assert(it->get()->GetOffset() == row.GetOffset());
     if (replace_existing)
@@ -567,9 +567,9 @@ void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
       range.Dump(&s, target_sp.get(), Address::DumpStyleSectionNameOffset);
     s.EOL();
   }
-  for (const auto &[index, row_sp] : llvm::enumerate(m_row_list)) {
+  for (const auto &[index, row_up] : llvm::enumerate(m_row_list)) {
     s.Format("row[{0}]: ", index);
-    row_sp->Dump(s, this, thread, base_addr);
+    row_up->Dump(s, this, thread, base_addr);
     s << "\n";
   }
 }

@labath
Copy link
Collaborator Author

labath commented Apr 2, 2025

FTR, this is what it takes to fix the use after free problem. I didn't do that because it strictly increases the number of copies, and the use pattern is reasonable, but I'd be totally fine with doing that instead (I don't expect anyone will notice the extra copies).

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I got kind of excited by the value semantics, but I don't know how many copies we're talking about and this is an established way to guarantee pointer stability.

@bulbazord
Copy link
Member

LGTM. I'm not sure if it's feasible, but perhaps x86AssemblyInspectionEngine could store an Index to the Row instead? Then you wouldn't need pointers or worry about their stability. UnwindPlan would just need to hand back some kind of row pointer/reference on demand and those should not be stored.

@labath
Copy link
Collaborator Author

labath commented Apr 3, 2025

LGTM. I got kind of excited by the value semantics, but I don't know how many copies we're talking about and this is an established way to guarantee pointer stability.

Yeah, this definitely feels less satisfying. It also feels a bit path-dependent, as I don't think we'd fret over this if Rows were values from the beginning.

So, I tried to make a small benchmark, and according to the results, copying a Row object with three register values (which is one more than what I'd expect for a typical first/last row of an unwind plan) takes about 50 nanoseconds. Copying a row with 100 registers (which is like more that most architectures have) takes ~three microseconds.

With that in mind, maybe we do want to go ahead with d55a1ba ?

LGTM. I'm not sure if it's feasible, but perhaps x86AssemblyInspectionEngine could store an Index to the Row instead? Then you wouldn't need pointers or worry about their stability. UnwindPlan would just need to hand back some kind of row pointer/reference on demand and those should not be stored.

That doesn't quite work here because the code in question is inserting new rows into the middle of the unwind plan, so the index changes as well (for the last row, at least). I mean, I suppose you could try and keep the index up to date, but that's going to be very fragile.

@labath
Copy link
Collaborator Author

labath commented Apr 8, 2025

I see a 👍, so here's the value-semantics version of this. Please approve that PR if you prefer that approach.

@labath
Copy link
Collaborator Author

labath commented Apr 9, 2025

Abandoning in favor of #134821

@labath labath closed this Apr 9, 2025
@labath labath deleted the rowsp branch April 23, 2025 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants