Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Marat Mukhamadiev
@maratoss
Whe is it?
Siegfried Pammer
@siegfriedpammer
icsharpcode/ILSpy#1471 will be merged soon, then the settings should all be back!
Marat Mukhamadiev
@maratoss
Aha! Good thanks, now i am calm! :)
FreddyD-GH
@FreddyD-GH
Does ILSpy (or ICSharpCode.Decompiler) have an easy way to generate a list of all references to external assemblies (Types/Methods/Properties/etc.) from a given assembly? Perhaps there is sample code already somewhere that does this?
Jesse Talavera-Greenberg
@JesseTG
Is it possible to use ILSpy to get inter-class dependencies within a single assembly? My project is mostly compiled into one big assembly that I want to break into a bunch of smaller assemblies.
Claudiu Guiman
@clguimanMSFT

Hello! I might have a dumb question so please bear with me :)
Why is IDecompilerTypeSystem.FindType() expecting generic types to not include the argument list, just the arity (`1), but if I get the same type as an IType (let's say I got it from a return type of a method) the ReflectionName property has the argument list?.

For example:

decompiler.TypeSystem.FindType(new FullTypeName("System.Threading.Tasks.Task`1[[System.String]]")) // returns Unknown
decompiler.TypeSystem.FindType(new FullTypeName("System.Threading.Tasks.Task`1")) // works

IMethod myMethod = ...
Console.Write(myMethod.ReturnType.ReflectionName); //outputs "System.Threading.Tasks.Task`1[[System.String]]"

Shouldn't the FullTypeName ctor also include the arguments?

Siegfried Pammer
@siegfriedpammer
IDecompilerTypeSystem.FindType() only returns ITypeDefinition
you can make a generic type by using var taskOfT = decompiler.TypeSystem.FindType(KnownTypeCode.TaskOfT).GetDefinition(); var taskOfString = new ParameterizedType(taskOfT, new[] { decompiler.TypeSystem.FindType(KnownTypeCode.String) });
using the KnownTypeCode overload for all known types is faster than using the FullTypeName overload
Siegfried Pammer
@siegfriedpammer
The return type of a "specialized" generic method is a ParameterizedType, that's why the reflection name includes type arguments
Siegfried Pammer
@siegfriedpammer
@FreddyD-GH sorry, for taking so long to reply: Unfortunately, ILSpy does not currently offer such functionality.
@JesseTG ILSpy lets you analyze a single member/type, but not all dependencies in one single step.
Claudiu Guiman
@clguimanMSFT
@siegfriedpammer thanks for the explanation. So the short name format ("System.Threading.Tasks.Task`1") is only for well known generic types? If I have a user defined generic type the full type name will also include the argument list?
Siegfried Pammer
@siegfriedpammer
no, FullTypeName can be used for any fully-qualified type definition in the type system. However, if you are looking for "special types" like void, int, string, IEnumerable<T>, Nullable<T>, Task, Task<T>, Span<T>, Memory<T>, etc. (see https://github.com/icsharpcode/ILSpy/blob/master/ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs#L26 for the full list)
Siegfried Pammer
@siegfriedpammer
typeSystem.FindType(KnownTypeCode.TaskOfT) should yield the same result as typeSystem.FindType(new FullTypeName("System.Threading.Tasks.Task1"))`, however the first one should be faster, because it directly uses the KnownTypeCache instead of having to parse a type-name and searching the whole compilation.
ThunderFrost0001
@ThunderFrost0001
Is it not possible to import this to Unity?
areller
@areller
Hi. I'm looking for a way to decompile an anonymous method (Action<T>) in .NET Core.
Basically, I have something like this
public void Add(Action<Cursor> action)
{
    var il = action.Method.GetMethodBody().GetILAsByteArray();
    var ast = decompiler.Decompile(il); // Is it possible?
}
Sorry for the newbie question but I couldn't find how to do it.
Daniel Grunwald
@dgrunwald
The IL bytes alone are not sufficient to decompile anything, as the decompiler also needs the metadata tables. (e.g. the IL bytecode itself only says "call method nr. 42", which means the method name and signature can be found in row 42 of the "methoddef" metadata table)
@areller The decompiler's type system (which reads from these tables) is based on System.Reflection.Metadata, so you can't use the decompiler with a normal System.Reflection assembly
next best thing you can do is to load the assembly again using System.Reflection.Metadata, and re-discover the method in question using its metadata-token
areller
@areller

@dgrunwald Thank you. I'm trying to do it, when I initialise an instance of CSharpCompiler that points to my current assembly,

var file = Assembly.GetEntryAssembly().Location;
var decompiler = new CSharpDecompiler(file, new UniversalAssemblyResolver(file, true, ".NETCOREAPP"), new DecompilerSettings());

I get the exception

An unhandled exception of type 'ICSharpCode.Decompiler.Metadata.AssemblyResolutionException' occurred in ICSharpCode.Decompiler.dll: 'Failed to resolve assembly: 'ICSharpCode.Decompiler, Version=4.0.0.4521, Culture=neutral, PublicKeyToken=d4bfe873e7598c49'

Reading the source file of UniversalAssemblyResolver (specifically, method ResolveInternal), I see that it doesn't search in the NuGet directory.
When I do dotnet publish and run my application, it works (the instantiation of CSharpDecompiler), because it includes the ICSharpCode.Decompiler dll in the publish folder.
Is there a way to make it work in development, by looking in NuGet packages?

areller
@areller
Okay, I found out that It has something to do with the version that I pass to UniversalAssemblyResolver. I will look into it
Chicken-Bones
@Chicken-Bones

I've 'fixed' #1764 by changing _.MatchLdcI(1) to _.MatchLdcI(1) || _.MatchLdcF4(1) || _.MatchLdcF8(1) in 3 places.

Test cases are passing fine (except for Cecil which has always had path issues). Am I overlooking something obvious or is this a simple fix?

Chicken-Bones
@Chicken-Bones
@dgrunwald @siegfriedpammer any rules about pinging?
Daniel Grunwald
@dgrunwald
Hmm looks like it's really that simple. The other helper functions involved are shared with the code for compound assignments/preincrement, and that already supports floats.
Daniel Grunwald
@dgrunwald
There's also #947 which is a bit more complicated, i guess the current code only works for byte*/sbyte*.
Chicken-Bones
@Chicken-Bones
I'll PR it sometime this week, with some test cases.
Chicken-Bones
@Chicken-Bones
I'm really struggling to conceive of a piece of code requiring the fix in icsharpcode/ILSpy@6c0216b
There's no test case or issue number
Daniel Grunwald
@dgrunwald
Hmm I think it's related to the two commits immediately preceding that one
Daniel Grunwald
@dgrunwald
I'm pretty sure the commit message is talking about the "Only the last instruction in a block may have an unreachable endpoint" assertion in Block.CheckInvariant; but I can't remember which test case ran into that assertion
Daniel Grunwald
@dgrunwald
@Chicken-Bones I can reproduce the assertion using the ILSpy version immediately prior to that commit on the assembly from #1364
Daniel Grunwald
@dgrunwald

paraphrasing the ILAst of the obfuscated code, before "Duplicate block exit" + "Extract else block" the control flow looks like this:

if (...) {
   call Something()
} else {
   while (true) {
      if (...)
        return;
   }
}
return;

and after it looks like this:

if (...) {
   call Something()
   return;
}
while (true) {
    if (...)
      return;
 }
return;
Chicken-Bones
@Chicken-Bones
            if (!b)
            {
                Console.WriteLine();
            }
            while (true)
            {
                for (int i = 0; i < 10; i++)
                    Console.WriteLine();

                if (b)
                    return;

                for (int i = 0; i < 10; i++)
                    Console.WriteLine();
            }
I tried this before asking, but it decompiles fine, I'll go grab the assembly from the issue
Chicken-Bones
@Chicken-Bones
I suppose more recent commits have improved the handling of dead code
it should be impossible to actually hit the condition there now
I could replace it with an assertion, or just leave it
Chicken-Bones
@Chicken-Bones
I stumbled across https://github.com/csmith-project/creduce today, awesome concept, might try it out in the future
Daniel Grunwald
@dgrunwald
creduce is great, I use it a lot at work to minimize reproducers for our C++ compiler
customers can send in 5 MB of boost header mess and creduce usually manages to cut it down to 10 to 20 lines of code
Chicken-Bones
@Chicken-Bones
An annoyance I found while doing test cases for something else:
public void Issue1524V3(string str)
{
    if (!string.IsNullOrEmpty(str))
    {
        return;
    }
    if (int.TryParse(str, out int id))
    {
        Console.WriteLine(new Func<int>(() => id));
    }
}

public void Issue1524V4(string str)
{
    if (string.IsNullOrEmpty(str))
    {
        if (int.TryParse(str, out int id))
        {
            Console.WriteLine(new Func<int>(() => id)); 
        }
    }
}
The first version decompiles with a short-circuit. Intended behaviour.
The second decompiles with an early return (how the first is written).
This is because the compiler emits the display class constructor and local variable store in different locations in the two
In the first version, the stloc V_1(newobj <>c__DisplayClass10_0..ctor()) is before the first if
In the second, it's between the two, preventing them from being merged.
TransformDisplayClassUsage removes the display class init and store, but it runs after ConditionDetection
The only solutions I can think of are either re-ordering the transforms, or running ConditionDetection (or a part of it) again
I don't know enough about the inter-transform dependencies to know if reordering would be very bad
It's not a major issue by any means, but it's an inconsistency which isn't ideal. Perhaps the lingering store prevents other transforms working properly as well
Stargazing Koishi
@sgkoishi
Do I need to put the .net framework libraries to somewhere if I want to decompile a netfx targeted file in net core linux environment?
Like say, copy all files from C:\Windows\Microsoft.NET\Framework64\v4.0.30319 to the linux machine and AssemblyResolver.AddSearchDirectory?
Siegfried Pammer
@siegfriedpammer
@sgkoishi yes, I think that would be necessary
Daniel Grunwald
@dgrunwald
@sgkoishi you could also use the equivalent mono assemblies or otherwise "similar enough" assemblies. ILSpy is mostly interested in having type definitions for types used in the assembly being decompiled -- most critically it needs to tell whether a typeref refers to a struct, class or enum. We also use the list of available methods to ensure we emit enough casts to uniquely identify the overload that's supposed to be called. There's also a bunch of other minor stuff.
ILSpy itself uses the .NET runtime assemblies (from the GAC) so that you can use "go to definition" and see the source code for those .NET methods. But the decompiler itself would also be happy with reference assemblies that have the public types and methods without implementation.
Mykola Morozov
@mcmikecreations
Hi everyone! I've been a happy user of the ILSpy CSharpDecompiler, specifically the decompiled node tree. But I've been wondering, is there any method to transform raw c# code (text files) into the SyntaxTree node tree? I understand I can create a parser myself, but I'm curious if it already exists.
Stanislav LukeŇ°
@exyi
@mcmikecreations I guess you can use the Roslyn API to parse C# files into a syntax tree, here is some intro text: https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/get-started/syntax-analysis It is a different tree than the ILSpy's one, but the principle is similar. And, in any case, translating the Roslyn tree into ILSpy tree is going to be way simpler than parsing C#