[llvm] Fix llvm::StripTemplateParameters to not return an empty name. (PR #157553)

Greg Clayton via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 12 10:24:58 PDT 2025


https://github.com/clayborg updated https://github.com/llvm/llvm-project/pull/157553

>From b31cccc9b1fb494b39c6ba2bc2430964257f6a29 Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Mon, 8 Sep 2025 13:57:49 -0700
Subject: [PATCH 1/4] Fix llvm::StripTemplateParameters to not return an empty
 name.

llvm::StripTemplateParameters was used to add accelerator table entries to the DWARF accelerator tables by adding and entry for the template name without the template. There is a bug where if a string starts with a '<' character, this function would return an std::optional<StringRef> that was empty. This causes invalid entries to be added to __apple_XXXX accelerator tables where entries with empty strings would be added and were causing issues with the AppleAcceleratorTable::Iterator before the fix that was submitted (https://github.com/llvm/llvm-project/pull/157538).
---
 llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 14 ++++++++------
 .../DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp  | 14 ++++++++++++++
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index ea336378bebb3..5e862e0c233e9 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -248,8 +248,8 @@ LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
     }
 
     for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
-      uint64_t HashOffset = HashesBase + HashIdx*4;
-      uint64_t OffsetsOffset = OffsetsBase + HashIdx*4;
+      uint64_t HashOffset = HashesBase + HashIdx * 4;
+      uint64_t OffsetsOffset = OffsetsBase + HashIdx * 4;
       uint32_t Hash = AccelSection.getU32(&HashOffset);
 
       if (Hash % Hdr.BucketCount != Bucket)
@@ -443,7 +443,7 @@ void DWARFDebugNames::Header::dump(ScopedPrinter &W) const {
 }
 
 Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS,
-                                             uint64_t *Offset) {
+                                       uint64_t *Offset) {
   auto HeaderError = [Offset = *Offset](Error E) {
     return createStringError(errc::illegal_byte_sequence,
                              "parsing .debug_names header at 0x%" PRIx64 ": %s",
@@ -830,8 +830,9 @@ bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W,
   uint64_t EntryId = *Offset;
   auto EntryOr = getEntry(Offset);
   if (!EntryOr) {
-    handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {},
-                    [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
+    handleAllErrors(
+        EntryOr.takeError(), [](const SentinelError &) {},
+        [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
     return false;
   }
 
@@ -1117,7 +1118,8 @@ std::optional<StringRef> llvm::StripTemplateParameters(StringRef Name) {
   //
   // We look for > at the end but if it does not contain any < then we
   // have something like operator>>. We check for the operator<=> case.
-  if (!Name.ends_with(">") || Name.count("<") == 0 || Name.ends_with("<=>"))
+  if (Name.starts_with("<") || !Name.ends_with(">") || Name.count("<") == 0 ||
+      Name.ends_with("<=>"))
     return {};
 
   // How many < until we have the start of the template parameters.
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
index dedcf816cf63f..2265ff9dd42be 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
@@ -299,4 +299,18 @@ TEST(DWARFDebugNames, UnsupportedForm) {
       Sections,
       FailedWithMessage("unsupported Form for YAML debug_names emitter"));
 }
+
+TEST(DWARFDebugNames, TestStripTemplateParameters) {
+
+  std::optional<StringRef> stripped_name;
+  // Make sure we can extract the name "foo" from the template parameters.
+  stripped_name = StripTemplateParameters("foo<int>");
+  ASSERT_TRUE(stripped_name.has_value());
+  ASSERT_EQ(*stripped_name, StringRef("foo"));
+  // Make sure that we don't get an empty name back when the string starts with
+  // '<'.
+  stripped_name = StripTemplateParameters("<int>");
+  ASSERT_FALSE(stripped_name.has_value());
+}
+
 } // end anonymous namespace

>From 6d612bd741985ae73f51277ec0ca567e9ad92c4d Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Tue, 9 Sep 2025 11:08:03 -0700
Subject: [PATCH 2/4] Remove extra clang format changes and fix comment.

---
 llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp    | 11 +++++------
 .../DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp     |  2 +-
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index 5e862e0c233e9..5a9fa7c4c9cb1 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -248,8 +248,8 @@ LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
     }
 
     for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
-      uint64_t HashOffset = HashesBase + HashIdx * 4;
-      uint64_t OffsetsOffset = OffsetsBase + HashIdx * 4;
+      uint64_t HashOffset = HashesBase + HashIdx*4;
+      uint64_t OffsetsOffset = OffsetsBase + HashIdx*4;
       uint32_t Hash = AccelSection.getU32(&HashOffset);
 
       if (Hash % Hdr.BucketCount != Bucket)
@@ -443,7 +443,7 @@ void DWARFDebugNames::Header::dump(ScopedPrinter &W) const {
 }
 
 Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS,
-                                       uint64_t *Offset) {
+                                             uint64_t *Offset) {
   auto HeaderError = [Offset = *Offset](Error E) {
     return createStringError(errc::illegal_byte_sequence,
                              "parsing .debug_names header at 0x%" PRIx64 ": %s",
@@ -830,9 +830,8 @@ bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W,
   uint64_t EntryId = *Offset;
   auto EntryOr = getEntry(Offset);
   if (!EntryOr) {
-    handleAllErrors(
-        EntryOr.takeError(), [](const SentinelError &) {},
-        [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
+    handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {},
+                    [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
     return false;
   }
 
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
index 2265ff9dd42be..82cc02c921d15 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
@@ -307,7 +307,7 @@ TEST(DWARFDebugNames, TestStripTemplateParameters) {
   stripped_name = StripTemplateParameters("foo<int>");
   ASSERT_TRUE(stripped_name.has_value());
   ASSERT_EQ(*stripped_name, StringRef("foo"));
-  // Make sure that we don't get an empty name back when the string starts with
+  // Make sure that we don't get a valid name back when the string starts with
   // '<'.
   stripped_name = StripTemplateParameters("<int>");
   ASSERT_FALSE(stripped_name.has_value());

>From be5014815ebd3698cdbf7eca73a90fce6fa66ec8 Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Thu, 11 Sep 2025 10:59:15 -0700
Subject: [PATCH 3/4] Make sure that if the string is empty that we return
 std::nullopt

---
 llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index 5a9fa7c4c9cb1..bcd3181a81a73 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -1139,5 +1139,8 @@ std::optional<StringRef> llvm::StripTemplateParameters(StringRef Name) {
   while (NumLeftAnglesToSkip--)
     StartOfTemplate = Name.find('<', StartOfTemplate) + 1;
 
-  return Name.substr(0, StartOfTemplate - 1);
+  StringRef Result = Name.substr(0, StartOfTemplate - 1);
+  if (Result.empty())
+    return std::nullopt;
+  return Result;
 }

>From 8442dfb4d360266302bacc4442820687bab46036 Mon Sep 17 00:00:00 2001
From: Greg Clayton <clayborg at gmail.com>
Date: Fri, 12 Sep 2025 10:24:28 -0700
Subject: [PATCH 4/4] Remove check for name starting with '<'.

---
 llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index bcd3181a81a73..4b80a44746127 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -1117,8 +1117,7 @@ std::optional<StringRef> llvm::StripTemplateParameters(StringRef Name) {
   //
   // We look for > at the end but if it does not contain any < then we
   // have something like operator>>. We check for the operator<=> case.
-  if (Name.starts_with("<") || !Name.ends_with(">") || Name.count("<") == 0 ||
-      Name.ends_with("<=>"))
+  if (!Name.ends_with(">") || Name.count("<") == 0 || Name.ends_with("<=>"))
     return {};
 
   // How many < until we have the start of the template parameters.



More information about the llvm-commits mailing list