forked from OSchip/llvm-project
llvm-undname: Fix more crashes and asserts on invalid inputs
For functions whose callers don't check that enough input is present, add checks at the start of the function that enough input is there and set Error otherwise. For functions that return AST objects, return nullptr instead of incomplete AST objects with nullptr fields if an error occurred during the function. Introduce a new function demangleDeclarator() for the sequence demangleFullyQualifiedSymbolName(); demangleEncodedSymbol() and use it in the two places that had this sequence. Let this new function check that ConversionOperatorIdentifiers have a valid TargetType. Some of the bad inputs found by oss-fuzz, others by inspection. Differential Revision: https://reviews.llvm.org/D60354 llvm-svn: 357936
This commit is contained in:
parent
3a4c2192a4
commit
63b97d2a67
|
@ -159,6 +159,7 @@ public:
|
|||
private:
|
||||
SymbolNode *demangleEncodedSymbol(StringView &MangledName,
|
||||
QualifiedNameNode *QN);
|
||||
SymbolNode *demangleDeclarator(StringView &MangledName);
|
||||
|
||||
VariableSymbolNode *demangleVariableEncoding(StringView &MangledName,
|
||||
StorageClass SC);
|
||||
|
|
|
@ -65,7 +65,10 @@ static bool isMemberPointer(StringView MangledName, bool &Error) {
|
|||
// 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');
|
||||
}
|
||||
|
||||
|
@ -75,7 +78,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()) {
|
||||
|
@ -378,11 +384,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);
|
||||
|
@ -400,7 +406,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.
|
||||
|
@ -674,6 +681,11 @@ Demangler::demangleFunctionIdentifierCode(StringView &MangledName,
|
|||
|
||||
SymbolNode *Demangler::demangleEncodedSymbol(StringView &MangledName,
|
||||
QualifiedNameNode *Name) {
|
||||
if (MangledName.empty()) {
|
||||
Error = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Read a variable.
|
||||
switch (MangledName.front()) {
|
||||
case '0':
|
||||
|
@ -693,11 +705,36 @@ 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;
|
||||
}
|
||||
|
||||
// Parser entry point.
|
||||
SymbolNode *Demangler::parse(StringView &MangledName) {
|
||||
// We can't demangle MD5 names, just output them as-is.
|
||||
|
@ -722,21 +759,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) {
|
||||
|
@ -763,6 +786,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()) {
|
||||
|
@ -1574,6 +1600,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':
|
||||
|
@ -1624,6 +1655,10 @@ StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {
|
|||
|
||||
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
|
||||
|
@ -1662,6 +1697,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);
|
||||
|
@ -1736,6 +1776,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);
|
||||
|
||||
|
@ -1763,6 +1808,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;
|
||||
|
@ -1903,6 +1952,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);
|
||||
|
@ -1910,11 +1961,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;
|
||||
|
|
|
@ -29,3 +29,63 @@
|
|||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ? @@ YC@
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
??B@$$J0
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ??B@$$J0
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
??B@4
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ??B@4
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
?A?@?@???B@4D
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ?A?@?@???B@4D
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
?A?@?@???B@4DD
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ?A?@?@???B@4DD
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
??$A@P15@
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ??$A@P15@
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
??$A@P
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ??$A@P
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
?A@@
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ?A@@
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
?A@@P
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ?A@@P
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
?A@@4PQA@@
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ?A@@4PQA@@
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
??__E
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ??__E
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
??__E@@
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ??__E@@
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
||||
??__E?Foo@@0HA@@
|
||||
; CHECK-EMPTY:
|
||||
; CHECK-NEXT: ??__E?Foo@@0HA@@
|
||||
; CHECK-NEXT: error: Invalid mangled name
|
||||
|
|
Loading…
Reference in New Issue