icsharpcode / ilspy Goto Github PK
View Code? Open in Web Editor NEW.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
(this issue is just for reference, I know this is top priority :-)
The following 'foreach' loop:
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.Add(5);
foreach (int i in list)
{
DoSomething();
}
decompiled to this:
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.Add(5);
List.Enumerator<int> enumerator = list.GetEnumerator();
try
{
for (; ; )
{
flag = enumerator.MoveNext();
if (!flag)
{
break;
}
else
{
current = enumerator.Current;
this.DoSomething();
}
}
}
finally
{
var arg_AF_0 = ref enumerator;
constrained(System.Collections.Generic.List`1/Enumerator<System.Int32>);
arg_AF_0.Dispose();
}
System.Double.NaN decompiles to the following code:
public const double NaN = NaN.0;
Obviously that will not compile. There are similar issues for System.Double.PositiveInfinity, and System.Double.NegativeInfinity.
Instead NaN is best represented as 0.0/0.0.
The C# 4.0 compiler will compile that into a NaN that is bit-for-bit identical to System.Double.NaN.
Similarly PositiveInfinity is best represented as 1.0/0.0, and NegativeInfinity as -1.0/0.0.
Those expressions also compile bit for bit identical to the System.Double members.
input:
public static T GenericMethod(T t)
{
return t;
}
output:
public static T GenericMethod(T t)
{
return t;
}
Console.WriteLine("{0} $$ {1}", AttributeTargets.Class, AttributeTargets.Field | AttributeTargets.Property);
Should print:
Class $$ Property, Field
but prints
Class $$ 384
I prepared a fix for this issue (see parts of commit arturek/ILSpy@679d525806d8ca7c0820) as a part of my work on custom attribute support but I am still working on some other issues related to it (and on validation of correctness of this change). I can notify you when I finish if you are interested in it.
mscorlib
System.Decimal
static Decimal()
{
uint[] expr_07 = new uint[10];
Array arg_0D_0 = expr_07;
uint[] arg_12_0 = expr_07;
RuntimeHelpers.InitializeArray(arg_0D_0, ldtoken($$method0x6006097-1));
decimal.Powers10 = arg_12_0;
decimal.Zero = new decimal(0);
decimal.One = new decimal(1);
decimal.MinusOne = new decimal(-1);
decimal.MaxValue = new decimal(-1, -1, -1, false, 0);
decimal.MinValue = new decimal(-1, -1, -1, 128 != 0, 0);
decimal.NearNegativeZero = new decimal(1, 0, 0, 128 != 0, 27);
decimal.NearPositiveZero = new decimal(1, 0, 0, false, 27);
}
must be
static Decimal()
{
Powers10 = new uint[] { 1, 10, 100, 0x3e8, 0x2710, 0x186a0, 0xf4240, 0x989680, 0x5f5e100, 0x3b9aca00 };
Zero = 0M;
One = 1M;
MinusOne = -1M;
MaxValue = 79228162514264337593543950335M;
MinValue = -79228162514264337593543950335M;
NearNegativeZero = -0.000000000000000000000000001M;
NearPositiveZero = 0.000000000000000000000000001M;
}
Some times the generated code has many gotos because code from defaults is not identified here is an example:
input:
public static int Switch(int i)
{
int j;
switch (i)
{
case 0:
{
j = i + 1;
break;
}
case 1:
{
j = i + 2;
break;
}
default:
{
return -1;
}
}
return j * 2;
}
output:
public static int Switch(int i)
{
int j;
switch (i)
{
case 0:
{
j = i + 1;
goto IL_20;
}
case 1:
{
j = i + 2;
goto IL_20;
}
}
return -1;
IL_20:
return j * 2;
}
mscorlib v.4.0
Microsoft.Win32.OAVariantLib
private static void ChangeTypeEx(Variant result, Variant source, int lcid, IntPtr typeHandle, int cvType, short flags);
should be
private static extern void ChangeTypeEx(Variant result, Variant source, int lcid, IntPtr typeHandle, int cvType, short flags);
method()
{
try
{
try
{ }
finaly()
{ }
// leave to return
}
catch()
{ }
List StackAnalysis(MethodDefinition methodDef)
{
Ln 207 // if (branchTarget.StackBefore.Count != newStack.Count) <-- is true
Ln 233 // int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count; <-- StackBefore == null
}
List ConvertToAst(List body)
{
Ln 364 // int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count; <-- StackBefore == null
}
When the method has multiple signatures; such as foo(MyObject o) and foo(string s), then code calling for with a null argument must have a cast. Currently ILSpy will display foo(null) and it should be foo((string) null) or foo((MyObject) null).
I found this while looking at the .ctor for System.Xml.Resolvers.XmlPreloadedResolver.
mscorlib
System.Decimal:
---> System.InvalidCastException: Cast from Int64 to Boolean not supported.
must be
static Decimal()
{
Powers10 = new uint[] { 1, 10, 100, 0x3e8, 0x2710, 0x186a0, 0xf4240, 0x989680, 0x5f5e100, 0x3b9aca00 };
Zero = 0M;
One = 1M;
MinusOne = -1M;
MaxValue = 79228162514264337593543950335M;
MinValue = -79228162514264337593543950335M;
NearNegativeZero = -0.000000000000000000000000001M;
NearPositiveZero = 0.000000000000000000000000001M;
}
this:
foreach (string s in list)
{
s.ToLower();
}
decompiled to this on debug build:
foreach (string current in list)
{
current.ToLower();
continue;
}
and to this on release build:
using (List.Enumerator<string> enumerator = list.GetEnumerator())
{
while (enumerator.MoveNext())
{
enumerator.Current.ToLower();
continue;
}
}
mscorlib
Microsoft.Win32.Win32Native.SetFilePointer()
should be
hr = 0;
this:
char c = str[i];
decompiles to this:
text.get_Chars(j);
Steps to reproduce:
---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
ICSharpCode.Decompiler/Tests/TestRunner.cs line 75
while ((line2 = r2.ReadLine()) != null) {
ok = false;
diff.WriteLine("+" + line1);
diff.WriteLine("+" + line2);
}
I get a "Image format is unrecognized" exception when launching ILSpy in Windows XP. A Google search reveled a problem with the 256x256 image in ILSpy.ico (http://torque.gig8.com/2009/01/image_format_is_unrecognized_w.html).
I loaded the source code, removed the 256x259 image in ILSpy.ico, recompiled, and everything is working fine.
Regards,
Patricio.
I cannot see the attributes used in classes neither members. Is this a bug? or, can this be a feature to add?
It takes several minor modifications to run ILSpy on .NET 3.5
Can we please add those with #if or something?
Majority of modifications are about generic collection covariance missing in .NET 3.5 -- basically sticking OfType<> now and then fixes it.
There are several string.Join calls with an absent signature. Select+ToArray does it.
There is a little Mono.Cecil patch to do with some obscure static type invocation. This one would just have to be ignored I guess.
And couple of WPF properties missing -- like layout rounding and text render preferences.
I've got the code and can post it.
Reflector provides convenient tooltips when hovering over an IL opcode, describing the opcode and giving the hexadecimal value of it. The descriptions are taken from the xml documentation summary tags for the corresponding fields in the System.Reflection.Emit.OpCodes class.
Please consider adding such tooltips once you have support for loading and displaying the xml documentation for an assembly.
Ln 207 if (branchTarget.StackBefore.Count != newStack.Count) // is true
Ln 233 int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count; // StackBefore == null
Ln 384 int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count; // StackBefore == null
class Class1
{
private int i = 0;
public void method(out string str)
{
str = "qq";
str += i.ToString();
}
}
public void method(out string str)
{
str = "qq";
string expr_09 = ref str;
string arg_0A_0 = expr_09;
stind.ref(expr_09, ldind.ref(arg_0A_0) + this.i.ToString());
}
class MyArray<T> where T : new()
{
private T[] arr;
public MyArray()
{
this.arr = new T[20];
}
public MyArray(int capacity)
{
this.arr = new T[capacity];
}
public void Size(int capacity)
{
T[] destinationArray = new T[capacity];
Array.Copy(this.arr, destinationArray, this.arr.Length);
this.arr = destinationArray;
}
public void Grow(int capacity)
{
if (capacity >= this.arr.Length)
{
this.Size(capacity + 1);
}
if (this.arr[capacity] == null)
{
this.arr[capacity] = new T();
}
}
}
public void Grow(int capacity)
{
if (capacity >= this.arr.Length)
{
base.Size(capacity + 1); <===============
}
if (ldelem.any(T, this.arr, capacity) == null) <===========
{
T[] arg_5F_0 = this.arr; <==== new T();
int arg_5F_1 = capacity;
T t = default(T);
T arg_5F_2;
if (t == null)
{
arg_5F_2 = Activator.CreateInstance();
}
else
{
t = default(T);
arg_5F_2 = t;
}
arg_5F_0[arg_5F_1] = arg_5F_2;
}
}
Trying to decompile the method 'System.Globalization.TimeSpanParse::ProcessTerminal_HMS_F_D' causes the decompiler to hang up within ILAstOptimizer.TryMatchCondition.
This issue is just to help remind you of the current lack of support for unsafe code in ILSpy. A reasonable example of a fairly simple unsafe function is System.Double.IsInfinity.
Reflector gives the following code:
public static unsafe bool IsInfinity(double d)
{
return (((((long) &d)) & 0x7fffffffffffffffL) == 0x7ff0000000000000L);
}
ILSpy 1.0.0.427 Gives:
public static bool IsInfinity(double d)
{
return (ldind.i8((object)ref d) & 9223372036854775807L) == 9218868437227405312L;
}
There are a few things needed for this:
This particular function would also greatly benefit from an option or heuristics for displaying literals in Hexadecimal format, but that would be a separate issue.
' ', hexadecimal value 0x01, is an invalid character.
Preservation of context during the exit from the program, which was loaded obfuscated assembly.
ILSpy_0.1.0.341_Source\ICSharpCode.Decompiler\Ast\Transforms\RemoveGotos.cs
public static AstNode GetNextStatement(Statement statement)
{
...
Statement next = (Statement)statement.NextSibling;
...
}
The trouble is that the assembly was obtained from the Visual Basic. His optimizer leaves much to be desired.
mscorlib
namespace System.Globalization
class TimeSpanParse
internal static TimeSpan ParseExact(string input, string format, IFormatProvider formatProvider, TimeSpanStyles styles)
{
initobj(System.Globalization.TimeSpanParse/TimeSpanResult, ref timeSpanResult);
must be
TimeSpanResult timeSpanResult = new TimeSpanResult();
...
}
"Check for updates" does not support web-proxy. If PC requires a web-proxy to connect to the internet, the check fails with an exception:
System.AggregateException: One or more errors occurred. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: Impossibile stabilire la connessione. Risposta non corretta della parte connessa dopo l'intervallo di tempo oppure mancata risposta dall'host collegato 195.234.231.66:80
at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
.... [SNIP] ....
ILSpy 1.0.0.427 gives the following for System.Double.IsNaN():
public static bool IsNaN(double d)
{
if (d != d)
{
return true;
}
return false;
}
That decompilation is entirely correct, but it is subobptimal. It would be better as a one liner like reflector gives:
public static bool IsNaN(double d)
{
return (d != d);
}
The pattern matching should also be able to handle returning the negation of the condition, for cases of the form "if(...) return false; else return true;".
mscorlib
namespace System.Globalization
class TimeSpanParse.
Hi,
I have noticed in a few places that an "else" is shown after argument checks (for nullity or anything else).
For example, in System.Collections.ArrayList :
public static ArrayList Adapter(IList list)
{
if (list == null)
{
throw new ArgumentNullException("list");
}
else
{
return new ArrayList.IListWrapper(list);
}
}
The else is not necessary.
When the Var button is clicked and if Graphviz is not installed the ILSpy application crashes. The application should inform the user that Graphviz is not installed instead of crashing.
Found this code when browsing ILSpy code on ILSpy:
function path: ILSpy/ICSharpCode.ILSpy/CSharpLanguage/d__7
private IEnumerator System.Collections.Generic.IEnumerable<ICSharpCode.ILSpy.CSharpLanguage>.GetEnumerator()
{
if (Thread.CurrentThread.ManagedThreadId == this.<>l__initialThreadId)
{
var arg_22_0 = this.<>1__state == -2 == 0; // <<< assinged bool
}
else
{
arg_22_0 = 1; // <<< assigned int
}
if (arg_22_0 == null) // <<< compared to pointer
{
this.<>1__state = 0;
CSharpLanguage.d__7 d__7 = this;
}
else
{
d__7 = new CSharpLanguage.d__7(0);
}
IEnumerator enumerator = d__7;
return enumerator;
}
public override void add_busChanged(__RSControl_busChangedEventHandler) <---- handler1
{
bool flag;
try
{
Monitor.Enter(this, ref flag);
if (this.m_ConnectionPoint == null)
{
this.Init();
}
__RSControl_SinkHelper __RSControl_SinkHelper = new __RSControl_SinkHelper();
int i = 0;
this.m_ConnectionPoint.Advise((object)__RSControl_SinkHelper, ref i);
__RSControl_SinkHelper.m_dwCookie = i;
__RSControl_SinkHelper.m_busChangedDelegate = ; <----- handler1
this.m_aEventSinkHelpers.Add((object)__RSControl_SinkHelper);
}
finally
{
if (flag)
{
Monitor.Exit(this);
}
}
}
IL_0048: ldarg <---- 1
The decompiler creates an unnecessary even confusing base..ctor() call in the constructor.
Artificial code to show you, what I mean:
public MyClass() { this.myField1 = true; base..ctor(); }
---> System.InvalidCastException: Unable to cast object of type 'Mono.Cecil.ArrayType' to type 'Mono.Cecil.GenericInstanceType'.
at Decompiler.TypeAnalysis.SubstituteTypeArgs(TypeReference type, MemberReference member)
internal class A<T> where T : new()
{
private T[,] a = new T[20, 20];
public T this[int i, int j]
{
get { return a[i, j]; }
set { a[i, j] = value; }
}
}
double num = 12.345;
double num2 = 12.0;
Console.WriteLine("{0:#.#} {1:#.#}", box(System.Double, num), box(System.Double, num2));
Notice the unnecessary box(...) instructions around num and num2.
For instance:
for (int current = 0; ; )
{
bool flag = current < 100; //<----- note this 'flag' variable created automatically by the decompiler
if (!flag)
{
break;
}
else
{
this.DoSomething();
current += 1;
}
}
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
flag = (list == null); //<----- the same 'flag' used again, although not in scope.
if (!flag)
{
this.DoSomething();
}
at ICSharpCode.NRefactory.Utils.CSharpPrimitiveCast.CSharpPrimitiveCastUnchecked(TypeCode targetType, Object input)
at Decompiler.AstMethodBodyBuilder.MakePrimitive(Int64 val, TypeReference type)
at Decompiler.AstMethodBodyBuilder.TransformByteCode(ILExpression byteCode, List`1 args)
at Decompiler.AstMethodBodyBuilder.TransformExpression(ILExpression expr)
...
IL_005a: ldloc.2
IL_005b: ldfld class RSClient_I32.__CallBackClass_busChangedEventHandler class RSClient_I32.__CallBackClass_SinkHelper::m_busChangedDelegate
IL_0060: ldarg <-------------- ldarg 1
IL_0064: castclass object
IL_0069: callvirt instance bool [mscorlib]System.Delegate::Equals(object)
IL_006e: ldc.i4 255 <----------- System.InvalidCastException
IL_0073: and
IL_0074: ldc.i4 0
IL_0079: beq IL_00d4
C# null checks are decompiled as :
if(instance)
{
instance.Dispose();
}
Correct should be
if (instance != null)
class a
{
methods...
class aa
{
}
}
It is necessary for proper operation of the visual dezaynera.
in a class without a ctor, ILSpy shows this:
public() : base()
{
}
Trying to decompile queryview.baml located in Profiler.Controls.dll causes this exception:
System.Xaml.XamlXmlWriterException: Cannot write the given positional parameters because a matching constructor was not found.
at System.Xaml.XamlXmlWriter.ExpandPositionalParameters.ExpandPositionalParametersIntoProperties(XamlXmlWriter writer)
at System.Xaml.XamlXmlWriter.ExpandPositionalParameters.WriteEndMember(XamlXmlWriter writer)
at System.Xaml.XamlXmlWriter.WriteEndMember()
at ICSharpCode.ILSpy.BamlDecompiler.DecompileBaml(MemoryStream bamlCode, Dictionary2 assemblies, String containingAssemblyFile) in d:\Projects\SharpDevelop\ILSpy\ILSpy\BamlDecompiler.cs:line 53 at ICSharpCode.ILSpy.BamlDecompiler.DecompileBaml(MemoryStream bamlCode, Dictionary
2 assemblies, String containingAssemblyFile)
at ICSharpCode.ILSpy.TreeNodes.ResourceEntryNode.LoadBaml(AvalonEditTextOutput output) in d:\Projects\SharpDevelop\ILSpy\ILSpy\TreeNodes\ResourceEntryNode.cs:line 111
at ICSharpCode.ILSpy.TreeNodes.ResourceEntryNode.<>c__DisplayClass5.b__1() in d:\Projects\SharpDevelop\ILSpy\ILSpy\TreeNodes\ResourceEntryNode.cs:line 55
I'm not sure how difficult this would be but if possible the C# using pattern should be used instead of explicit try finally.
Hey,
I've got the latest sources and I tried to decompile the SearchBox from ILSpy and ILSpy crashed...
When debugging I got this error:
Can not intercept exception. Debugged program can not be continued and properties can not be evaluated.
System.StackOverflowException
at Object Decompiler.Transforms.PushNegation.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, Object data) in e:\ILSpy\ICSharpCode.Decompiler\Ast\Transforms\PushNegation.cs:line 80
at Object ICSharpCode.NRefactory.CSharp.BinaryOperatorExpression.AcceptVisitor(IAstVisitor2 visitor, Object data) in e:\ILSpy\NRefactory\ICSharpCode.NRefactory\CSharp\Ast\Expressions\BinaryOperatorExpression.cs:line 72 at Object Decompiler.Transforms.PushNegation.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, Object data) in e:\ILSpy\ICSharpCode.Decompiler\Ast\Transforms\PushNegation.cs:line 86 at Object ICSharpCode.NRefactory.CSharp.BinaryOperatorExpression.AcceptVisitor(IAstVisitor
2 visitor, Object data) in e:\ILSpy\NRefactory\ICSharpCode.NRefactory\CSharp\Ast\Expressions\BinaryOperatorExpression.cs:line 72
at Object Decompiler.Transforms.PushNegation.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, Object data) in e:\ILSpy\ICSharpCode.Decompiler\Ast\Transforms\PushNegation.cs:line 86
at Object ICSharpCode.NRefactory.CSharp.BinaryOperatorExpression.AcceptVisitor(IAstVisitor2 visitor, Object data) in e:\ILSpy\NRefactory\ICSharpCode.NRefactory\CSharp\Ast\Expressions\BinaryOperatorExpression.cs:line 72 at Object Decompiler.Transforms.PushNegation.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, Object data) in e:\ILSpy\ICSharpCode.Decompiler\Ast\Transforms\PushNegation.cs:line 86 at Object ICSharpCode.NRefactory.CSharp.BinaryOperatorExpression.AcceptVisitor(IAstVisitor
2 visitor, Object data) in e:\ILSpy\NRefactory\ICSharpCode.NRefactory\CSharp\Ast\Expressions\BinaryOperatorExpression.cs:line 72
The decompiled version of this:
public void ForLoopTest()
{
for (int i = 0; i < 100; ++i)
{
DoSomething();
}
}
is this:
public void ForLoopTest()
{
for (int i = 0; ; )
{
if (i >= 100) // should be placed after first semicolon
{
break;
}
else
{
this.DoSomething(); // redundant 'this.'
i += 1; // can be changed to ++i or i++ and placed after second semicolon
}
}
}
When you press the back button to go to the previous class, the methods that where opened before are collapsed again.
ILSpy decompile:
private void InsertComments(CompilerCompilationUnit top, ConversionVisitor conversionVisitor)
{
...
}
from ILSpy_0.1.0.335_Source\NRefactory\ICSharpCode.NRefactory\CSharp\Parser\CSharpParser.cs
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.