ILSpy icon indicating copy to clipboard operation
ILSpy copied to clipboard

Undesired (and hindering) value conversion and base type specification break subsequent compilation

Open Rubidium37 opened this issue 1 year ago • 11 comments

Input code

public struct STRUCT
{
}
public void METHOD()
{
	int value = 0;
	Console.WriteLine("value = " + value.ToString());
}

Erroneous output

public struct STRUCT : ValueType
{
}
public void METHOD()
{
	int value = 0;
	Console.WriteLine(String.Concat("value = ", ((Int32)(ref value)).ToString()));
}

Details

Above are two different examples for two totally unrelated issues: The first one depicts what happens with type declarations: the decompiled code contains a base type that is rejected by the C# compiler; the example is for a struct type, but similarly it also happens for class (that adds : Object), enum (that adds : Enum), etc. The second issue shows a totally useless conversion of a local variable whose value is converted to string; along the conversion, the added ref keyword prevents compilation.

I'm using ILSpy version 8.1.1.7464 with .NET version 6.0.21-servicing.23363.11+e40b3abf1b41621d4298642a5fd300ebf7cccf6d, installed as VS2022 extension.

The issue does not happen on a colleague installation using standalone ILSpy version 7.

I searched for options causing the issue but was not able to identity anything related.

Rubidium37 avatar Oct 13 '23 11:10 Rubidium37

Looks like the assembly references cannot be found on your system, while they can be found on your colleague's system.

siegfriedpammer avatar Oct 13 '23 11:10 siegfriedpammer

Just tried standalone versions 8.1, 8.0 and 7.2.1 on my computer, installed in similar paths and decompiling the same assemblies: the older one (7.2.1) works as expected, without adding undesired keywords. The newest versions both add the keywords. I tried the three versions without touching any option.

Rubidium37 avatar Oct 13 '23 11:10 Rubidium37

Looks like the assembly references cannot be found on your system, while they can be found on your colleague's system.

Indeed, in some methods I can see warnings in the following forms: //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown But they are sparse and not present everywhere the undesired "ref" keyword is found.

Rubidium37 avatar Oct 13 '23 11:10 Rubidium37

Can you please provide the assembly and related references, so I can take a closer look at what's going wrong? Thanks!

siegfriedpammer avatar Oct 13 '23 13:10 siegfriedpammer

Missing references alone don't quite explain this behavior; as we'd inject our own MinimalCorlib with those types. If primitive types like Int32 misbehave, then something else is going on -- maybe a weird mixture of reference assemblies is loaded that results in multiple copies of System.Int32?

Note that all assemblies loaded in the assembly list serve as candidate for ILSpy finding reference assemblies. You might get better results if you start with a clean assembly list.

dgrunwald avatar Oct 13 '23 15:10 dgrunwald

-- maybe a weird mixture of reference assemblies is loaded that results in multiple copies of System.Int32?

Note that all assemblies loaded in the assembly list serve as candidate for ILSpy finding reference assemblies. You might get better results if you start with a clean assembly list.

I can confirm that by loading the assembly alone, without any other assembly, solved the issue. Therefore, cleaning the list of loaded assemblies actually helped ILSpy identify the correct reference assemblies.

Given that the inspected assembly is a NET 4.8 exe, I still don't understand why ILSpy was not able to pick the correct reference assemblies. I guess that based on the full assembly name, ILSpy should have no doubt which one to choose from the list. Furthermore, Int32, Object, Enum, etc are declared in system assemblies which should be easily discoverable (despite ILSpy being designed agnostic to different frameworks and versions of .NET).

It would be useful for ILSPY to warn you when it is unable to determine the correct assembly to use (the comments it inserts into the code are not sufficient to understand the reason for the problem), in case with detailed information about what failed; it would also be useful if it provided options to resolve the situation, either at the time of decompilation or as general rules to be set a priori.

Rubidium37 avatar Oct 16 '23 07:10 Rubidium37

It would be useful for ILSPY to warn you when it is unable to determine the correct assembly to use (the comments it inserts into the code are not sufficient to understand the reason for the problem), in case with detailed information about what failed; it would also be useful if it provided options to resolve the situation, either at the time of decompilation or as general rules to be set a priori.

ILSpy should display the following hint at the top of each decompiler output, if an assembly cannot be found:

image

Unfortunately, this only works, if an assembly cannot be resolved at all. Checking whether the assemblies actually contain the correct types is nearly impossible. Giving hints about type mismatches is the best, we can do without destroying UI/decompilation performance, I think, however, I am open to concrete implementation suggestions.

Also there is a full resolver log in the "References" tree node:

image

Hope this helps!

siegfriedpammer avatar Oct 16 '23 15:10 siegfriedpammer

@siegfriedpammer I"ve got an improvement idea is it possible to paint error lines as in example above with red colors? this is help to identify missed refs much faster without any hard to catch exploration (specially if that list is dozen of screens!)

thanks

greenozon avatar Oct 16 '23 15:10 greenozon