aboutsummaryrefslogtreecommitdiff
path: root/lib/Demangle/MicrosoftDemangle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Demangle/MicrosoftDemangle.cpp')
-rw-r--r--lib/Demangle/MicrosoftDemangle.cpp397
1 files changed, 262 insertions, 135 deletions
diff --git a/lib/Demangle/MicrosoftDemangle.cpp b/lib/Demangle/MicrosoftDemangle.cpp
index 51ffa0bff7f3..bf7d77638f34 100644
--- a/lib/Demangle/MicrosoftDemangle.cpp
+++ b/lib/Demangle/MicrosoftDemangle.cpp
@@ -1,9 +1,8 @@
//===- MicrosoftDemangle.cpp ----------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -18,7 +17,7 @@
#include "llvm/Demangle/Demangle.h"
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
-#include "llvm/Demangle/Compiler.h"
+#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/StringView.h"
#include "llvm/Demangle/Utility.h"
@@ -59,14 +58,18 @@ static bool isMemberPointer(StringView MangledName, bool &Error) {
// what.
break;
default:
- Error = true;
- return false;
+ // isMemberPointer() is called only if isPointerType() returns true,
+ // and it rejects other prefixes.
+ DEMANGLE_UNREACHABLE;
}
// If it starts with a number, then 6 indicates a non-member function
// pointer, and 8 indicates a member function pointer.
if (startsWithDigit(MangledName)) {
- assert(MangledName[0] == '6' || MangledName[0] == '8');
+ if (MangledName[0] != '6' && MangledName[0] != '8') {
+ Error = true;
+ return false;
+ }
return (MangledName[0] == '8');
}
@@ -76,7 +79,10 @@ static bool isMemberPointer(StringView MangledName, bool &Error) {
MangledName.consumeFront('I'); // restrict
MangledName.consumeFront('F'); // unaligned
- assert(!MangledName.empty());
+ if (MangledName.empty()) {
+ Error = true;
+ return false;
+ }
// The next value should be either ABCD (non-member) or QRST (member).
switch (MangledName.front()) {
@@ -136,8 +142,6 @@ consumeSpecialIntrinsicKind(StringView &MangledName) {
static bool startsWithLocalScopePattern(StringView S) {
if (!S.consumeFront('?'))
return false;
- if (S.size() < 2)
- return false;
size_t End = S.find('?');
if (End == StringView::npos)
@@ -234,10 +238,10 @@ demanglePointerCVQualifiers(StringView &MangledName) {
case 'S':
return std::make_pair(Qualifiers(Q_Const | Q_Volatile),
PointerAffinity::Pointer);
- default:
- assert(false && "Ty is not a pointer type!");
}
- return std::make_pair(Q_None, PointerAffinity::Pointer);
+ // This function is only called if isPointerType() returns true,
+ // and it only returns true for the six cases listed above.
+ DEMANGLE_UNREACHABLE;
}
StringView Demangler::copyString(StringView Borrowed) {
@@ -265,12 +269,16 @@ Demangler::demangleSpecialTableSymbolNode(StringView &MangledName,
NI->Name = "`RTTI Complete Object Locator'";
break;
default:
- LLVM_BUILTIN_UNREACHABLE;
+ DEMANGLE_UNREACHABLE;
}
QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);
SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>();
STSN->Name = QN;
bool IsMember = false;
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
char Front = MangledName.popFront();
if (Front != '6' && Front != '7') {
Error = true;
@@ -284,9 +292,10 @@ Demangler::demangleSpecialTableSymbolNode(StringView &MangledName,
}
LocalStaticGuardVariableNode *
-Demangler::demangleLocalStaticGuard(StringView &MangledName) {
+Demangler::demangleLocalStaticGuard(StringView &MangledName, bool IsThread) {
LocalStaticGuardIdentifierNode *LSGI =
Arena.alloc<LocalStaticGuardIdentifierNode>();
+ LSGI->IsThread = IsThread;
QualifiedNameNode *QN = demangleNameScopeChain(MangledName, LSGI);
LocalStaticGuardVariableNode *LSGVN =
Arena.alloc<LocalStaticGuardVariableNode>();
@@ -379,11 +388,11 @@ FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName,
if (MangledName.consumeFront('?'))
IsKnownStaticDataMember = true;
- QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName);
+ SymbolNode *Symbol = demangleDeclarator(MangledName);
+ if (Error)
+ return nullptr;
- SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN);
FunctionSymbolNode *FSN = nullptr;
- Symbol->Name = QN;
if (Symbol->kind() == NodeKind::VariableSymbol) {
DSIN->Variable = static_cast<VariableSymbolNode *>(Symbol);
@@ -401,7 +410,8 @@ FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName,
}
FSN = demangleFunctionEncoding(MangledName);
- FSN->Name = synthesizeQualifiedName(Arena, DSIN);
+ if (FSN)
+ FSN->Name = synthesizeQualifiedName(Arena, DSIN);
} else {
if (IsKnownStaticDataMember) {
// This was supposed to be a static data member, but we got a function.
@@ -419,10 +429,10 @@ FunctionSymbolNode *Demangler::demangleInitFiniStub(StringView &MangledName,
SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) {
SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName);
- if (SIK == SpecialIntrinsicKind::None)
- return nullptr;
switch (SIK) {
+ case SpecialIntrinsicKind::None:
+ return nullptr;
case SpecialIntrinsicKind::StringLiteralSymbol:
return demangleStringLiteral(MangledName);
case SpecialIntrinsicKind::Vftable:
@@ -433,7 +443,9 @@ SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) {
case SpecialIntrinsicKind::VcallThunk:
return demangleVcallThunkNode(MangledName);
case SpecialIntrinsicKind::LocalStaticGuard:
- return demangleLocalStaticGuard(MangledName);
+ return demangleLocalStaticGuard(MangledName, /*IsThread=*/false);
+ case SpecialIntrinsicKind::LocalStaticThreadGuard:
+ return demangleLocalStaticGuard(MangledName, /*IsThread=*/true);
case SpecialIntrinsicKind::RttiTypeDescriptor: {
TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result);
if (Error)
@@ -453,11 +465,16 @@ SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) {
case SpecialIntrinsicKind::RttiBaseClassDescriptor:
return demangleRttiBaseClassDescriptorNode(Arena, MangledName);
case SpecialIntrinsicKind::DynamicInitializer:
- return demangleInitFiniStub(MangledName, false);
+ return demangleInitFiniStub(MangledName, /*IsDestructor=*/false);
case SpecialIntrinsicKind::DynamicAtexitDestructor:
- return demangleInitFiniStub(MangledName, true);
- default:
+ return demangleInitFiniStub(MangledName, /*IsDestructor=*/true);
+ case SpecialIntrinsicKind::Typeof:
+ case SpecialIntrinsicKind::UdtReturning:
+ // It's unclear which tools produces these manglings, so demangling
+ // support is not (yet?) implemented.
break;
+ case SpecialIntrinsicKind::Unknown:
+ DEMANGLE_UNREACHABLE; // Never returned by consumeSpecialIntrinsicKind.
}
Error = true;
return nullptr;
@@ -467,11 +484,15 @@ IdentifierNode *
Demangler::demangleFunctionIdentifierCode(StringView &MangledName) {
assert(MangledName.startsWith('?'));
MangledName = MangledName.dropFront();
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
if (MangledName.consumeFront("__"))
return demangleFunctionIdentifierCode(
MangledName, FunctionIdentifierCodeGroup::DoubleUnder);
- else if (MangledName.consumeFront("_"))
+ if (MangledName.consumeFront("_"))
return demangleFunctionIdentifierCode(MangledName,
FunctionIdentifierCodeGroup::Under);
return demangleFunctionIdentifierCode(MangledName,
@@ -497,16 +518,22 @@ LiteralOperatorIdentifierNode *
Demangler::demangleLiteralOperatorIdentifier(StringView &MangledName) {
LiteralOperatorIdentifierNode *N =
Arena.alloc<LiteralOperatorIdentifierNode>();
- N->Name = demangleSimpleString(MangledName, false);
+ N->Name = demangleSimpleString(MangledName, /*Memorize=*/false);
return N;
}
-static IntrinsicFunctionKind
-translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group) {
+IntrinsicFunctionKind
+Demangler::translateIntrinsicFunctionCode(char CH,
+ FunctionIdentifierCodeGroup Group) {
+ using IFK = IntrinsicFunctionKind;
+ if (!(CH >= '0' && CH <= '9') && !(CH >= 'A' && CH <= 'Z')) {
+ Error = true;
+ return IFK::None;
+ }
+
// Not all ? identifiers are intrinsics *functions*. This function only maps
// operator codes for the special functions, all others are handled elsewhere,
// hence the IFK::None entries in the table.
- using IFK = IntrinsicFunctionKind;
static IFK Basic[36] = {
IFK::None, // ?0 # Foo::Foo()
IFK::None, // ?1 # Foo::~Foo()
@@ -606,8 +633,8 @@ translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group) {
// iter
IFK::None, // ?__J local static thread guard
IFK::None, // ?__K operator ""_name
- IFK::CoAwait, // ?__L co_await
- IFK::None, // ?__M <unused>
+ IFK::CoAwait, // ?__L operator co_await
+ IFK::Spaceship, // ?__M operator<=>
IFK::None, // ?__N <unused>
IFK::None, // ?__O <unused>
IFK::None, // ?__P <unused>
@@ -632,12 +659,16 @@ translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group) {
case FunctionIdentifierCodeGroup::DoubleUnder:
return DoubleUnder[Index];
}
- LLVM_BUILTIN_UNREACHABLE;
+ DEMANGLE_UNREACHABLE;
}
IdentifierNode *
Demangler::demangleFunctionIdentifierCode(StringView &MangledName,
FunctionIdentifierCodeGroup Group) {
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
switch (Group) {
case FunctionIdentifierCodeGroup::Basic:
switch (char CH = MangledName.popFront()) {
@@ -650,7 +681,6 @@ Demangler::demangleFunctionIdentifierCode(StringView &MangledName,
return Arena.alloc<IntrinsicFunctionIdentifierNode>(
translateIntrinsicFunctionCode(CH, Group));
}
- break;
case FunctionIdentifierCodeGroup::Under:
return Arena.alloc<IntrinsicFunctionIdentifierNode>(
translateIntrinsicFunctionCode(MangledName.popFront(), Group));
@@ -663,13 +693,17 @@ Demangler::demangleFunctionIdentifierCode(StringView &MangledName,
translateIntrinsicFunctionCode(CH, Group));
}
}
- // No Mangling Yet: Spaceship, // operator<=>
- return nullptr;
+ DEMANGLE_UNREACHABLE;
}
SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName,
QualifiedNameNode *Name) {
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+
// Read a variable.
switch (MangledName.front()) {
case '0':
@@ -680,8 +714,6 @@ SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName,
StorageClass SC = demangleVariableStorageClass(MangledName);
return demangleVariableEncoding(MangledName, SC);
}
- case '8':
- return nullptr;
}
FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName);
@@ -689,23 +721,74 @@ SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName,
if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {
ConversionOperatorIdentifierNode *COIN =
static_cast<ConversionOperatorIdentifierNode *>(UQN);
- COIN->TargetType = FSN->Signature->ReturnType;
+ if (FSN)
+ COIN->TargetType = FSN->Signature->ReturnType;
}
return FSN;
}
+SymbolNode *Demangler::demangleDeclarator(StringView &MangledName) {
+ // What follows is a main symbol name. This may include namespaces or class
+ // back references.
+ QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName);
+ if (Error)
+ return nullptr;
+
+ SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN);
+ if (Error)
+ return nullptr;
+ Symbol->Name = QN;
+
+ IdentifierNode *UQN = QN->getUnqualifiedIdentifier();
+ if (UQN->kind() == NodeKind::ConversionOperatorIdentifier) {
+ ConversionOperatorIdentifierNode *COIN =
+ static_cast<ConversionOperatorIdentifierNode *>(UQN);
+ if (!COIN->TargetType) {
+ Error = true;
+ return nullptr;
+ }
+ }
+ return Symbol;
+}
+
+SymbolNode *Demangler::demangleMD5Name(StringView &MangledName) {
+ assert(MangledName.startsWith("??@"));
+ // This is an MD5 mangled name. We can't demangle it, just return the
+ // mangled name.
+ // An MD5 mangled name is ??@ followed by 32 characters and a terminating @.
+ size_t MD5Last = MangledName.find('@', strlen("??@"));
+ if (MD5Last == StringView::npos) {
+ Error = true;
+ return nullptr;
+ }
+ const char *Start = MangledName.begin();
+ MangledName = MangledName.dropFront(MD5Last + 1);
+
+ // There are two additional special cases for MD5 names:
+ // 1. For complete object locators where the object name is long enough
+ // for the object to have an MD5 name, the complete object locator is
+ // called ??@...@??_R4@ (with a trailing "??_R4@" instead of the usual
+ // leading "??_R4". This is handled here.
+ // 2. For catchable types, in versions of MSVC before 2015 (<1900) or after
+ // 2017.2 (>= 1914), the catchable type mangling is _CT??@...@??@...@8
+ // instead of_CT??@...@8 with just one MD5 name. Since we don't yet
+ // demangle catchable types anywhere, this isn't handled for MD5 names
+ // either.
+ MangledName.consumeFront("??_R4@");
+
+ StringView MD5(Start, MangledName.begin());
+ SymbolNode *S = Arena.alloc<SymbolNode>(NodeKind::Md5Symbol);
+ S->Name = synthesizeQualifiedName(Arena, MD5);
+
+ return S;
+}
+
// Parser entry point.
SymbolNode *Demangler::parse(StringView &MangledName) {
- // We can't demangle MD5 names, just output them as-is.
- // Also, MSVC-style mangled symbols must start with '?'.
- if (MangledName.startsWith("??@")) {
- // This is an MD5 mangled name. We can't demangle it, just return the
- // mangled name.
- SymbolNode *S = Arena.alloc<SymbolNode>(NodeKind::Md5Symbol);
- S->Name = synthesizeQualifiedName(Arena, MangledName);
- return S;
- }
+ if (MangledName.startsWith("??@"))
+ return demangleMD5Name(MangledName);
+ // MSVC-style mangled symbols must start with '?'.
if (!MangledName.startsWith('?')) {
Error = true;
return nullptr;
@@ -718,21 +801,7 @@ SymbolNode *Demangler::parse(StringView &MangledName) {
if (SymbolNode *SI = demangleSpecialIntrinsic(MangledName))
return SI;
- // What follows is a main symbol name. This may include namespaces or class
- // back references.
- QualifiedNameNode *QN = demangleFullyQualifiedSymbolName(MangledName);
- if (Error)
- return nullptr;
-
- SymbolNode *Symbol = demangleEncodedSymbol(MangledName, QN);
- if (Symbol) {
- Symbol->Name = QN;
- }
-
- if (Error)
- return nullptr;
-
- return Symbol;
+ return demangleDeclarator(MangledName);
}
TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) {
@@ -759,6 +828,9 @@ VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName,
VSN->Type = demangleType(MangledName, QualifierMangleMode::Drop);
VSN->SC = SC;
+ if (Error)
+ return nullptr;
+
// <variable-type> ::= <type> <cvr-qualifiers>
// ::= <type> <pointee-cvr-qualifiers> # pointers, references
switch (VSN->Type->kind()) {
@@ -797,7 +869,7 @@ VariableSymbolNode *Demangler::demangleVariableEncoding(StringView &MangledName,
// <number> ::= [?] <non-negative integer>
//
// <non-negative integer> ::= <decimal digit> # when 1 <= Number <= 10
-// ::= <hex digit>+ @ # when Numbrer == 0 or >= 10
+// ::= <hex digit>+ @ # when Number == 0 or >= 10
//
// <hex-digit> ::= [A-P] # A = 0, B = 1, ...
std::pair<uint64_t, bool> Demangler::demangleNumber(StringView &MangledName) {
@@ -906,8 +978,18 @@ Demangler::demangleTemplateInstantiationName(StringView &MangledName,
if (Error)
return nullptr;
- if (NBB & NBB_Template)
+ if (NBB & NBB_Template) {
+ // NBB_Template is only set for types and non-leaf names ("a::" in "a::b").
+ // Structors and conversion operators only makes sense in a leaf name, so
+ // reject them in NBB_Template contexts.
+ if (Identifier->kind() == NodeKind::ConversionOperatorIdentifier ||
+ Identifier->kind() == NodeKind::StructorIdentifier) {
+ Error = true;
+ return nullptr;
+ }
+
memorizeIdentifier(Identifier);
+ }
return Identifier;
}
@@ -931,6 +1013,7 @@ static uint8_t rebasedHexDigitToNumber(char C) {
}
uint8_t Demangler::demangleCharLiteral(StringView &MangledName) {
+ assert(!MangledName.empty());
if (!MangledName.startsWith('?'))
return MangledName.popFront();
@@ -988,7 +1071,7 @@ wchar_t Demangler::demangleWcharLiteral(StringView &MangledName) {
uint8_t C1, C2;
C1 = demangleCharLiteral(MangledName);
- if (Error)
+ if (Error || MangledName.empty())
goto WCharLiteralError;
C2 = demangleCharLiteral(MangledName);
if (Error)
@@ -1007,10 +1090,8 @@ static void writeHexDigit(char *Buffer, uint8_t Digit) {
}
static void outputHex(OutputStream &OS, unsigned C) {
- if (C == 0) {
- OS << "\\x00";
- return;
- }
+ assert (C != 0);
+
// It's easier to do the math if we can work from right to left, but we need
// to print the numbers from left to right. So render this into a temporary
// buffer first, then output the temporary buffer. Each byte is of the form
@@ -1019,23 +1100,26 @@ static void outputHex(OutputStream &OS, unsigned C) {
char TempBuffer[17];
::memset(TempBuffer, 0, sizeof(TempBuffer));
- constexpr int MaxPos = 15;
+ constexpr int MaxPos = sizeof(TempBuffer) - 1;
- int Pos = MaxPos - 1;
+ int Pos = MaxPos - 1; // TempBuffer[MaxPos] is the terminating \0.
while (C != 0) {
for (int I = 0; I < 2; ++I) {
writeHexDigit(&TempBuffer[Pos--], C % 16);
C /= 16;
}
- TempBuffer[Pos--] = 'x';
- TempBuffer[Pos--] = '\\';
- assert(Pos >= 0);
}
+ TempBuffer[Pos--] = 'x';
+ assert(Pos >= 0);
+ TempBuffer[Pos--] = '\\';
OS << StringView(&TempBuffer[Pos + 1]);
}
static void outputEscapedChar(OutputStream &OS, unsigned C) {
switch (C) {
+ case '\0': // nul
+ OS << "\\0";
+ return;
case '\'': // single quote
OS << "\\\'";
return;
@@ -1100,8 +1184,11 @@ static unsigned countEmbeddedNulls(const uint8_t *StringBytes,
return Result;
}
+// A mangled (non-wide) string literal stores the total length of the string it
+// refers to (passed in NumBytes), and it contains up to 32 bytes of actual text
+// (passed in StringBytes, NumChars).
static unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars,
- unsigned NumBytes) {
+ uint64_t NumBytes) {
assert(NumBytes > 0);
// If the number of bytes is odd, this is guaranteed to be a char string.
@@ -1113,7 +1200,7 @@ static unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars,
// 2-byte, or 4-byte null terminator.
if (NumBytes < 32) {
unsigned TrailingNulls = countTrailingNullBytes(StringBytes, NumChars);
- if (TrailingNulls >= 4)
+ if (TrailingNulls >= 4 && NumBytes % 4 == 0)
return 4;
if (TrailingNulls >= 2)
return 2;
@@ -1127,7 +1214,7 @@ static unsigned guessCharByteSize(const uint8_t *StringBytes, unsigned NumChars,
// perfect and is biased towards languages that have ascii alphabets, but this
// was always going to be best effort since the encoding is lossy.
unsigned Nulls = countEmbeddedNulls(StringBytes, NumChars);
- if (Nulls >= 2 * NumChars / 3)
+ if (Nulls >= 2 * NumChars / 3 && NumBytes % 4 == 0)
return 4;
if (Nulls >= NumChars / 3)
return 2;
@@ -1178,6 +1265,11 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>();
+ // Must happen before the first `goto StringLiteralError`.
+ if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
+ // FIXME: Propagate out-of-memory as an error?
+ std::terminate();
+
// Prefix indicating the beginning of a string literal
if (!MangledName.consumeFront("@_"))
goto StringLiteralError;
@@ -1188,7 +1280,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
switch (MangledName.popFront()) {
case '1':
IsWcharT = true;
- LLVM_FALLTHROUGH;
+ DEMANGLE_FALLTHROUGH;
case '0':
break;
default:
@@ -1197,7 +1289,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
// Encoded Length
std::tie(StringByteSize, IsNegative) = demangleNumber(MangledName);
- if (Error || IsNegative)
+ if (Error || IsNegative || StringByteSize < (IsWcharT ? 2 : 1))
goto StringLiteralError;
// CRC 32 (always 8 characters plus a terminator)
@@ -1209,16 +1301,14 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
if (MangledName.empty())
goto StringLiteralError;
- if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
- // FIXME: Propagate out-of-memory as an error?
- std::terminate();
if (IsWcharT) {
Result->Char = CharKind::Wchar;
if (StringByteSize > 64)
Result->IsTruncated = true;
while (!MangledName.consumeFront('@')) {
- assert(StringByteSize >= 2);
+ if (MangledName.size() < 2)
+ goto StringLiteralError;
wchar_t W = demangleWcharLiteral(MangledName);
if (StringByteSize != 2 || Result->IsTruncated)
outputEscapedChar(OS, W);
@@ -1234,7 +1324,8 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
unsigned BytesDecoded = 0;
while (!MangledName.consumeFront('@')) {
- assert(StringByteSize >= 1);
+ if (MangledName.size() < 1 || BytesDecoded >= MaxStringByteLength)
+ goto StringLiteralError;
StringBytes[BytesDecoded++] = demangleCharLiteral(MangledName);
}
@@ -1255,7 +1346,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
Result->Char = CharKind::Char32;
break;
default:
- LLVM_BUILTIN_UNREACHABLE;
+ DEMANGLE_UNREACHABLE;
}
const unsigned NumChars = BytesDecoded / CharBytes;
for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) {
@@ -1274,15 +1365,20 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
StringLiteralError:
Error = true;
+ std::free(OS.getBuffer());
return nullptr;
}
+// Returns MangledName's prefix before the first '@', or an error if
+// MangledName contains no '@' or the prefix has length 0.
StringView Demangler::demangleSimpleString(StringView &MangledName,
bool Memorize) {
StringView S;
for (size_t i = 0; i < MangledName.size(); ++i) {
if (MangledName[i] != '@')
continue;
+ if (i == 0)
+ break;
S = MangledName.substr(0, i);
MangledName = MangledName.dropFront(i + 1);
@@ -1319,8 +1415,10 @@ Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {
NamedIdentifierNode *Identifier = Arena.alloc<NamedIdentifierNode>();
MangledName.consumeFront('?');
- auto Number = demangleNumber(MangledName);
- assert(!Number.second);
+ uint64_t Number = 0;
+ bool IsNegative = false;
+ std::tie(Number, IsNegative) = demangleNumber(MangledName);
+ assert(!IsNegative);
// One ? to terminate the number
MangledName.consumeFront('?');
@@ -1338,7 +1436,7 @@ Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {
OS << '`';
Scope->output(OS, OF_Default);
OS << '\'';
- OS << "::`" << Number.first << "'";
+ OS << "::`" << Number << "'";
OS << '\0';
char *Result = OS.getBuffer();
Identifier->Name = copyString(Result);
@@ -1349,7 +1447,8 @@ Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {
// Parses a type name in the form of A@B@C@@ which represents C::B::A.
QualifiedNameNode *
Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) {
- IdentifierNode *Identifier = demangleUnqualifiedTypeName(MangledName, true);
+ IdentifierNode *Identifier =
+ demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true);
if (Error)
return nullptr;
assert(Identifier);
@@ -1381,9 +1480,12 @@ Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) {
return nullptr;
if (Identifier->kind() == NodeKind::StructorIdentifier) {
+ if (QN->Components->Count < 2) {
+ Error = true;
+ return nullptr;
+ }
StructorIdentifierNode *SIN =
static_cast<StructorIdentifierNode *>(Identifier);
- assert(QN->Components->Count >= 2);
Node *ClassNode = QN->Components->Nodes[QN->Components->Count - 2];
SIN->Class = static_cast<IdentifierNode *>(ClassNode);
}
@@ -1415,7 +1517,7 @@ Demangler::demangleUnqualifiedSymbolName(StringView &MangledName,
return demangleTemplateInstantiationName(MangledName, NBB);
if (MangledName.startsWith('?'))
return demangleFunctionIdentifierCode(MangledName);
- return demangleSimpleName(MangledName, (NBB & NBB_Simple) != 0);
+ return demangleSimpleName(MangledName, /*Memorize=*/(NBB & NBB_Simple) != 0);
}
IdentifierNode *Demangler::demangleNameScopePiece(StringView &MangledName) {
@@ -1431,7 +1533,7 @@ IdentifierNode *Demangler::demangleNameScopePiece(StringView &MangledName) {
if (startsWithLocalScopePattern(MangledName))
return demangleLocallyScopedNamePiece(MangledName);
- return demangleSimpleName(MangledName, true);
+ return demangleSimpleName(MangledName, /*Memorize=*/true);
}
static NodeArrayNode *nodeListToNodeArray(ArenaAllocator &Arena, NodeList *Head,
@@ -1489,11 +1591,11 @@ FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {
case 'C':
return FuncClass(FC_Private | FC_Static);
case 'D':
- return FuncClass(FC_Private | FC_Static);
+ return FuncClass(FC_Private | FC_Static | FC_Far);
case 'E':
return FuncClass(FC_Private | FC_Virtual);
case 'F':
- return FuncClass(FC_Private | FC_Virtual);
+ return FuncClass(FC_Private | FC_Virtual | FC_Far);
case 'G':
return FuncClass(FC_Private | FC_StaticThisAdjust);
case 'H':
@@ -1538,7 +1640,8 @@ FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {
FuncClass VFlag = FC_VirtualThisAdjust;
if (MangledName.consumeFront('R'))
VFlag = FuncClass(VFlag | FC_VirtualThisAdjustEx);
-
+ if (MangledName.empty())
+ break;
switch (MangledName.popFront()) {
case '0':
return FuncClass(FC_Private | FC_Virtual | VFlag);
@@ -1561,6 +1664,11 @@ FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {
}
CallingConv Demangler::demangleCallingConvention(StringView &MangledName) {
+ if (MangledName.empty()) {
+ Error = true;
+ return CallingConv::None;
+ }
+
switch (MangledName.popFront()) {
case 'A':
case 'B':
@@ -1591,7 +1699,7 @@ CallingConv Demangler::demangleCallingConvention(StringView &MangledName) {
}
StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {
- assert(std::isdigit(MangledName.front()));
+ assert(MangledName.front() >= '0' && MangledName.front() <= '4');
switch (MangledName.popFront()) {
case '0':
@@ -1605,12 +1713,15 @@ StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {
case '4':
return StorageClass::FunctionLocalStatic;
}
- Error = true;
- return StorageClass::None;
+ DEMANGLE_UNREACHABLE;
}
std::pair<Qualifiers, bool>
Demangler::demangleQualifiers(StringView &MangledName) {
+ if (MangledName.empty()) {
+ Error = true;
+ return std::make_pair(Q_None, false);
+ }
switch (MangledName.popFront()) {
// Member qualifiers
@@ -1649,6 +1760,11 @@ TypeNode *Demangler::demangleType(StringView &MangledName,
std::tie(Quals, IsMember) = demangleQualifiers(MangledName);
}
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+
TypeNode *Ty = nullptr;
if (isTagType(MangledName))
Ty = demangleClassType(MangledName);
@@ -1710,7 +1826,7 @@ FunctionSignatureNode *Demangler::demangleFunctionType(StringView &MangledName,
if (!IsStructor)
FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result);
- FTy->Params = demangleFunctionParameterList(MangledName);
+ FTy->Params = demangleFunctionParameterList(MangledName, FTy->IsVariadic);
FTy->IsNoexcept = demangleThrowSpecification(MangledName);
@@ -1723,6 +1839,11 @@ Demangler::demangleFunctionEncoding(StringView &MangledName) {
if (MangledName.consumeFront("$$J0"))
ExtraFlags = FC_ExternC;
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+
FuncClass FC = demangleFunctionClass(MangledName);
FC = FuncClass(ExtraFlags | FC);
@@ -1750,6 +1871,10 @@ Demangler::demangleFunctionEncoding(StringView &MangledName) {
bool HasThisQuals = !(FC & (FC_Global | FC_Static));
FSN = demangleFunctionType(MangledName, HasThisQuals);
}
+
+ if (Error)
+ return nullptr;
+
if (TTN) {
*static_cast<FunctionSignatureNode *>(TTN) = *FSN;
FSN = TTN;
@@ -1766,7 +1891,7 @@ CustomTypeNode *Demangler::demangleCustomType(StringView &MangledName) {
MangledName.popFront();
CustomTypeNode *CTN = Arena.alloc<CustomTypeNode>();
- CTN->Identifier = demangleUnqualifiedTypeName(MangledName, true);
+ CTN->Identifier = demangleUnqualifiedTypeName(MangledName, /*Memorize=*/true);
if (!MangledName.consumeFront('@'))
Error = true;
if (Error)
@@ -1820,6 +1945,8 @@ PrimitiveTypeNode *Demangler::demanglePrimitiveType(StringView &MangledName) {
return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Uint64);
case 'W':
return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Wchar);
+ case 'Q':
+ return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char8);
case 'S':
return Arena.alloc<PrimitiveTypeNode>(PrimitiveKind::Char16);
case 'U':
@@ -1846,7 +1973,7 @@ TagTypeNode *Demangler::demangleClassType(StringView &MangledName) {
TT = Arena.alloc<TagTypeNode>(TagKind::Class);
break;
case 'W':
- if (MangledName.popFront() != '4') {
+ if (!MangledName.consumeFront('4')) {
Error = true;
return nullptr;
}
@@ -1890,6 +2017,8 @@ PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) {
Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);
Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
+ // isMemberPointer() only returns true if there is at least one character
+ // after the qualifiers.
if (MangledName.consumeFront("8")) {
Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);
Pointer->Pointee = demangleFunctionType(MangledName, true);
@@ -1897,11 +2026,12 @@ PointerTypeNode *Demangler::demangleMemberPointerType(StringView &MangledName) {
Qualifiers PointeeQuals = Q_None;
bool IsMember = false;
std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName);
- assert(IsMember);
+ assert(IsMember || Error);
Pointer->ClassParent = demangleFullyQualifiedTypeName(MangledName);
Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop);
- Pointer->Pointee->Quals = PointeeQuals;
+ if (Pointer->Pointee)
+ Pointer->Pointee->Quals = PointeeQuals;
}
return Pointer;
@@ -1938,7 +2068,7 @@ ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) {
for (uint64_t I = 0; I < Rank; ++I) {
uint64_t D = 0;
std::tie(D, IsNegative) = demangleNumber(MangledName);
- if (IsNegative) {
+ if (Error || IsNegative) {
Error = true;
return nullptr;
}
@@ -1963,12 +2093,12 @@ ArrayTypeNode *Demangler::demangleArrayType(StringView &MangledName) {
return ATy;
}
-// Reads a function or a template parameters.
-NodeArrayNode *
-Demangler::demangleFunctionParameterList(StringView &MangledName) {
+// Reads a function's parameters.
+NodeArrayNode *Demangler::demangleFunctionParameterList(StringView &MangledName,
+ bool &IsVariadic) {
// Empty parameter list.
if (MangledName.consumeFront('X'))
- return {};
+ return nullptr;
NodeList *Head = Arena.alloc<NodeList>();
NodeList **Current = &Head;
@@ -1981,7 +2111,7 @@ Demangler::demangleFunctionParameterList(StringView &MangledName) {
size_t N = MangledName[0] - '0';
if (N >= Backrefs.FunctionParamCount) {
Error = true;
- return {};
+ return nullptr;
}
MangledName = MangledName.dropFront();
@@ -2012,7 +2142,7 @@ Demangler::demangleFunctionParameterList(StringView &MangledName) {
}
if (Error)
- return {};
+ return nullptr;
NodeArrayNode *NA = nodeListToNodeArray(Arena, Head, Count);
// A non-empty parameter list is terminated by either 'Z' (variadic) parameter
@@ -2022,13 +2152,11 @@ Demangler::demangleFunctionParameterList(StringView &MangledName) {
return NA;
if (MangledName.consumeFront('Z')) {
- // This is a variadic parameter list. We probably need a variadic node to
- // append to the end.
+ IsVariadic = true;
return NA;
}
- Error = true;
- return {};
+ DEMANGLE_UNREACHABLE;
}
NodeArrayNode *
@@ -2037,7 +2165,7 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
NodeList **Current = &Head;
size_t Count = 0;
- while (!Error && !MangledName.startsWith('@')) {
+ while (!MangledName.startsWith('@')) {
if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") ||
MangledName.consumeFront("$$$V") || MangledName.consumeFront("$$Z")) {
// parameter pack separator
@@ -2070,12 +2198,16 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
MangledName = MangledName.dropFront();
// 1 - single inheritance <name>
// H - multiple inheritance <name> <number>
- // I - virtual inheritance <name> <number> <number> <number>
+ // I - virtual inheritance <name> <number> <number>
// J - unspecified inheritance <name> <number> <number> <number>
char InheritanceSpecifier = MangledName.popFront();
SymbolNode *S = nullptr;
if (MangledName.startsWith('?')) {
S = parse(MangledName);
+ if (Error || !S->Name) {
+ Error = true;
+ return nullptr;
+ }
memorizeIdentifier(S->Name->getUnqualifiedIdentifier());
}
@@ -2083,20 +2215,19 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
case 'J':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
- LLVM_FALLTHROUGH;
+ DEMANGLE_FALLTHROUGH;
case 'I':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
- LLVM_FALLTHROUGH;
+ DEMANGLE_FALLTHROUGH;
case 'H':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
- LLVM_FALLTHROUGH;
+ DEMANGLE_FALLTHROUGH;
case '1':
break;
default:
- Error = true;
- break;
+ DEMANGLE_UNREACHABLE;
}
TPRN->Affinity = PointerAffinity::Pointer;
TPRN->Symbol = S;
@@ -2117,18 +2248,15 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
case 'G':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
- LLVM_FALLTHROUGH;
+ DEMANGLE_FALLTHROUGH;
case 'F':
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
TPRN->ThunkOffsets[TPRN->ThunkOffsetCount++] =
demangleSigned(MangledName);
- LLVM_FALLTHROUGH;
- case '0':
break;
default:
- Error = true;
- break;
+ DEMANGLE_UNREACHABLE;
}
TPRN->IsMemberPointer = true;
@@ -2148,15 +2276,14 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
Current = &TP.Next;
}
- if (Error)
- return nullptr;
+ // The loop above returns nullptr on Error.
+ assert(!Error);
// Template parameter lists cannot be variadic, so it can only be terminated
- // by @.
- if (MangledName.consumeFront('@'))
- return nodeListToNodeArray(Arena, Head, Count);
- Error = true;
- return nullptr;
+ // by @ (as opposed to 'Z' in the function parameter case).
+ assert(MangledName.startsWith('@')); // The above loop exits only on '@'.
+ MangledName.consumeFront('@');
+ return nodeListToNodeArray(Arena, Head, Count);
}
void Demangler::dumpBackReferences() {