Browse Source

Fix subtle issues with BitNot operator.

pull/728/head
Daniel Grunwald 9 years ago
parent
commit
3faca4372e
  1. 105
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 4
      ICSharpCode.Decompiler/IL/ILReader.cs
  3. 2
      ICSharpCode.Decompiler/IL/Instructions.cs
  4. 2
      ICSharpCode.Decompiler/IL/Instructions.tt
  5. 5
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  6. 52
      ICSharpCode.Decompiler/Tests/Helpers/Tester.cs
  7. 2
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  8. 8
      ICSharpCode.Decompiler/Tests/RoundtripAssembly.cs
  9. 96
      ICSharpCode.Decompiler/Tests/TestCases/BitNot.il
  10. 93
      ICSharpCode.Decompiler/Tests/TestCases/ILTest.il
  11. 10
      ICSharpCode.Decompiler/Tests/TestRunner.cs

105
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -279,34 +279,38 @@ namespace ICSharpCode.Decompiler.CSharp @@ -279,34 +279,38 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitBitNot(BitNot inst)
{
var argument = Translate(inst.Argument);
var compatibleType = argument.Type.GetEnumUnderlyingType();
var type = compatibleType.GetDefinition();
if (argument.Type.GetStackType().GetSize() < inst.ResultType.GetSize()
|| argument.Type.Kind == TypeKind.Enum && argument.Type.IsSmallIntegerType())
{
// Argument is undersized (even after implicit integral promotion to I4)
// -> we need to perform sign/zero-extension before the BitNot.
// Same if the argument is an enum based on a small integer type
// (those don't undergo numeric promotion in C# the way non-enum small integer types do).
argument = argument.ConvertTo(compilation.FindType(inst.ResultType.ToKnownTypeCode(argument.Type.GetSign())), this);
}
var type = argument.Type.GetDefinition();
if (type != null) {
// Handle those types that don't support operator ~
// Note that it's OK to use a type that's larger than necessary.
switch (type.KnownTypeCode) {
case KnownTypeCode.Boolean:
case KnownTypeCode.Char:
compatibleType = compilation.FindType(KnownTypeCode.UInt32);
argument = argument.ConvertTo(compilation.FindType(KnownTypeCode.UInt32), this);
break;
case KnownTypeCode.IntPtr:
compatibleType = compilation.FindType(KnownTypeCode.Int64);
argument = argument.ConvertTo(compilation.FindType(KnownTypeCode.Int64), this);
break;
case KnownTypeCode.UIntPtr:
compatibleType = compilation.FindType(KnownTypeCode.UInt64);
argument = argument.ConvertTo(compilation.FindType(KnownTypeCode.UInt64), this);
break;
}
}
argument = argument.ConvertTo(compatibleType, this);
var rr = resolver.ResolveUnaryOperator(UnaryOperatorType.BitNot, argument.ResolveResult);
var result = new UnaryOperatorExpression(UnaryOperatorType.BitNot, argument)
.WithRR(rr)
return new UnaryOperatorExpression(UnaryOperatorType.BitNot, argument)
.WithRR(resolver.ResolveUnaryOperator(UnaryOperatorType.BitNot, argument.ResolveResult))
.WithILInstruction(inst);
if (type != null && (type.KnownTypeCode == KnownTypeCode.IntPtr || type.KnownTypeCode == KnownTypeCode.UIntPtr)) {
return result.ConvertTo(type, this);
} else {
return result;
}
}
ExpressionWithResolveResult LogicNot(TranslatedExpression expr)
@ -510,33 +514,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -510,33 +514,16 @@ namespace ICSharpCode.Decompiler.CSharp
var resolverWithOverflowCheck = resolver.WithCheckForOverflow(inst.CheckForOverflow);
var left = Translate(inst.Left);
var right = Translate(inst.Right);
ResolveResult rr;
if (left.Type.GetStackType() == StackType.I || right.Type.GetStackType() == StackType.I) {
// IntPtr or pointers as input.
// C# doesn't allow adding IntPtr values, and adding pointer values has the wrong semantics
// (adding number of elements instead of number of bytes), so switch to long/ulong in both cases.
IType targetType;
if (inst.Sign == Sign.Unsigned) {
targetType = compilation.FindType(KnownTypeCode.UInt64);
} else {
targetType = compilation.FindType(KnownTypeCode.Int64);
}
left = left.ConvertTo(targetType, this);
right = right.ConvertTo(targetType, this);
rr = new OperatorResolveResult(targetType, BinaryOperatorExpression.GetLinqNodeType(op, inst.CheckForOverflow), left.ResolveResult, right.ResolveResult);
var resultExpr = new BinaryOperatorExpression(left.Expression, op, right.Expression)
.WithILInstruction(inst)
.WithRR(rr);
if (BinaryOperatorMightCheckForOverflow(op))
resultExpr.Expression.AddAnnotation(inst.CheckForOverflow ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation);
return resultExpr.ConvertTo(compilation.FindType(inst.ResultType.ToKnownTypeCode()), this);
} else {
rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
left = PrepareArithmeticArgument(left, inst.Left.ResultType, inst.Sign);
right = PrepareArithmeticArgument(right, inst.Right.ResultType, inst.Sign);
var rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
if (rr.IsError || rr.Type.GetStackType() != inst.ResultType
|| !IsCompatibleWithSign(left.Type, inst.Sign) || !IsCompatibleWithSign(right.Type, inst.Sign))
{
// Left and right operands are incompatible, so convert them to a common type
IType targetType = compilation.FindType(inst.ResultType.ToKnownTypeCode(inst.Sign));
StackType targetStackType = inst.ResultType == StackType.I ? StackType.I8 : inst.ResultType;
IType targetType = compilation.FindType(targetStackType.ToKnownTypeCode(inst.Sign));
left = left.ConvertTo(targetType, this);
right = right.ConvertTo(targetType, this);
rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
@ -548,6 +535,33 @@ namespace ICSharpCode.Decompiler.CSharp @@ -548,6 +535,33 @@ namespace ICSharpCode.Decompiler.CSharp
resultExpr.Expression.AddAnnotation(inst.CheckForOverflow ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation);
return resultExpr;
}
/// <summary>
/// Handle oversized arguments needing truncation; and avoid IntPtr/pointers in arguments.
/// </summary>
TranslatedExpression PrepareArithmeticArgument(TranslatedExpression arg, StackType argStackType, Sign sign)
{
if (argStackType.IsIntegerType() && argStackType.GetSize() < arg.Type.GetSize()) {
// If the argument is oversized (needs truncation to match stack size of its ILInstruction),
// perform the truncation now.
arg = arg.ConvertTo(compilation.FindType(argStackType.ToKnownTypeCode(sign)), this);
}
if (arg.Type.GetStackType() == StackType.I) {
// None of the operators we might want to apply are supported by IntPtr/UIntPtr.
// Also, pointer arithmetic has different semantics (works in number of elements, not bytes).
// So any inputs of size StackType.I must be converted to long/ulong.
arg = arg.ConvertTo(compilation.FindType(StackType.I8.ToKnownTypeCode(sign)), this);
}
return arg;
}
/// <summary>
/// Gets whether <paramref name="type"/> has the specified <paramref name="sign"/>.
/// If <paramref name="sign"/> is None, always returns true.
/// </summary>
static bool IsCompatibleWithSign(IType type, Sign sign)
{
return sign == Sign.None || type.GetSign() == sign;
}
static bool BinaryOperatorMightCheckForOverflow(BinaryOperatorType op)
@ -564,15 +578,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -564,15 +578,6 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
/// <summary>
/// Gets whether <paramref name="type"/> has the specified <paramref name="sign"/>.
/// If <paramref name="sign"/> is None, always returns true.
/// </summary>
bool IsCompatibleWithSign(IType type, Sign sign)
{
return sign == Sign.None || type.GetSign() == sign;
}
protected internal override TranslatedExpression VisitShl(Shl inst)
{
return HandleShift(inst, BinaryOperatorType.ShiftLeft);
@ -689,6 +694,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -689,6 +694,8 @@ namespace ICSharpCode.Decompiler.CSharp
// If the target type is a small integer type, IL will implicitly sign- or zero-extend
// the result after the truncation back to StackType.I4.
// (which means there's actually 3 conversions involved!)
// Note that we must handle truncation to small integer types ourselves:
// our caller only sees the StackType.I4 and doesn't know to truncate to the small type.
if (arg.Type.GetSize() <= inst.TargetType.GetSize() && arg.Type.GetSign() == inst.TargetType.GetSign()) {
// There's no actual truncation involved, and the result of the Conv instruction is extended
@ -989,17 +996,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -989,17 +996,15 @@ namespace ICSharpCode.Decompiler.CSharp
if (arrayExpr.Type.Kind != TypeKind.Array) {
arrayExpr = arrayExpr.ConvertTo(compilation.FindType(KnownTypeCode.Array), this);
}
TranslatedExpression lenExpr;
if (inst.ResultType == StackType.I4) {
lenExpr = arrayExpr.Expression.Member("Length")
return arrayExpr.Expression.Member("Length")
.WithILInstruction(inst)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Int32)));
} else {
lenExpr = arrayExpr.Expression.Member("LongLength")
return arrayExpr.Expression.Member("LongLength")
.WithILInstruction(inst)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Int64)));
}
return lenExpr.ConvertTo(compilation.FindType(inst.ResultType.ToKnownTypeCode()), this);
}
protected internal override TranslatedExpression VisitLdFlda(LdFlda inst)

4
ICSharpCode.Decompiler/IL/ILReader.cs

@ -337,7 +337,7 @@ namespace ICSharpCode.Decompiler.IL @@ -337,7 +337,7 @@ namespace ICSharpCode.Decompiler.IL
case StackType.I4:
return Push(new Sub(new LdcI4(0), Pop(), checkForOverflow: false, sign: Sign.None));
case StackType.I:
return Push(new Sub(new Conv(new LdcI4(0), PrimitiveType.I, false, Sign.Signed), Pop(), checkForOverflow: false, sign: Sign.None));
return Push(new Sub(new Conv(new LdcI4(0), PrimitiveType.I, false, Sign.None), Pop(), checkForOverflow: false, sign: Sign.None));
case StackType.I8:
return Push(new Sub(new LdcI8(0), Pop(), checkForOverflow: false, sign: Sign.None));
case StackType.F:
@ -880,6 +880,8 @@ namespace ICSharpCode.Decompiler.IL @@ -880,6 +880,8 @@ namespace ICSharpCode.Decompiler.IL
if (expectedType != inst.ResultType) {
if (expectedType == StackType.I && inst.ResultType == StackType.I4) {
inst = new Conv(inst, PrimitiveType.I, false, Sign.None);
} else if (inst is InvalidInstruction) {
((InvalidInstruction)inst).ExpectedResultType = expectedType;
} else {
Warn($"Expected {expectedType}, but got {inst.ResultType}");
}

2
ICSharpCode.Decompiler/IL/Instructions.cs

@ -452,7 +452,7 @@ namespace ICSharpCode.Decompiler.IL @@ -452,7 +452,7 @@ namespace ICSharpCode.Decompiler.IL
public InvalidInstruction() : base(OpCode.InvalidInstruction)
{
}
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -37,7 +37,7 @@ @@ -37,7 +37,7 @@
OpCode[] opCodes = {
new OpCode("invalid", "Represents invalid IL. Semantically, this instruction is considered to throw some kind of exception.",
CustomClassName("InvalidInstruction"), NoArguments, MayThrow, UnconditionalBranch),
CustomClassName("InvalidInstruction"), NoArguments, MayThrow, HasFlag("InstructionFlags.EndPointUnreachable")),
new OpCode("nop", "No operation. Takes 0 arguments and returns void.",
VoidResult, NoArguments),
new OpCode("ILFunction", "A container of IL blocks.",

5
ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs

@ -40,12 +40,17 @@ namespace ICSharpCode.Decompiler.IL @@ -40,12 +40,17 @@ namespace ICSharpCode.Decompiler.IL
partial class InvalidInstruction : SimpleInstruction
{
public string Message;
public StackType ExpectedResultType = StackType.Unknown;
public InvalidInstruction(string message) : this()
{
this.Message = message;
}
public override StackType ResultType {
get { return ExpectedResultType; }
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);

52
ICSharpCode.Decompiler/Tests/Helpers/Tester.cs

@ -56,7 +56,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -56,7 +56,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
public static string AssembleIL(string sourceFileName, AssemblerOptions options = AssemblerOptions.UseDebug)
{
string ilasmPath = Path.Combine(Environment.GetEnvironmentVariable("windir"), @"Microsoft.NET\Framework\v4.0.30319\ilasm.exe");
string outputFile = Path.GetTempFileName();
string outputFile = sourceFileName + ".exe";
string otherOptions = " ";
@ -155,34 +155,52 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -155,34 +155,52 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
int result1 = Tester.Run(outputFile, out output1, out error1);
int result2 = Tester.Run(decompiledOutputFile, out output2, out error2);
if (result1 != result2 || output1 != output2 || error1 != error2) {
Console.WriteLine("original: " + outputFile);
Console.WriteLine("decompiled: " + decompiledOutputFile);
Assert.AreEqual(0, result1, "Exit code != 0; did the test case crash?" + Environment.NewLine + error1);
Assert.AreEqual(0, result2, "Exit code != 0; did the decompiled code crash?" + Environment.NewLine + error2);
Console.WriteLine("Test {0} failed.", testFileName);
if (decompiledCodeFile != null)
Console.WriteLine("Decompiled code in {0}:line 1", decompiledCodeFile);
if (error1 == "" && error2 != "") {
Console.WriteLine(error2);
} else {
if (output1 != output2 || error1 != error2) {
StringBuilder b = new StringBuilder();
b.AppendLine($"Test {testFileName} failed: output does not match.");
if (decompiledCodeFile != null) {
b.AppendLine($"Decompiled code in {decompiledCodeFile}:line 1");
}
if (error1 != error2) {
b.AppendLine("Got different error output.");
b.AppendLine("Original error:");
b.AppendLine(error1);
b.AppendLine();
b.AppendLine("Error after de+re-compiling:");
b.AppendLine(error2);
b.AppendLine();
}
if (output1 != output2) {
string outputFileName = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(testFileName));
File.WriteAllText(outputFileName + ".original.out", output1);
File.WriteAllText(outputFileName + ".decompiled.out", output2);
int diffLine = 0;
foreach (var pair in output1.Split('\n').Zip(output2.Split('\n'), Tuple.Create)) {
string lastHeader = null;
Tuple<string, string> errorItem = null;
foreach (var pair in output1.Replace("\r", "").Split('\n').Zip(output2.Replace("\r", "").Split('\n'), Tuple.Create)) {
diffLine++;
if (pair.Item1 != pair.Item2) {
errorItem = pair;
break;
}
if (pair.Item1.EndsWith(":", StringComparison.Ordinal)) {
lastHeader = pair.Item1;
}
Console.WriteLine("Output: {0}.original.out:line {1}", outputFileName, diffLine);
Console.WriteLine("Output: {0}.decompiled.out:line {1}", outputFileName, diffLine);
}
b.AppendLine($"Output differs; first difference in line {diffLine}");
if (lastHeader != null) {
b.AppendLine(lastHeader);
}
b.AppendLine($"{outputFileName}.original.out:line {diffLine}");
b.AppendLine(errorItem.Item1);
b.AppendLine($"{outputFileName}.decompiled.out:line {diffLine}");
b.AppendLine(errorItem.Item2);
}
Assert.Fail(b.ToString());
}
Assert.AreEqual(0, result1, "Exit code != 0; did the test case crash?" + Environment.NewLine + error1);
Assert.AreEqual(0, result2, "Exit code != 0; did the decompiled code crash?" + Environment.NewLine + error2);
Assert.AreEqual(error1, error2);
Assert.AreEqual(output1, output2);
}
}
}

2
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -89,7 +89,7 @@ @@ -89,7 +89,7 @@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="TestCases\ConvTest.il" />
<None Include="TestCases\BitNot.il" />
<None Include="TestCases\ILTest.il" />
<None Include="TestCases\Readme.txt" />
</ItemGroup>

8
ICSharpCode.Decompiler/Tests/RoundtripAssembly.cs

@ -62,25 +62,25 @@ namespace ICSharpCode.Decompiler.Tests @@ -62,25 +62,25 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public void Implicit_Conversions()
public void ImplicitConversions()
{
RunWithOutput("Random Tests\\TestCases", "ImplicitConversions.exe");
}
[Test]
public void Implicit_Conversions_32()
public void ImplicitConversions_32()
{
RunWithOutput("Random Tests\\TestCases", "ImplicitConversions_32.exe");
}
[Test]
public void Explicit_Conversions()
public void ExplicitConversions()
{
RunWithOutput("Random Tests\\TestCases", "ExplicitConversions.exe");
}
[Test]
public void Explicit_Conversions_32()
public void ExplicitConversions_32()
{
RunWithOutput("Random Tests\\TestCases", "ExplicitConversions_32.exe");
}

96
ICSharpCode.Decompiler/Tests/TestCases/BitNot.il

@ -0,0 +1,96 @@ @@ -0,0 +1,96 @@
.assembly extern mscorlib
{
.publickeytoken = ( b7 7a 5c 56 19 34 e0 89 )
.ver 4:0:0:0
}
.assembly 'ConvTest'
{
.ver 0:0:0:0
}
.module ConvTest.exe
.corflags 0x00000001 // ILOnly
.class private auto ansi abstract sealed beforefieldinit Program
extends [mscorlib]System.Object
{
.method public hidebysig static void Main (string[] args) cil managed
{
.maxstack 8
.entrypoint
ldc.i8 0xCCCCCCCCCCCCCCCC
call int64 Program::BitwiseComplementInNativeSize(int64)
call void Program::PrintHex(int64)
ldc.i4 0x99999999
call int64 Program::BitwiseComplementWithUndersizedValue(int32)
call void Program::PrintHex(int64)
ldc.i4 0x9999
call int32 Program::BitwiseComplementWithSmallInteger(uint16)
call void Program::PrintHex(int32)
ldc.i4 0x9999
call int32 Program::BitwiseComplementWithSmallEnum(valuetype Enums.EUInt16)
call void Program::PrintHex(int32)
ret
} // end of method Main
.method public static int64 BitwiseComplementInNativeSize(int64 val)
{
ldarg.0
conv.i // truncate 64-bits to native-size bits
not // negate those native size bits
conv.i8 // sign extend back to 64-bits
ret
}
.method public static int64 BitwiseComplementWithUndersizedValue(int32 val)
{
ldarg.0
conv.u8 // zero extend up to 64-bits
not // negate those 64-bits
ret
}
.method public static int32 BitwiseComplementWithSmallInteger(uint16 val)
{
ldarg.0 // zero extend up to 32-bits
not // negate those 32-bits
ret
}
.method public static int32 BitwiseComplementWithSmallEnum(valuetype Enums.EUInt16 val)
{
ldarg.0 // zero extend up to 32-bits
not // negate those 32-bits
ret
}
.method public static void PrintHex(int32 val)
{
ldstr "{0:x8}"
ldarg.0
box valuetype [mscorlib]System.UInt32
call void [mscorlib]System.Console::WriteLine(string, object)
ret
}
.method public static void PrintHex(int64 val)
{
ldstr "{0:x16}"
ldarg.0
box valuetype [mscorlib]System.UInt64
call void [mscorlib]System.Console::WriteLine(string, object)
ret
}
}
.class public auto ansi sealed Enums.EUInt16
extends [mscorlib]System.Enum
{
.field public specialname uint16 __value
}

93
ICSharpCode.Decompiler/Tests/TestCases/ILTest.il

@ -2,101 +2,28 @@ @@ -2,101 +2,28 @@
.assembly extern mscorlib
{
.publickeytoken = (
b7 7a 5c 56 19 34 e0 89
)
.publickeytoken = ( b7 7a 5c 56 19 34 e0 89 )
.ver 4:0:0:0
}
.assembly HelloWorld
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = (
01 00 08 00 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (
01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78
63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01
)
.custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
01 00 07 01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = (
01 00 0a 48 65 6c 6c 6f 57 6f 72 6c 64 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = (
01 00 0a 48 65 6c 6c 6f 57 6f 72 6c 64 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = (
01 00 0e 43 6f 70 79 72 69 67 68 74 20 32 30 31
36 00 00
)
.custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = (
01 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = (
01 00 1a 2e 4e 45 54 46 72 61 6d 65 77 6f 72 6b
2c 56 65 72 73 69 6f 6e 3d 76 34 2e 30 01 00 54
0e 14 46 72 61 6d 65 77 6f 72 6b 44 69 73 70 6c
61 79 4e 61 6d 65 10 2e 4e 45 54 20 46 72 61 6d
65 77 6f 72 6b 20 34
)
.hash algorithm 0x00008004 // SHA1
.ver 1:0:6020:38157
.ver 0:0:0:0
}
.module HelloWorld.exe
// MVID: {987E1A15-519A-400C-B879-759CFB7F990B}
.corflags 0x00000003 // ILOnly, Required32Bit
.corflags 0x00000001 // ILOnly
.class private auto ansi '<Module>'
{
} // end of class <Module>
.class private auto ansi beforefieldinit HelloWorld.Program
.class private auto ansi abstract sealed beforefieldinit Program
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig static
void Main (
string[] args
) cil managed
.method public hidebysig static void Main (string[] args) cil managed
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 8
.entrypoint
IL_0000: nop
IL_0001: ldstr "Hello World!"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Program::Main
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x205e
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Program::.ctor
} // end of class HelloWorld.Program
ldstr "Hello World!"
call void [mscorlib]System.Console::WriteLine(string)
ret
} // end of method Main
} // end of class <Module>

10
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -23,7 +23,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -23,7 +23,7 @@ namespace ICSharpCode.Decompiler.Tests
.Select(m => m.Name)
.ToArray();
foreach (var file in new DirectoryInfo(TestCasePath).EnumerateFiles()) {
if (file.Extension == ".txt")
if (file.Extension == ".txt" || file.Extension == ".exe")
continue;
var testName = Path.GetFileNameWithoutExtension(file.Name);
Assert.Contains(testName, testNames);
@ -121,6 +121,13 @@ namespace ICSharpCode.Decompiler.Tests @@ -121,6 +121,13 @@ namespace ICSharpCode.Decompiler.Tests
TestAssembleDecompileCompileOutput("ConvTest.il", CompilerOptions.UseDebug | CompilerOptions.Force32Bit, AssemblerOptions.Force32Bit);
}
[Test]
public void BitNot()
{
TestAssembleDecompileCompileOutput("BitNot.il");
TestAssembleDecompileCompileOutput("BitNot.il", CompilerOptions.UseDebug | CompilerOptions.Force32Bit, AssemblerOptions.Force32Bit);
}
[Test, Ignore("Fixed statements are broken")]
public void UnsafeCode()
{
@ -170,7 +177,6 @@ namespace ICSharpCode.Decompiler.Tests @@ -170,7 +177,6 @@ namespace ICSharpCode.Decompiler.Tests
Tester.RunAndCompareOutput(testFileName, outputFile, decompiledOutputFile.PathToAssembly, decompiledCodeFile);
File.Delete(decompiledCodeFile);
File.Delete(outputFile);
File.Delete(decompiledOutputFile.PathToAssembly);
} finally {
if (decompiledOutputFile != null)

Loading…
Cancel
Save