-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use SRM's TypeName parser in ILLink #103740
Conversation
Tagging subscribers to this area: @agocke, @sbomer, @vitek-karas |
readonly ITryResolveMetadata _metadataResolver; | ||
readonly ITryResolveAssemblyName _assemblyResolver; | ||
|
||
private static readonly TypeNameParseOptions s_typeNameParseOptions = new () { MaxNodes = int.MaxValue }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @adamsitnik @GrabYourPitchforks So far every single real-world use of TypeName.Parse
except the one in NRBF overrides the low MaxNodes default with int.MaxValue. It makes me wonder whether we made the right choice for the default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I just copied this default from the type name parser used in Native AOT.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int.MaxValue
is the right value to use for tools like ILLinker. The tools like ILLinker are not hardened against too complex input. It is fine for these tools to crash with StackOverflowException or take a long time to run when the input is too complex.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far every single real-world use of TypeName.Parse except the one in NRBF overrides the low MaxNodes default with int.MaxValue. It makes me wonder whether we made the right choice for the default.
From my perspective, we wanted to be secure by default and this was the right choice.
IMO int.MaxValue
is never the right value, as it is impossible to create such complex type names (runtime is unable to load them). For Runtime and its tools we should rather find a value that is large enough to allow for the most complex real-life types, but not big enough to cause SO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Runtime and its tools we should rather find a value that is large enough to allow for the most complex real-life types, but not big enough to cause SO.
There is no point in doing that unless we make the runtime and tools hardened against too complex types. There are 1000 different ways how too complex types can introduce stackoverflow in the runtime and tools. Reducing that by one does not really help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reducing that by one does not really help.
It does not solve the problem, but on the other hand it's almost free (the logic is implemented, it's just a matter of changing one value in few places) and it would not hurt.
But, I don't have the perspective of long term thinking about the .NET Runtime you have, so I am most probably missing a lot of details (like giving the users a false impression that Type.GetType(string)
is hardened against all kinds of unsafe inputs)
Some tests have exported types that are kept even though the types they point to are removed. The ResultCheckr resolution logic should not throw in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM aside from a couple test nits, thank you!
if (!originalsTypeNameResolver.TryResolveTypeName (originalTargetAssembly, expectedTypeName, out TypeReference? expectedTypeRef, out _)) | ||
Assert.Fail($"Could not resolve original type `{expectedTypeName}' in assembly {assemblyName}"); | ||
TypeDefinition expectedType = expectedTypeRef.Resolve (); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Append to the errs list rather than failing immediately.
if (!originalsTypeNameResolver.TryResolveTypeName (originalTargetAssembly, expectedTypeName, out TypeReference? expectedTypeRef, out _)) | |
Assert.Fail($"Could not resolve original type `{expectedTypeName}' in assembly {assemblyName}"); | |
TypeDefinition expectedType = expectedTypeRef.Resolve (); | |
if (!originalsTypeNameResolver.TryResolveTypeName (originalTargetAssembly, expectedTypeName, out TypeReference? expectedTypeRef, out _)) { | |
errs.Add($"Could not resolve original type `{expectedTypeName}' in assembly {assemblyName}"); | |
continue; | |
} | |
TypeDefinition expectedType = expectedTypeRef.Resolve (); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather keep this one as an assert because it indicates a test authoring issue, and this matches what we do in some other places that fail to resolve something from the input.
src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/AssemblyChecker.cs
Show resolved
Hide resolved
src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs
Show resolved
Hide resolved
src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/Dependencies/EscapedTypeNames.il
Show resolved
Hide resolved
- Remove TestResolver.Instance - Test type name with '/'
This replaces the type name parser we copied from corert with the one in System.Reflection.Metadata.
Adds a test for resolving escaped type names, shared by ILLink and Native AOT. To support this testcase, the test infra also uses TypeNameResolver. The ILLink tests use it via IVT, and the Native AOT tests use it by including source files. The sources have been factored a little to make it possible to use just the TypeNameResolver from NativeAot without pulling in other components of ILLink.