Browse Source

Fix #1655: Incorrect pointer cast when calling method on integer constant

pull/1686/head
Daniel Grunwald 6 years ago
parent
commit
57b725df79
  1. 5
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  3. 9
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  4. 2
      ICSharpCode.Decompiler/IL/ILReader.cs
  5. 17
      ICSharpCode.Decompiler/IL/Instructions.cs
  6. 2
      ICSharpCode.Decompiler/IL/Instructions.tt
  7. 2
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  8. 2
      ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs
  9. 3
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  10. 2
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  11. 4
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs
  12. 2
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

5
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs

@ -273,5 +273,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -273,5 +273,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
Get<S>().Field.ToString();
}
public static string CallOnIntegerConstant()
{
return ulong.MaxValue.ToString();
}
}
}

2
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1294,7 +1294,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1294,7 +1294,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (thisArgBox.Argument is LdObj ldobj) {
thisArg = ldobj.Target;
} else {
thisArg = new AddressOf(thisArgBox.Argument);
thisArg = new AddressOf(thisArgBox.Argument, thisArgBox.Type);
}
}
target = expressionBuilder.TranslateTarget(thisArg,

9
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2769,14 +2769,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2769,14 +2769,9 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitAddressOf(AddressOf inst, TranslationContext context)
{
IType targetTypeHint = null;
if (context.TypeHint is ByReferenceType brt) {
targetTypeHint = brt.ElementType;
} else if (context.TypeHint is PointerType pt) {
targetTypeHint = pt.ElementType;
}
// HACK: this is only correct if the argument is an R-value; otherwise we're missing the copy to the temporary
var value = Translate(inst.Value, targetTypeHint);
var value = Translate(inst.Value, inst.Type);
value = value.ConvertTo(inst.Type, this);
return new DirectionExpression(FieldDirection.Ref, value)
.WithILInstruction(inst)
.WithRR(new ByReferenceResolveResult(value.ResolveResult, ReferenceKind.Ref));

2
ICSharpCode.Decompiler/IL/ILReader.cs

@ -1199,7 +1199,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1199,7 +1199,7 @@ namespace ICSharpCode.Decompiler.IL
case false:
// field of value type: ldfld can handle temporaries
if (PeekStackType() == StackType.O || PeekStackType() == StackType.Unknown)
return new AddressOf(Pop());
return new AddressOf(Pop(), field.DeclaringType);
else
return PopPointer();
default:

17
ICSharpCode.Decompiler/IL/Instructions.cs

@ -2529,9 +2529,10 @@ namespace ICSharpCode.Decompiler.IL @@ -2529,9 +2529,10 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Stores the value into an anonymous temporary variable, and returns the address of that variable.</summary>
public sealed partial class AddressOf : ILInstruction
{
public AddressOf(ILInstruction value) : base(OpCode.AddressOf)
public AddressOf(ILInstruction value, IType type) : base(OpCode.AddressOf)
{
this.Value = value;
this.type = type;
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
@ -2581,6 +2582,12 @@ namespace ICSharpCode.Decompiler.IL @@ -2581,6 +2582,12 @@ namespace ICSharpCode.Decompiler.IL
return clone;
}
public override StackType ResultType { get { return StackType.Ref; } }
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
protected override InstructionFlags ComputeFlags()
{
return value.Flags;
@ -2594,6 +2601,8 @@ namespace ICSharpCode.Decompiler.IL @@ -2594,6 +2601,8 @@ namespace ICSharpCode.Decompiler.IL
{
WriteILRange(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
output.Write('(');
this.value.WriteTo(output, options);
output.Write(')');
@ -2613,7 +2622,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2613,7 +2622,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as AddressOf;
return o != null && this.value.PerformMatch(o.value, ref match);
return o != null && this.value.PerformMatch(o.value, ref match) && type.Equals(o.type);
}
}
}
@ -7805,14 +7814,16 @@ namespace ICSharpCode.Decompiler.IL @@ -7805,14 +7814,16 @@ namespace ICSharpCode.Decompiler.IL
value = default(ILInstruction);
return false;
}
public bool MatchAddressOf(out ILInstruction value)
public bool MatchAddressOf(out ILInstruction value, out IType type)
{
var inst = this as AddressOf;
if (inst != null) {
value = inst.Value;
type = inst.Type;
return true;
}
value = default(ILInstruction);
type = default(IType);
return false;
}
public bool MatchThreeValuedBoolAnd(out ILInstruction left, out ILInstruction right)

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -179,7 +179,7 @@ @@ -179,7 +179,7 @@
CustomClassName("StLoc"), HasVariableOperand("Store", generateCheckInvariant: false), CustomArguments(("value", null)),
ResultType("variable.StackType")),
new OpCode("addressof", "Stores the value into an anonymous temporary variable, and returns the address of that variable.",
CustomClassName("AddressOf"), CustomArguments(("value", null)), ResultType("Ref")),
CustomClassName("AddressOf"), CustomArguments(("value", null)), ResultType("Ref"), HasTypeOperand),
new OpCode("3vl.bool.and", "Three valued logic and. Inputs are of type bool? or I4, output is of type bool?. Unlike logic.and(), does not have short-circuiting behavior.",
CustomClassName("ThreeValuedBoolAnd"), Binary, ResultType("O")),
new OpCode("3vl.bool.or", "Three valued logic or. Inputs are of type bool? or I4, output is of type bool?. Unlike logic.or(), does not have short-circuiting behavior.",

2
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -418,7 +418,7 @@ namespace ICSharpCode.Decompiler.IL @@ -418,7 +418,7 @@ namespace ICSharpCode.Decompiler.IL
{
if (this is LdObj ldobj && ldobj.Target is LdFlda ldflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile) {
field = ldflda.Field;
if (field.DeclaringType.IsReferenceType == true || !ldflda.Target.MatchAddressOf(out target)) {
if (field.DeclaringType.IsReferenceType == true || !ldflda.Target.MatchAddressOf(out target, out _)) {
target = ldflda.Target;
}
return true;

2
ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs

@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
temp = ldfldaTarget;
range = range.Concat(temp.ILRanges);
}
if (temp.MatchAddressOf(out var addressOfTarget) && addressOfTarget.MatchLdLoc(out var v)) {
if (temp.MatchAddressOf(out var addressOfTarget, out _) && addressOfTarget.MatchLdLoc(out var v)) {
context.Step($"ldobj(...(addressof(ldloca {v.Name}))) => ldobj(...(ldloca {v.Name}))", inst);
var replacement = new LdLoca(v).WithILRange(addressOfTarget);
foreach (var r in range) {

3
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -226,7 +226,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -226,7 +226,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (loadInst.OpCode == OpCode.LdLoca) {
// it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof'
// to preserve the semantics of the compiler-generated temporary
loadInst.ReplaceWith(new AddressOf(inlinedExpression));
Debug.Assert(((LdLoca)loadInst).Variable == v);
loadInst.ReplaceWith(new AddressOf(inlinedExpression, v.Type));
} else {
loadInst.ReplaceWith(inlinedExpression);
}

2
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -203,7 +203,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -203,7 +203,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; // setter/adder/remover cannot be called with ?. syntax
}
inst = call.Arguments[0];
if ((call.ConstrainedTo ?? call.Method.DeclaringType).IsReferenceType == false && inst.MatchAddressOf(out var arg)) {
if ((call.ConstrainedTo ?? call.Method.DeclaringType).IsReferenceType == false && inst.MatchAddressOf(out var arg, out _)) {
inst = arg;
}
// ensure the access chain does not contain any 'nullable.unwrap' that aren't directly part of the chain

4
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -541,7 +541,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -541,7 +541,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (target.ResultType == StackType.Ref)
return target;
else
return new AddressOf(target);
return new AddressOf(target, expectedType);
case StackType.O:
if (targetType.IsReferenceType == false) {
return new Box(target, targetType);
@ -721,7 +721,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -721,7 +721,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (member.DeclaringType.IsReferenceType == true) {
inst = new LdFlda(target, (IField)member);
} else {
inst = new LdFlda(new AddressOf(target), (IField)member);
inst = new LdFlda(new AddressOf(target, member.DeclaringType), (IField)member);
}
}
if (typeHint.SkipModifiers() is ByReferenceType brt && !member.ReturnType.IsByRefLike) {

2
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -224,7 +224,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -224,7 +224,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
var firstArg = callVirt.Arguments.FirstOrDefault();
if (!(firstArg.MatchUnboxAny(out var innerArg1, out var unboxType) && unboxType.IsKnownType(KnownTypeCode.IDisposable))) {
if (!firstArg.MatchAddressOf(out var innerArg2))
if (!firstArg.MatchAddressOf(out var innerArg2, out _))
return false;
return NullableLiftingTransform.MatchGetValueOrDefault(innerArg2, objVar)
|| (innerArg2 is NullableUnwrap unwrap

Loading…
Cancel
Save