Browse Source

#1195: Fix comparison of object reference with ldc.i4 0.

pull/1243/head
Daniel Grunwald 8 years ago
parent
commit
2f54eee5db
  1. 44
      ICSharpCode.Decompiler/IL/ILReader.cs
  2. 8
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

44
ICSharpCode.Decompiler/IL/ILReader.cs

@ -76,6 +76,7 @@ namespace ICSharpCode.Decompiler.IL @@ -76,6 +76,7 @@ namespace ICSharpCode.Decompiler.IL
BitArray isBranchTarget;
BlockContainer mainContainer;
List<ILInstruction> instructionBuilder;
int currentInstructionStart;
// Dictionary that stores stacks for each IL instruction
Dictionary<int, ImmutableStack<ILVariable>> stackByOffset;
@ -251,7 +252,7 @@ namespace ICSharpCode.Decompiler.IL @@ -251,7 +252,7 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
void Warn(string message)
{
Warnings.Add(string.Format("IL_{0:x4}: {1}", reader.Offset, message));
Warnings.Add(string.Format("IL_{0:x4}: {1}", currentInstructionStart, message));
}
ImmutableStack<ILVariable> MergeStacks(ImmutableStack<ILVariable> a, ImmutableStack<ILVariable> b)
@ -382,6 +383,7 @@ namespace ICSharpCode.Decompiler.IL @@ -382,6 +383,7 @@ namespace ICSharpCode.Decompiler.IL
cancellationToken.ThrowIfCancellationRequested();
int start = reader.Offset;
StoreStackForOffset(start, ref currentStack);
currentInstructionStart = start;
ILInstruction decodedInstruction;
try {
decodedInstruction = DecodeInstruction();
@ -1427,22 +1429,31 @@ namespace ICSharpCode.Decompiler.IL @@ -1427,22 +1429,31 @@ namespace ICSharpCode.Decompiler.IL
{
var right = Pop();
var left = Pop();
// make the implicit I4->I conversion explicit:
if (left.ResultType == StackType.I4 && right.ResultType == StackType.I) {
left = new Conv(left, PrimitiveType.I, false, Sign.None);
} else if (left.ResultType == StackType.I && right.ResultType == StackType.I4) {
right = new Conv(right, PrimitiveType.I, false, Sign.None);
if (left.ResultType == StackType.O && right.ResultType.IsIntegerType()) {
// C++/CLI sometimes compares object references with integers.
if (right.ResultType == StackType.I4) {
// ensure we compare at least native integer size
right = new Conv(right, PrimitiveType.I, false, Sign.None);
}
left = new Conv(left, right.ResultType.ToPrimitiveType(), false, Sign.None);
} else if (right.ResultType == StackType.O && left.ResultType.IsIntegerType()) {
if (left.ResultType == StackType.I4) {
left = new Conv(left, PrimitiveType.I, false, Sign.None);
}
right = new Conv(right, left.ResultType.ToPrimitiveType(), false, Sign.None);
}
// make implicit integer conversions explicit:
MakeExplicitConversion(sourceType: StackType.I4, targetType: StackType.I, conversionType: PrimitiveType.I);
MakeExplicitConversion(sourceType: StackType.I4, targetType: StackType.I8, conversionType: PrimitiveType.I8);
MakeExplicitConversion(sourceType: StackType.I, targetType: StackType.I8, conversionType: PrimitiveType.I8);
// Based on Table 4: Binary Comparison or Branch Operation
if (left.ResultType.IsFloatType() && right.ResultType.IsFloatType()) {
if (left.ResultType != right.ResultType) {
// make the implicit F4->F8 conversion explicit:
if (left.ResultType == StackType.F4) {
left = new Conv(left, PrimitiveType.R8, false, Sign.Signed);
} else if (right.ResultType == StackType.F4) {
right = new Conv(right, PrimitiveType.R8, false, Sign.Signed);
}
MakeExplicitConversion(StackType.F4, StackType.F8, PrimitiveType.R8);
}
if (un) {
// for floats, 'un' means 'unordered'
@ -1466,6 +1477,15 @@ namespace ICSharpCode.Decompiler.IL @@ -1466,6 +1477,15 @@ namespace ICSharpCode.Decompiler.IL
}
return new Comp(kind, Sign.None, left, right);
}
void MakeExplicitConversion(StackType sourceType, StackType targetType, PrimitiveType conversionType)
{
if (left.ResultType == sourceType && right.ResultType == targetType) {
left = new Conv(left, conversionType, false, Sign.None);
} else if (left.ResultType == targetType && right.ResultType == sourceType) {
right = new Conv(right, conversionType, false, Sign.None);
}
}
}
bool IsInvalidBranch(int target) => target < 0 || target >= reader.Length;

8
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -131,6 +131,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -131,6 +131,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
inst.InputType = StackType.I4;
inst.Left.ReplaceWith(new LdLen(StackType.I4, array) { ILRange = inst.Left.ILRange });
inst.Right = rightWithoutConv;
} else if (inst.Left is Conv conv && conv.TargetType == PrimitiveType.I && conv.Argument.ResultType == StackType.O) {
// C++/CLI sometimes uses this weird comparison with null:
context.Step("comp(conv o->i (ldloc obj) == conv i4->i <sign extend>(ldc.i4 0))", inst);
// -> comp(ldloc obj == ldnull)
inst.InputType = StackType.O;
inst.Left = conv.Argument;
inst.Right = new LdNull { ILRange = inst.Right.ILRange };
inst.Right.AddILRange(rightWithoutConv.ILRange);
}
}

Loading…
Cancel
Save