ILSpy icon indicating copy to clipboard operation
ILSpy copied to clipboard

UI performance issue when decoding large generic type references

Open greenozon opened this issue 3 years ago • 4 comments

ILSpy version 6.0.0.5836 used

Steps to reproduce

  1. Just browse the tree nodes of classes/types in the left hand tree view

Error message shown

No errors, ILSpy just hangs eating lots of CPU time + increasing memory consumption, once you find that monster node.

No obfuscation/whatsoever, just a clean assembly

err100.zip

greenozon avatar Jul 13 '20 17:07 greenozon

Fun fact: ildasm has the same problem with this assembly.

Looks like a test of that case with generics+inheritance+nested types where the typename explodes exponentially when compiling.

dgrunwald avatar Jul 18 '20 12:07 dgrunwald

Here's something producing a similar assembly:

class X<A, B, C, D, E>
{
    class Y : X<Y, Y, Y, Y, Y>
    {
        Y.Y.Y.Y.Y.Y.Y.Y y;
    }
}

In IL it's not possible to refer to a nested type via a derived class. A field Y.Y.Y y; gets compiled to:

private X<X<X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y>.Y, X<X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y>.Y, X<X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y>.Y, X<X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y>.Y, X<X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y, X<A, B, C, D, E>.Y>.Y>.Y y;

With a higher nested level, the typename becomes exponentially bigger -- the 30 MB assembly is so big due to this single type signature. In text form the typename grows to 109 MB!

dgrunwald avatar Jul 18 '20 14:07 dgrunwald

The issue with the tree view is that we decode the type of the field for the field: Type tree view label. This is especially problematic because the tree view uses an "uncached" type system: every mention of X in the type signature results in the construction of a new MetadataTypeDefinition instance.

Not sure what we can do here.. everything is working as designed, it's just an extremely unusual assembly.

dgrunwald avatar Jul 18 '20 15:07 dgrunwald

I think the only good solution is to replace the SRM signature decoder with our own. Then we'd be able to abort signature decoding if the signature is too huge (with a small limit for the tree view's TS; but no limit for the decompiler itself). This could also help merge ApplyAttributeTypeVisitor into the type decoder which could provide some minor performance benefits -- the TS is immutable so modifying the type tree after decoding involves a bunch of extra allocations.

dgrunwald avatar Jul 26 '20 08:07 dgrunwald