Browse Source

#2158: Fix decompilation of arithmetic on managed pointers after ConversionKind.StartGCTracking.

pull/2176/head
Daniel Grunwald 5 years ago
parent
commit
9381be2280
  1. 4
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs
  2. 35
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 2
      ICSharpCode.Decompiler/IL/PointerArithmeticOffset.cs

4
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs

@ -65,14 +65,14 @@ internal sealed class ExtraUnsafeTests
{ {
if (*ptr <= 0) if (*ptr <= 0)
{ {
ptr[4 * 0] = 1; Unsafe.AddByteOffset(ref *ptr, 4 * 0) = 1;
return; return;
} }
reference = ref *ptr; reference = ref *ptr;
} }
fixed (int* ptr = &b[reference]) fixed (int* ptr = &b[reference])
{ {
ptr[4 * 0] = 1; Unsafe.AddByteOffset(ref *ptr, 4 * 0) = 1;
} }
} }

35
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1235,12 +1235,17 @@ namespace ICSharpCode.Decompiler.CSharp
new NamedArgumentExpression("origin", right.Expression) new NamedArgumentExpression("origin", right.Expression)
}, compilation.FindType(KnownTypeCode.IntPtr), inst); }, compilation.FindType(KnownTypeCode.IntPtr), inst);
} }
if (inst.LeftInputType == StackType.Ref && inst.RightInputType.IsIntegerType() if (inst.LeftInputType == StackType.Ref && inst.RightInputType.IsIntegerType())
&& left.Type is ByReferenceType brt)
{ {
// ref [+-] int // ref [+-] int
var brt = left.Type as ByReferenceType;
if (brt == null)
{
brt = GetReferenceType(left.Type);
left = left.ConvertTo(brt, this);
}
string name = (inst.Operator == BinaryNumericOperator.Sub ? "Subtract" : "Add"); string name = (inst.Operator == BinaryNumericOperator.Sub ? "Subtract" : "Add");
ILInstruction offsetInst = PointerArithmeticOffset.Detect(inst.Right, brt.ElementType, inst.CheckForOverflow); ILInstruction offsetInst = PointerArithmeticOffset.Detect(inst.Right, brt?.ElementType, inst.CheckForOverflow);
if (offsetInst != null) if (offsetInst != null)
{ {
if (settings.FixedBuffers && inst.Operator == BinaryNumericOperator.Add && inst.Left is LdFlda ldFlda if (settings.FixedBuffers && inst.Operator == BinaryNumericOperator.Add && inst.Left is LdFlda ldFlda
@ -1264,11 +1269,17 @@ namespace ICSharpCode.Decompiler.CSharp
return CallUnsafeIntrinsic(name + "ByteOffset", new[] { left.Expression, right.Expression }, brt, inst); return CallUnsafeIntrinsic(name + "ByteOffset", new[] { left.Expression, right.Expression }, brt, inst);
} }
} }
brt = right.Type as ByReferenceType;
if (inst.LeftInputType == StackType.I && inst.RightInputType == StackType.Ref && brt != null if (inst.LeftInputType == StackType.I && inst.RightInputType == StackType.Ref
&& inst.Operator == BinaryNumericOperator.Add) && inst.Operator == BinaryNumericOperator.Add)
{ {
// int + ref // int + ref
var brt = right.Type as ByReferenceType;
if (brt == null)
{
brt = GetReferenceType(right.Type);
right = right.ConvertTo(brt, this);
}
ILInstruction offsetInst = PointerArithmeticOffset.Detect(inst.Left, brt.ElementType, inst.CheckForOverflow); ILInstruction offsetInst = PointerArithmeticOffset.Detect(inst.Left, brt.ElementType, inst.CheckForOverflow);
if (offsetInst != null) if (offsetInst != null)
{ {
@ -1286,6 +1297,18 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
return null; return null;
ByReferenceType GetReferenceType(IType type)
{
if (type is PointerType pt)
{
return new ByReferenceType(pt.ElementType);
}
else
{
return new ByReferenceType(compilation.FindType(KnownTypeCode.Byte));
}
}
} }
internal TranslatedExpression CallUnsafeIntrinsic(string name, Expression[] arguments, IType returnType, ILInstruction inst = null, IEnumerable<IType> typeArguments = null) internal TranslatedExpression CallUnsafeIntrinsic(string name, Expression[] arguments, IType returnType, ILInstruction inst = null, IEnumerable<IType> typeArguments = null)
@ -1429,7 +1452,7 @@ namespace ICSharpCode.Decompiler.CSharp
var left = Translate(inst.Left, op.IsBitwise() ? context.TypeHint : null); var left = Translate(inst.Left, op.IsBitwise() ? context.TypeHint : null);
var right = Translate(inst.Right, op.IsBitwise() ? context.TypeHint : null); var right = Translate(inst.Right, op.IsBitwise() ? context.TypeHint : null);
if (left.Type.Kind == TypeKind.ByReference || right.Type.Kind == TypeKind.ByReference) if (inst.UnderlyingResultType == StackType.Ref)
{ {
var ptrResult = HandleManagedPointerArithmetic(inst, left, right); var ptrResult = HandleManagedPointerArithmetic(inst, left, right);
if (ptrResult != null) if (ptrResult != null)

2
ICSharpCode.Decompiler/IL/PointerArithmeticOffset.cs

@ -39,6 +39,8 @@ namespace ICSharpCode.Decompiler.IL
bool checkForOverflow, bool checkForOverflow,
bool unwrapZeroExtension = false) bool unwrapZeroExtension = false)
{ {
if (pointerElementType == null)
return null;
if (byteOffsetInst is Conv conv && conv.InputType == StackType.I8 && conv.ResultType == StackType.I) if (byteOffsetInst is Conv conv && conv.InputType == StackType.I8 && conv.ResultType == StackType.I)
{ {
byteOffsetInst = conv.Argument; byteOffsetInst = conv.Argument;

Loading…
Cancel
Save