Demangler: handle errors in demangleType

Makes sure that invalid runtime type strings result in errors and not fail silently.
In worst case this could lead to wrong reconstructed metatypes which can result in all kind of memory corruption.

relates to rdar://129861211
This commit is contained in:
Erik Eckstein
2024-06-27 11:50:46 +02:00
parent 9580b21495
commit 7fe2befd31
4 changed files with 38 additions and 22 deletions

View File

@@ -638,6 +638,8 @@ public:
auto substitutedDemangleTree = Builder.demangleTypeRef(
substitutedTypeRef,
/* useOpaqueTypeSymbolicReferences */ true);
if (!substitutedDemangleTree)
continue;
// If the substituted type is an opaque type, also gather info
// about which protocols it is required to conform to and the

View File

@@ -224,6 +224,8 @@ llvm::StringRef swift::Demangle::dropSwiftManglingPrefix(StringRef mangledName){
}
static bool isAliasNode(Demangle::NodePointer Node) {
if (!Node)
return false;
switch (Node->getKind()) {
case Demangle::Node::Kind::Type:
return isAliasNode(Node->getChild(0));
@@ -241,6 +243,8 @@ bool swift::Demangle::isAlias(llvm::StringRef mangledName) {
}
static bool isClassNode(Demangle::NodePointer Node) {
if (!Node)
return false;
switch (Node->getKind()) {
case Demangle::Node::Kind::Type:
return isClassNode(Node->getChild(0));
@@ -259,6 +263,8 @@ bool swift::Demangle::isClass(llvm::StringRef mangledName) {
}
static bool isEnumNode(Demangle::NodePointer Node) {
if (!Node)
return false;
switch (Node->getKind()) {
case Demangle::Node::Kind::Type:
return isEnumNode(Node->getChild(0));
@@ -277,6 +283,8 @@ bool swift::Demangle::isEnum(llvm::StringRef mangledName) {
}
static bool isProtocolNode(Demangle::NodePointer Node) {
if (!Node)
return false;
switch (Node->getKind()) {
case Demangle::Node::Kind::Type:
return isProtocolNode(Node->getChild(0));
@@ -296,6 +304,8 @@ bool swift::Demangle::isProtocol(llvm::StringRef mangledName) {
}
static bool isStructNode(Demangle::NodePointer Node) {
if (!Node)
return false;
switch (Node->getKind()) {
case Demangle::Node::Kind::Type:
return isStructNode(Node->getChild(0));
@@ -774,12 +784,16 @@ NodePointer Demangler::demangleType(StringRef MangledName,
std::function<SymbolicReferenceResolver_t> Resolver) {
DemangleInitRAII state(*this, MangledName, std::move(Resolver));
parseAndPushNodes();
if (!parseAndPushNodes())
return nullptr;
if (NodePointer Result = popNode())
return Result;
NodePointer Result = popNode();
return createNode(Node::Kind::Suffix, Text);
// The result is only valid if it was the only node on the stack.
if (popNode())
return nullptr;
return Result;
}
bool Demangler::parseAndPushNodes() {

View File

@@ -79,28 +79,28 @@ DemangleToMetadataTests.test("function types") {
expectEqual(type(of: f0_throws), _typeByName("yyKc")!)
// More parameters.
expectEqual(type(of: f1), _typeByName("yyyt_tc")!)
expectEqual(type(of: f2), _typeByName("yyyt_yttc")!)
expectEqual(type(of: f1), _typeByName("yyt_tc")!)
expectEqual(type(of: f2), _typeByName("yyt_yttc")!)
// Variadic parameters.
expectEqual(type(of: f1_variadic), _typeByName("yyytd_tc")!)
expectEqual(type(of: f1_variadic), _typeByName("yytd_tc")!)
// Inout parameters.
expectEqual(type(of: f1_inout), _typeByName("yyytzc")!)
expectEqual(type(of: f1_inout), _typeByName("yytzc")!)
// Ownership parameters.
expectEqual(type(of: f1_shared), _typeByName("yyyXlhc")!)
expectEqual(type(of: f1_owned), _typeByName("yyyXlnc")!)
expectEqual(type(of: f1_shared), _typeByName("yyXlhc")!)
expectEqual(type(of: f1_owned), _typeByName("yyXlnc")!)
// Concurrent function types.
expectEqual(type(of: f1_takes_concurrent), _typeByName("yyyyYbXEc")!)
expectEqual(type(of: f1_takes_concurrent), _typeByName("yyyYbXEc")!)
// Mix-and-match.
expectEqual(type(of: f2_variadic_inout), _typeByName("yyytd_ytztc")!)
expectEqual(type(of: f2_variadic_inout), _typeByName("yytd_ytztc")!)
// A function type that hasn't been built before.
expectEqual("(Int, Float, Double, String, Character, UInt, Bool) -> ()",
String(describing: _typeByName("yySi_SfSdSSs9CharacterVSuSbtc")!))
String(describing: _typeByName("ySi_SfSdSSs9CharacterVSuSbtc")!))
// Escaping
expectEqual(type(of: f1_escaping), _typeByName("ySfSicc")!)
@@ -145,16 +145,16 @@ func f1_composition_superclass(_: C & P1 & P2) { }
DemangleToMetadataTests.test("existential types") {
// Any, AnyObject
expectEqual(type(of: f2_any_anyobject), _typeByName("yyyp_yXltc")!)
expectEqual(type(of: f2_any_anyobject), _typeByName("yyp_yXltc")!)
// References to protocols.
expectEqual(type(of: f1_composition), _typeByName("yy4main2P1_4main2P2pc")!)
expectEqual(type(of: f1_composition), _typeByName("y4main2P1_4main2P2pc")!)
// Reference to protocol with AnyObject.
expectEqual(type(of: f1_composition_anyobject), _typeByName("yy4main2P1_Xlc")!)
expectEqual(type(of: f1_composition_anyobject), _typeByName("y4main2P1_Xlc")!)
// References to superclass.
expectEqual(type(of: f1_composition_superclass), _typeByName("yy4main2P1_4main2P2AA1CCXcc")!)
expectEqual(type(of: f1_composition_superclass), _typeByName("y4main2P1_4main2P2AA1CCXcc")!)
// Demangle an existential type that hasn't been seen before.
expectEqual("P1 & P2 & P3", String(describing: _typeByName("4main2P1_4main2P24main2P3p")!))

View File

@@ -40,9 +40,9 @@ func f1_composition_objc_protocol_P4(_: mainP4) { }
DemangleToMetadataTests.test("@objc protocols") {
expectEqual(type(of: f1_composition_objc_protocol),
_typeByName("yy4main2P1_pc")!)
_typeByName("y4main2P1_pc")!)
expectEqual(type(of: f1_composition_objc_protocol_P4),
_typeByName("yy4main0A2P4_pc")!)
_typeByName("y4main0A2P4_pc")!)
}
DemangleToMetadataTests.test("Objective-C classes") {
@@ -53,13 +53,13 @@ func f1_composition_NSCoding(_: NSCoding) { }
func f1_composition_P5(_: P5) { }
DemangleToMetadataTests.test("Objective-C protocols") {
expectEqual(type(of: f1_composition_NSCoding), _typeByName("yySo8NSCoding_pc")!)
expectEqual(type(of: f1_composition_NSCoding), _typeByName("ySo8NSCoding_pc")!)
// @objc Swift protocols can be found by their Objective-C names...
expectEqual(type(of: f1_composition_P5), _typeByName("yySo15P5RenamedInObjC_pc")!)
expectEqual(type(of: f1_composition_P5), _typeByName("ySo15P5RenamedInObjC_pc")!)
// ... but not their Swift names.
expectNil(_typeByName("yy4main2P5_pc"))
expectNil(_typeByName("y4main2P5_pc"))
}
DemangleToMetadataTests.test("Classes that don't exist") {