From a6ebab905e08668ebb2a7b358ba39146e1beea58 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 30 Mar 2023 17:11:44 -0700 Subject: [PATCH] Fix type parsing error returned for type names with invalid start of assembly name (#84141) * Fix type parsing error returned for type names with invalid start of assembly name Fixes #84118 * Mono error handling is different --- .../src/System/Reflection/TypeNameParser.cs | 24 +++++++++++++++---- .../System.Reflection/tests/GetTypeTests.cs | 10 ++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/libraries/Common/src/System/Reflection/TypeNameParser.cs b/src/libraries/Common/src/System/Reflection/TypeNameParser.cs index d7bb0e8fb2b0b..3cc111f5fea4c 100644 --- a/src/libraries/Common/src/System/Reflection/TypeNameParser.cs +++ b/src/libraries/Common/src/System/Reflection/TypeNameParser.cs @@ -50,6 +50,8 @@ private TypeNameParser(ReadOnlySpan name) return null; assemblyName = GetNextAssemblyName(); + if (assemblyName is null) + return null; Debug.Assert(Peek == TokenType.End); } @@ -128,7 +130,7 @@ private TypeNameParser(ReadOnlySpan name) return null; // Because "[" is used both for generic arguments and array indexes, we must peek two characters deep. - if (!(Peek == TokenType.OpenSqBracket && (PeekSecond == TokenType.Other || PeekSecond == TokenType.OpenSqBracket))) + if (!(Peek is TokenType.OpenSqBracket && (PeekSecond is TokenType.Other or TokenType.OpenSqBracket))) return namedType; Skip(); @@ -330,9 +332,10 @@ private TokenType GetNextToken() // Lex the next segment as the assembly name at the end of an assembly-qualified type name. (Do not use for // assembly names embedded inside generic type arguments.) // - private string GetNextAssemblyName() + private string? GetNextAssemblyName() { - SkipWhiteSpace(); + if (!StartAssemblyName()) + return null; string assemblyName = new string(_input.Slice(_index)); _index = _input.Length; @@ -346,7 +349,8 @@ private string GetNextAssemblyName() // private string? GetNextEmbeddedAssemblyName() { - SkipWhiteSpace(); + if (!StartAssemblyName()) + return null; ValueStringBuilder sb = new ValueStringBuilder(stackalloc char[64]); @@ -384,6 +388,18 @@ private string GetNextAssemblyName() return sb.ToString(); } + private bool StartAssemblyName() + { + // Compat: Treat invalid starting token of assembly name as type name parsing error instead of assembly name parsing error. This only affects + // exception returned by the parser. + if (Peek is TokenType.End or TokenType.Comma) + { + ParseError(); + return false; + } + return true; + } + // // Classify a character as a TokenType. (Fortunately, all tokens in type name strings other than identifiers are single-character tokens.) // diff --git a/src/libraries/System.Reflection/tests/GetTypeTests.cs b/src/libraries/System.Reflection/tests/GetTypeTests.cs index 43820b36351d8..f7d2cebcf7bb8 100644 --- a/src/libraries/System.Reflection/tests/GetTypeTests.cs +++ b/src/libraries/System.Reflection/tests/GetTypeTests.cs @@ -269,6 +269,16 @@ public void GetType_GenericTypeArgumentList() Assert.Equal(typeof(System.Reflection.Tests.GenericClass), Type.GetType("System.Reflection.Tests.GenericClass`1[[System.String, System.Private.CoreLib]]", throwOnError: true)); Assert.Throws(() => Type.GetType("System.Reflection.Tests.GenericClass`1[[Bogus, BogusAssembly]]", throwOnError: true)); } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/37871", TestRuntimes.Mono)] + public void GetType_InvalidAssemblyName() + { + Assert.Null(Type.GetType("MissingAssemblyName, ")); + Assert.Null(Type.GetType("ExtraComma, ,")); + Assert.Null(Type.GetType("ExtraComma, , System.Runtime")); + Assert.Throws(() => Type.GetType("System.Object, System.Runtime, Version=x.y")); + } } namespace MyNamespace1