[llvm] 3641e26 - [MsDemangle] Read entire chain of target names in special tables (#155630)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 5 07:48:28 PST 2025
Author: nerix
Date: 2025-11-05T16:48:24+01:00
New Revision: 3641e269b0fdf3614b6a2a068678d8431204a489
URL: https://github.com/llvm/llvm-project/commit/3641e269b0fdf3614b6a2a068678d8431204a489
DIFF: https://github.com/llvm/llvm-project/commit/3641e269b0fdf3614b6a2a068678d8431204a489.diff
LOG: [MsDemangle] Read entire chain of target names in special tables (#155630)
When there's a deep inheritance hierarchy of multiple C++ classes (see
below), then the mangled name of a VFTable can include multiple key
nodes in the target name.
For example, in the following code, MSVC will generate mangled names for
the VFTables that have up to three key classes in the context.
<details><summary>Code</summary>
```cpp
class Base1 {
virtual void a() {};
};
class Base2 {
virtual void b() {}
};
class Ind1 : public Base1 {};
class Ind2 : public Base1 {};
class A : public Ind1, public Ind2 {};
class Ind3 : public A {};
class Ind4 : public A {};
class B : public Ind3, public Ind4 {};
class Ind5 : public B {};
class Ind6 : public B {};
class C : public Ind5, public Ind6 {};
int main() { auto i = new C; }
```
</details>
This will include `??_7C@@6BInd1@@Ind4@@Ind5@@@` (and every other
combination). Microsoft's undname will demangle this to "const
C::\`vftable'{for \`Ind1's \`Ind4's \`Ind5'}". Previously, LLVM would
demangle this to "const C::\`vftable'{for \`Ind1'}".
With this PR, the output of LLVM's undname will be identical to
Microsoft's version. This changes `SpecialTableSymbolNode::TargetName`
to a node array which contains each key from the name. Unlike
namespaces, these keys are not in reverse order - they are in the same
order as in the mangled name.
Added:
Modified:
llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
llvm/lib/Demangle/MicrosoftDemangle.cpp
llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
llvm/test/Demangle/ms-operators.test
Removed:
################################################################################
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..250d382998982 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -15,6 +15,8 @@
#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"
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
@@ -277,6 +279,15 @@ demanglePointerCVQualifiers(std::string_view &MangledName) {
DEMANGLE_UNREACHABLE;
}
+static NodeArrayNode *smallVecToNodeArray(ArenaAllocator &Arena,
+ ArrayRef<Node *> 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
@@ -323,8 +334,19 @@ Demangler::demangleSpecialTableSymbolNode(std::string_view &MangledName,
}
std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName);
- if (!consumeFront(MangledName, '@'))
- STSN->TargetName = demangleFullyQualifiedTypeName(MangledName);
+
+ SmallVector<Node *, 1> TargetNames;
+ while (!consumeFront(MangledName, '@')) {
+ QualifiedNameNode *QN = demangleFullyQualifiedTypeName(MangledName);
+ if (Error)
+ return nullptr;
+ assert(QN);
+ TargetNames.push_back(QN);
+ }
+
+ if (!TargetNames.empty())
+ STSN->TargetNames = smallVecToNodeArray(Arena, TargetNames);
+
return STSN;
}
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}}
More information about the llvm-commits
mailing list