From e915178746d1856bb74c823d77256c6627af1802 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 5 Apr 2016 18:18:37 -0400 Subject: [PATCH] [corlib] TypeSpec.Parse for non-assembly qualified names. Previously for types like "Foo[P,Q]" the recursive call of the parser would incorrectly consume the delimiter after a type argument (ie the ',' or ']') which would leave the caller potentially past the end of the string which would signal a failed parse. New behavior is to peek at the delimiter but leave it up to the caller to consume. Also `Type.GetType(name, null, null)` should behave like `Type.GetType(name)` (previously it dropped generic type arguments). --- mcs/class/corlib/System/TypeSpec.cs | 49 +++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/mcs/class/corlib/System/TypeSpec.cs b/mcs/class/corlib/System/TypeSpec.cs index 9ad485e07cd..3cf08ae3520 100644 --- a/mcs/class/corlib/System/TypeSpec.cs +++ b/mcs/class/corlib/System/TypeSpec.cs @@ -218,7 +218,7 @@ namespace System { if (typeName == null) throw new ArgumentNullException ("typeName"); - TypeSpec res = Parse (typeName, ref pos, false, false); + TypeSpec res = Parse (typeName, ref pos, false, true); if (pos < typeName.Length) throw new ArgumentException ("Count not parse the whole type name", "typeName"); return res; @@ -287,7 +287,7 @@ namespace System { { Assembly asm = null; if (assemblyResolver == null && typeResolver == null) - return Type.GetType (name.DisplayName, throwOnError, ignoreCase); + return Type.GetType (DisplayFullName, throwOnError, ignoreCase); if (assembly_name != null) { if (assemblyResolver != null) @@ -376,6 +376,12 @@ namespace System { pos = p; } + static void BoundCheck (int idx, string s) + { + if (idx >= s.Length) + throw new ArgumentException ("Invalid generic arguments spec", "typeName"); + } + static TypeIdentifier ParsedTypeIdentifier (string displayName) { return TypeIdentifiers.FromDisplay(displayName); @@ -383,6 +389,17 @@ namespace System { static TypeSpec Parse (string name, ref int p, bool is_recurse, bool allow_aqn) { + // Invariants: + // - On exit p, is updated to pos the current unconsumed character. + // + // - The callee peeks at but does not consume delimiters following + // recurisve parse (so for a recursive call like the args of "Foo[P,Q]" + // we'll return with p either on ',' or on ']'. If the name was aqn'd + // "Foo[[P,assmblystuff],Q]" on return p with be on the ']' just + // after the "assmblystuff") + // + // - If allow_aqn is True, assembly qualification is optional. + // If allow_aqn is False, assembly qualification is prohibited. int pos = p; int name_start; bool in_modifiers = false; @@ -450,18 +467,24 @@ namespace System { data.AddModifier (new PointerSpec(pointer_level)); break; case ',': - if (is_recurse) { + if (is_recurse && allow_aqn) { int end = pos; while (end < name.Length && name [end] != ']') ++end; if (end >= name.Length) throw new ArgumentException ("Unmatched ']' while parsing generic argument assembly name"); data.assembly_name = name.Substring (pos + 1, end - pos - 1).Trim (); - p = end + 1; + p = end; return data; } - data.assembly_name = name.Substring (pos + 1).Trim (); - pos = name.Length; + if (is_recurse) { + p = pos; + return data; + } + if (allow_aqn) { + data.assembly_name = name.Substring (pos + 1).Trim (); + pos = name.Length; + } break; case '[': if (data.is_byref) @@ -482,11 +505,17 @@ namespace System { if (aqn) ++pos; //skip '[' to the start of the type args.Add (Parse (name, ref pos, true, aqn)); - if (pos >= name.Length) - throw new ArgumentException ("Invalid generic arguments spec", "typeName"); + BoundCheck (pos, name); + if (aqn) { + if (name [pos] == ']') + ++pos; + else + throw new ArgumentException ("Unclosed assembly-qualified type name at " + name[pos], "typeName"); + BoundCheck (pos, name); +} if (name [pos] == ']') - break; + break; if (name [pos] == ',') ++pos; // skip ',' to the start of the next arg else @@ -523,7 +552,7 @@ namespace System { break; case ']': if (is_recurse) { - p = pos + 1; + p = pos; return data; } throw new ArgumentException ("Unmatched ']'", "typeName"); -- 2.25.1