[llvm] [MsDemangle] Read entire chain of target names in special tables (PR #155630)

via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 5 07:02:29 PST 2025


https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/155630

>From 99582cddc79f98bf499a87b4c8683e57438e6a90 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 27 Aug 2025 15:58:02 +0200
Subject: [PATCH 1/3] [MsDemangle] Read entire chain of target names in special
 table

---
 .../llvm/Demangle/MicrosoftDemangleNodes.h    |  2 +-
 llvm/lib/Demangle/MicrosoftDemangle.cpp       | 50 +++++++++++++------
 llvm/lib/Demangle/MicrosoftDemangleNodes.cpp  |  4 +-
 llvm/test/Demangle/ms-operators.test          | 15 ++++++
 4 files changed, 54 insertions(+), 17 deletions(-)

diff --git a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
index 155cfe8dd3a98..711aa70a4a8d3 100644
--- a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
+++ b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
@@ -708,7 +708,7 @@ struct DEMANGLE_ABI SpecialTableSymbolNode : public SymbolNode {
     return N->kind() == NodeKind::SpecialTableSymbol;
   }
 
-  QualifiedNameNode *TargetName = nullptr;
+  NodeArrayNode *TargetNames = nullptr;
   Qualifiers Quals = Qualifiers::Q_None;
 };
 
diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index b22928be3be50..0aefe6e077c24 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -277,6 +277,18 @@ demanglePointerCVQualifiers(std::string_view &MangledName) {
   DEMANGLE_UNREACHABLE;
 }
 
+static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,
+                                          size_t Count) {
+  NodeArrayNode *N = Arena.alloc<NodeArrayNode>();
+  N->Count = Count;
+  N->Nodes = Arena.allocArray<Node *>(Count);
+  for (size_t I = 0; I < Count; ++I) {
+    N->Nodes[I] = Head->N;
+    Head = Head->Next;
+  }
+  return N;
+}
+
 std::string_view Demangler::copyString(std::string_view Borrowed) {
   char *Stable = Arena.allocUnalignedBuffer(Borrowed.size());
   // This is not a micro-optimization, it avoids UB, should Borrowed be an null
@@ -323,8 +335,30 @@ Demangler::demangleSpecialTableSymbolNode(std::string_view &MangledName,
   }
 
   std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName);
-  if (!consumeFront(MangledName, '@'))
-    STSN->TargetName = demangleFullyQualifiedTypeName(MangledName);
+
+  NodeList *TargetCurrent = nullptr;
+  NodeList *TargetHead = nullptr;
+  size_t Count = 0;
+  while (!consumeFront(MangledName, '@')) {
+    ++Count;
+
+    NodeList *Next = Arena.alloc<NodeList>();
+    if (TargetCurrent)
+      TargetCurrent->Next = Next;
+    else
+      TargetHead = Next;
+
+    TargetCurrent = Next;
+    QualifiedNameNode *QN = demangleFullyQualifiedTypeName(MangledName);
+    if (Error)
+      return nullptr;
+    assert(QN);
+    TargetCurrent->N = QN;
+  }
+
+  if (Count > 0)
+    STSN->TargetNames = nodeListToNodeArray(Arena, TargetHead, Count);
+
   return STSN;
 }
 
@@ -1605,18 +1639,6 @@ Demangler::demangleNameScopePiece(std::string_view &MangledName) {
   return demangleSimpleName(MangledName, /*Memorize=*/true);
 }
 
-static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,
-                                          size_t Count) {
-  NodeArrayNode *N = Arena.alloc<NodeArrayNode>();
-  N->Count = Count;
-  N->Nodes = Arena.allocArray<Node *>(Count);
-  for (size_t I = 0; I < Count; ++I) {
-    N->Nodes[I] = Head->N;
-    Head = Head->Next;
-  }
-  return N;
-}
-
 QualifiedNameNode *
 Demangler::demangleNameScopeChain(std::string_view &MangledName,
                                   IdentifierNode *UnqualifiedName) {
diff --git a/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
index 61e4961c714bc..17c6aab500049 100644
--- a/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
@@ -662,9 +662,9 @@ void VcallThunkIdentifierNode::output(OutputBuffer &OB,
 void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
   outputQualifiers(OB, Quals, false, true);
   Name->output(OB, Flags);
-  if (TargetName) {
+  if (TargetNames) {
     OB << "{for `";
-    TargetName->output(OB, Flags);
+    TargetNames->output(OB, Flags, "'s `");
     OB << "'}";
   }
 }
diff --git a/llvm/test/Demangle/ms-operators.test b/llvm/test/Demangle/ms-operators.test
index b940488786631..cafa1ae3c0663 100644
--- a/llvm/test/Demangle/ms-operators.test
+++ b/llvm/test/Demangle/ms-operators.test
@@ -143,9 +143,24 @@
 ??_7A at B@@6BC at D@@@
 ; CHECK: const B::A::`vftable'{for `D::C'}
 
+??_7A at B@@6BC at D@@E at F@@@
+; CHECK: const B::A::`vftable'{for `D::C's `F::E'}
+
+??_7A at B@@6BC at D@@E at F@@G at H@@@
+; CHECK: const B::A::`vftable'{for `D::C's `F::E's `H::G'}
+
 ??_8Middle2@@7B@
 ; CHECK: const Middle2::`vbtable'
 
+??_7A@@6BB@@@
+; CHECK: const A::`vftable'{for `B'}
+
+??_7A@@6BB@@C@@@
+; CHECK: const A::`vftable'{for `B's `C'}
+
+??_7A@@6BB@@C@@D@@@
+; CHECK: const A::`vftable'{for `B's `C's `D'}
+
 ??_9Base@@$B7AA
 ; CHECK: [thunk]: __cdecl Base::`vcall'{8, {flat}}
 

>From 544e9d2f383179b8c6f0972009ce719e7f1cc0c9 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 5 Nov 2025 15:23:54 +0100
Subject: [PATCH 2/3] fix: use small vector

---
 llvm/lib/Demangle/MicrosoftDemangle.cpp | 30 ++++++++++++-------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index 0aefe6e077c24..f5013640d162a 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -15,6 +15,7 @@
 
 #include "llvm/Demangle/MicrosoftDemangle.h"
 
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Demangle/Demangle.h"
 #include "llvm/Demangle/DemangleConfig.h"
 #include "llvm/Demangle/MicrosoftDemangleNodes.h"
@@ -289,6 +290,16 @@ static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,
   return N;
 }
 
+template <unsigned N>
+static NodeArrayNode *smallVecToNodeArray(ArenaAllocator &Arena,
+                                          const SmallVector<Node *, N> &Vec) {
+  NodeArrayNode *Arr = Arena.alloc<NodeArrayNode>();
+  Arr->Count = Vec.size();
+  Arr->Nodes = Arena.allocArray<Node *>(Vec.size());
+  std::memcpy(Arr->Nodes, Vec.data(), Vec.size() * sizeof(Node *));
+  return Arr;
+}
+
 std::string_view Demangler::copyString(std::string_view Borrowed) {
   char *Stable = Arena.allocUnalignedBuffer(Borrowed.size());
   // This is not a micro-optimization, it avoids UB, should Borrowed be an null
@@ -336,28 +347,17 @@ Demangler::demangleSpecialTableSymbolNode(std::string_view &MangledName,
 
   std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName);
 
-  NodeList *TargetCurrent = nullptr;
-  NodeList *TargetHead = nullptr;
-  size_t Count = 0;
+  SmallVector<Node *, 1> TargetNames;
   while (!consumeFront(MangledName, '@')) {
-    ++Count;
-
-    NodeList *Next = Arena.alloc<NodeList>();
-    if (TargetCurrent)
-      TargetCurrent->Next = Next;
-    else
-      TargetHead = Next;
-
-    TargetCurrent = Next;
     QualifiedNameNode *QN = demangleFullyQualifiedTypeName(MangledName);
     if (Error)
       return nullptr;
     assert(QN);
-    TargetCurrent->N = QN;
+    TargetNames.push_back(QN);
   }
 
-  if (Count > 0)
-    STSN->TargetNames = nodeListToNodeArray(Arena, TargetHead, Count);
+  if (!TargetNames.empty())
+    STSN->TargetNames = smallVecToNodeArray(Arena, TargetNames);
 
   return STSN;
 }

>From 7e181010d715aa64349ecd17c43e5468e65978e5 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 5 Nov 2025 16:02:11 +0100
Subject: [PATCH 3/3] fix: use ArrayRef and move nodeListToNodeArray back

---
 llvm/lib/Demangle/MicrosoftDemangle.cpp | 28 ++++++++++++-------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index f5013640d162a..250d382998982 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -15,6 +15,7 @@
 
 #include "llvm/Demangle/MicrosoftDemangle.h"
 
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Demangle/Demangle.h"
 #include "llvm/Demangle/DemangleConfig.h"
@@ -278,21 +279,8 @@ demanglePointerCVQualifiers(std::string_view &MangledName) {
   DEMANGLE_UNREACHABLE;
 }
 
-static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,
-                                          size_t Count) {
-  NodeArrayNode *N = Arena.alloc<NodeArrayNode>();
-  N->Count = Count;
-  N->Nodes = Arena.allocArray<Node *>(Count);
-  for (size_t I = 0; I < Count; ++I) {
-    N->Nodes[I] = Head->N;
-    Head = Head->Next;
-  }
-  return N;
-}
-
-template <unsigned N>
 static NodeArrayNode *smallVecToNodeArray(ArenaAllocator &Arena,
-                                          const SmallVector<Node *, N> &Vec) {
+                                          ArrayRef<Node *> Vec) {
   NodeArrayNode *Arr = Arena.alloc<NodeArrayNode>();
   Arr->Count = Vec.size();
   Arr->Nodes = Arena.allocArray<Node *>(Vec.size());
@@ -1639,6 +1627,18 @@ Demangler::demangleNameScopePiece(std::string_view &MangledName) {
   return demangleSimpleName(MangledName, /*Memorize=*/true);
 }
 
+static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,
+                                          size_t Count) {
+  NodeArrayNode *N = Arena.alloc<NodeArrayNode>();
+  N->Count = Count;
+  N->Nodes = Arena.allocArray<Node *>(Count);
+  for (size_t I = 0; I < Count; ++I) {
+    N->Nodes[I] = Head->N;
+    Head = Head->Next;
+  }
+  return N;
+}
+
 QualifiedNameNode *
 Demangler::demangleNameScopeChain(std::string_view &MangledName,
                                   IdentifierNode *UnqualifiedName) {



More information about the llvm-commits mailing list