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
{ {
Get<S>().Field.ToString(); 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
if (thisArgBox.Argument is LdObj ldobj) { if (thisArgBox.Argument is LdObj ldobj) {
thisArg = ldobj.Target; thisArg = ldobj.Target;
} else { } else {
thisArg = new AddressOf(thisArgBox.Argument); thisArg = new AddressOf(thisArgBox.Argument, thisArgBox.Type);
} }
} }
target = expressionBuilder.TranslateTarget(thisArg, target = expressionBuilder.TranslateTarget(thisArg,

9
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2769,14 +2769,9 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitAddressOf(AddressOf inst, TranslationContext context) 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 // 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) return new DirectionExpression(FieldDirection.Ref, value)
.WithILInstruction(inst) .WithILInstruction(inst)
.WithRR(new ByReferenceResolveResult(value.ResolveResult, ReferenceKind.Ref)); .WithRR(new ByReferenceResolveResult(value.ResolveResult, ReferenceKind.Ref));

2
ICSharpCode.Decompiler/IL/ILReader.cs

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

17
ICSharpCode.Decompiler/IL/Instructions.cs

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

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -179,7 +179,7 @@
CustomClassName("StLoc"), HasVariableOperand("Store", generateCheckInvariant: false), CustomArguments(("value", null)), CustomClassName("StLoc"), HasVariableOperand("Store", generateCheckInvariant: false), CustomArguments(("value", null)),
ResultType("variable.StackType")), ResultType("variable.StackType")),
new OpCode("addressof", "Stores the value into an anonymous temporary variable, and returns the address of that variable.", 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.", 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")), 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.", 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
{ {
if (this is LdObj ldobj && ldobj.Target is LdFlda ldflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile) { if (this is LdObj ldobj && ldobj.Target is LdFlda ldflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile) {
field = ldflda.Field; 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; target = ldflda.Target;
} }
return true; return true;

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

@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
temp = ldfldaTarget; temp = ldfldaTarget;
range = range.Concat(temp.ILRanges); 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); context.Step($"ldobj(...(addressof(ldloca {v.Name}))) => ldobj(...(ldloca {v.Name}))", inst);
var replacement = new LdLoca(v).WithILRange(addressOfTarget); var replacement = new LdLoca(v).WithILRange(addressOfTarget);
foreach (var r in range) { foreach (var r in range) {

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

@ -226,7 +226,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (loadInst.OpCode == OpCode.LdLoca) { if (loadInst.OpCode == OpCode.LdLoca) {
// it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof' // it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof'
// to preserve the semantics of the compiler-generated temporary // 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 { } else {
loadInst.ReplaceWith(inlinedExpression); loadInst.ReplaceWith(inlinedExpression);
} }

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

@ -203,7 +203,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; // setter/adder/remover cannot be called with ?. syntax return false; // setter/adder/remover cannot be called with ?. syntax
} }
inst = call.Arguments[0]; 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; inst = arg;
} }
// ensure the access chain does not contain any 'nullable.unwrap' that aren't directly part of the chain // 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
if (target.ResultType == StackType.Ref) if (target.ResultType == StackType.Ref)
return target; return target;
else else
return new AddressOf(target); return new AddressOf(target, expectedType);
case StackType.O: case StackType.O:
if (targetType.IsReferenceType == false) { if (targetType.IsReferenceType == false) {
return new Box(target, targetType); return new Box(target, targetType);
@ -721,7 +721,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (member.DeclaringType.IsReferenceType == true) { if (member.DeclaringType.IsReferenceType == true) {
inst = new LdFlda(target, (IField)member); inst = new LdFlda(target, (IField)member);
} else { } 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) { 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
return false; return false;
var firstArg = callVirt.Arguments.FirstOrDefault(); var firstArg = callVirt.Arguments.FirstOrDefault();
if (!(firstArg.MatchUnboxAny(out var innerArg1, out var unboxType) && unboxType.IsKnownType(KnownTypeCode.IDisposable))) { 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 false;
return NullableLiftingTransform.MatchGetValueOrDefault(innerArg2, objVar) return NullableLiftingTransform.MatchGetValueOrDefault(innerArg2, objVar)
|| (innerArg2 is NullableUnwrap unwrap || (innerArg2 is NullableUnwrap unwrap

Loading…
Cancel
Save