Skip to content

Commit 3641e26

Browse files
authored
[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.
1 parent d568601 commit 3641e26

File tree

4 files changed

+42
-5
lines changed

4 files changed

+42
-5
lines changed

llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ struct DEMANGLE_ABI SpecialTableSymbolNode : public SymbolNode {
708708
return N->kind() == NodeKind::SpecialTableSymbol;
709709
}
710710

711-
QualifiedNameNode *TargetName = nullptr;
711+
NodeArrayNode *TargetNames = nullptr;
712712
Qualifiers Quals = Qualifiers::Q_None;
713713
};
714714

llvm/lib/Demangle/MicrosoftDemangle.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#include "llvm/Demangle/MicrosoftDemangle.h"
1717

18+
#include "llvm/ADT/ArrayRef.h"
19+
#include "llvm/ADT/SmallVector.h"
1820
#include "llvm/Demangle/Demangle.h"
1921
#include "llvm/Demangle/DemangleConfig.h"
2022
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
@@ -277,6 +279,15 @@ demanglePointerCVQualifiers(std::string_view &MangledName) {
277279
DEMANGLE_UNREACHABLE;
278280
}
279281

282+
static NodeArrayNode *smallVecToNodeArray(ArenaAllocator &Arena,
283+
ArrayRef<Node *> Vec) {
284+
NodeArrayNode *Arr = Arena.alloc<NodeArrayNode>();
285+
Arr->Count = Vec.size();
286+
Arr->Nodes = Arena.allocArray<Node *>(Vec.size());
287+
std::memcpy(Arr->Nodes, Vec.data(), Vec.size() * sizeof(Node *));
288+
return Arr;
289+
}
290+
280291
std::string_view Demangler::copyString(std::string_view Borrowed) {
281292
char *Stable = Arena.allocUnalignedBuffer(Borrowed.size());
282293
// This is not a micro-optimization, it avoids UB, should Borrowed be an null
@@ -323,8 +334,19 @@ Demangler::demangleSpecialTableSymbolNode(std::string_view &MangledName,
323334
}
324335

325336
std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName);
326-
if (!consumeFront(MangledName, '@'))
327-
STSN->TargetName = demangleFullyQualifiedTypeName(MangledName);
337+
338+
SmallVector<Node *, 1> TargetNames;
339+
while (!consumeFront(MangledName, '@')) {
340+
QualifiedNameNode *QN = demangleFullyQualifiedTypeName(MangledName);
341+
if (Error)
342+
return nullptr;
343+
assert(QN);
344+
TargetNames.push_back(QN);
345+
}
346+
347+
if (!TargetNames.empty())
348+
STSN->TargetNames = smallVecToNodeArray(Arena, TargetNames);
349+
328350
return STSN;
329351
}
330352

llvm/lib/Demangle/MicrosoftDemangleNodes.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -662,9 +662,9 @@ void VcallThunkIdentifierNode::output(OutputBuffer &OB,
662662
void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
663663
outputQualifiers(OB, Quals, false, true);
664664
Name->output(OB, Flags);
665-
if (TargetName) {
665+
if (TargetNames) {
666666
OB << "{for `";
667-
TargetName->output(OB, Flags);
667+
TargetNames->output(OB, Flags, "'s `");
668668
OB << "'}";
669669
}
670670
}

llvm/test/Demangle/ms-operators.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,24 @@
143143
??_7A@B@@6BC@D@@@
144144
; CHECK: const B::A::`vftable'{for `D::C'}
145145

146+
??_7A@B@@6BC@D@@E@F@@@
147+
; CHECK: const B::A::`vftable'{for `D::C's `F::E'}
148+
149+
??_7A@B@@6BC@D@@E@F@@G@H@@@
150+
; CHECK: const B::A::`vftable'{for `D::C's `F::E's `H::G'}
151+
146152
??_8Middle2@@7B@
147153
; CHECK: const Middle2::`vbtable'
148154

155+
??_7A@@6BB@@@
156+
; CHECK: const A::`vftable'{for `B'}
157+
158+
??_7A@@6BB@@C@@@
159+
; CHECK: const A::`vftable'{for `B's `C'}
160+
161+
??_7A@@6BB@@C@@D@@@
162+
; CHECK: const A::`vftable'{for `B's `C's `D'}
163+
149164
??_9Base@@$B7AA
150165
; CHECK: [thunk]: __cdecl Base::`vcall'{8, {flat}}
151166

0 commit comments

Comments
 (0)