Give microsoftDemangle() an outparam for how many input bytes were consumed.

Demangling Itanium symbols either consumes the whole input or fails,
but Microsoft symbols can be successfully demangled with just some
of the input.

Add an outparam that enables clients to know how much of the input was
consumed, and use this flag to give llvm-undname an opt-in warning
on partially consumed symbols.

Differential Revision: https://reviews.llvm.org/D80173
This commit is contained in:
Nico Weber 2020-05-18 19:57:30 -04:00
parent 05ca034290
commit 6863d97f67
8 changed files with 40 additions and 12 deletions

View File

@ -40,7 +40,21 @@ enum MSDemangleFlags {
MSDF_NoReturnType = 1 << 3,
MSDF_NoMemberType = 1 << 4,
};
char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,
/// Demangles the Microsoft symbol pointed at by mangled_name and returns it.
/// Returns a pointer to the start of a null-terminated demangled string on
/// success, or nullptr on error.
/// If n_read is non-null and demangling was successful, it receives how many
/// bytes of the input string were consumed.
/// buf can point to a *n_buf bytes large buffer where the demangled name is
/// stored. If the buffer is too small, it is grown with realloc(). If buf is
/// nullptr, then this malloc()s memory for the result.
/// *n_buf stores the size of buf on input if buf is non-nullptr, and it
/// receives the size of the demangled string on output if n_buf is not nullptr.
/// status receives one of the demangle_ enum entries above if it's not nullptr.
/// Flags controls various details of the demangled representation.
char *microsoftDemangle(const char *mangled_name, size_t *n_read,
char *buf, size_t *n_buf,
int *status, MSDemangleFlags Flags = MSDF_None);
/// Attempt to demangle a string using different demangling schemes.

View File

@ -624,7 +624,7 @@ LLVMSymbolizer::DemangleName(const std::string &Name,
// Only do MSVC C++ demangling on symbols starting with '?'.
int status = 0;
char *DemangledName = microsoftDemangle(
Name.c_str(), nullptr, nullptr, &status,
Name.c_str(), nullptr, nullptr, nullptr, &status,
MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention |
MSDF_NoMemberType | MSDF_NoReturnType));
if (status != 0)

View File

@ -24,8 +24,8 @@ std::string llvm::demangle(const std::string &MangledName) {
if (isItaniumEncoding(MangledName))
Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr);
else
Demangled =
microsoftDemangle(MangledName.c_str(), nullptr, nullptr, nullptr);
Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr,
nullptr, nullptr);
if (!Demangled)
return MangledName;

View File

@ -2334,14 +2334,16 @@ void Demangler::dumpBackReferences() {
std::printf("\n");
}
char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N,
char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled,
char *Buf, size_t *N,
int *Status, MSDemangleFlags Flags) {
int InternalStatus = demangle_success;
Demangler D;
OutputStream S;
StringView Name{MangledName};
SymbolNode *AST = D.parse(Name);
if (!D.Error && NMangled)
*NMangled = Name.begin() - MangledName;
if (Flags & MSDF_DumpBackrefs)
D.dumpBackReferences();
@ -2356,6 +2358,7 @@ char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N,
if (Flags & MSDF_NoMemberType)
OF = OutputFlags(OF | OF_NoMemberType);
int InternalStatus = demangle_success;
if (D.Error)
InternalStatus = demangle_invalid_mangled_name;
else if (!initializeOutputStream(Buf, N, S, 1024))

View File

@ -0,0 +1,6 @@
; RUN: llvm-undname -warn-trailing 2>&1 < %s | FileCheck %s
?x@@3HAasdf
; CHECK: ?x@@3HAasdf
; CHECK-NEXT: int x
; CHECK-NEXT: warning: trailing characters: asdf

View File

@ -15,6 +15,6 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
std::string NullTerminatedString((const char *)Data, Size);
free(llvm::microsoftDemangle(NullTerminatedString.c_str(), nullptr, nullptr,
nullptr));
nullptr, nullptr));
return 0;
}

View File

@ -679,11 +679,9 @@ void objdump::printCOFFSymbolTable(const COFFObjectFile *coff) {
<< "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
<< Name;
if (Demangle && Name.startswith("?")) {
char *DemangledSymbol = nullptr;
size_t Size = 0;
int Status = -1;
DemangledSymbol =
microsoftDemangle(Name.data(), DemangledSymbol, &Size, &Status);
char *DemangledSymbol =
microsoftDemangle(Name.data(), nullptr, nullptr, nullptr, &Status);
if (Status == 0 && DemangledSymbol) {
outs() << " (" << StringRef(DemangledSymbol) << ")";

View File

@ -45,6 +45,9 @@ cl::opt<bool> NoMemberType("no-member-type", cl::Optional,
cl::init(false));
cl::opt<std::string> RawFile("raw-file", cl::Optional,
cl::desc("for fuzzer data"), cl::Hidden);
cl::opt<bool> WarnTrailing("warn-trailing", cl::Optional,
cl::desc("warn on trailing characters"), cl::Hidden,
cl::init(false));
cl::list<std::string> Symbols(cl::Positional, cl::desc("<input symbols>"),
cl::ZeroOrMore);
@ -62,11 +65,15 @@ static bool msDemangle(const std::string &S) {
if (NoMemberType)
Flags = MSDemangleFlags(Flags | MSDF_NoMemberType);
size_t NRead;
char *ResultBuf =
microsoftDemangle(S.c_str(), nullptr, nullptr, &Status, Flags);
microsoftDemangle(S.c_str(), &NRead, nullptr, nullptr, &Status, Flags);
if (Status == llvm::demangle_success) {
outs() << ResultBuf << "\n";
outs().flush();
if (WarnTrailing && NRead < S.size())
WithColor::warning() << "trailing characters: " << S.c_str() + NRead
<< "\n";
} else {
WithColor::error() << "Invalid mangled name\n";
}