Browse Source

Ensure stack types for call arguments are correct.

pull/992/head
Daniel Grunwald 8 years ago
parent
commit
0b442e82bb
  1. 2
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs
  2. 10
      ICSharpCode.Decompiler/IL/ILReader.cs
  3. 27
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  4. 44
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

2
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs

@ -218,7 +218,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -218,7 +218,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public void MembersBuiltin()
{
ExpressionTrees.ToCode(ExpressionTrees.X(), () => 1.23m.ToString());
ExpressionTrees.ToCode(ExpressionTrees.X(), () => AttributeTargets.All.HasFlag((Enum)AttributeTargets.Assembly));
ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Enum)(object)AttributeTargets.All).HasFlag((Enum)AttributeTargets.Assembly));
ExpressionTrees.ToCode(ExpressionTrees.X(), () => "abc".Length == 3);
ExpressionTrees.ToCode(ExpressionTrees.X(), () => 'a'.CompareTo('b') < 0);
}

10
ICSharpCode.Decompiler/IL/ILReader.cs

@ -1130,15 +1130,18 @@ namespace ICSharpCode.Decompiler.IL @@ -1130,15 +1130,18 @@ namespace ICSharpCode.Decompiler.IL
return new StObj(target, value, type);
}
IType constrainedPrefix;
private ILInstruction DecodeConstrainedCall()
{
var typeRef = ReadAndDecodeTypeReference();
constrainedPrefix = ReadAndDecodeTypeReference();
var inst = DecodeInstruction();
var call = UnpackPush(inst) as CallInstruction;
if (call != null)
call.ConstrainedTo = typeRef;
Debug.Assert(call.ConstrainedTo == constrainedPrefix);
else
Warn("Ignored invalid 'constrained' prefix");
constrainedPrefix = null;
return inst;
}
@ -1196,7 +1199,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1196,7 +1199,7 @@ namespace ICSharpCode.Decompiler.IL
arguments[firstArgument + i] = Pop(method.Parameters[i].Type.GetStackType());
}
if (firstArgument == 1) {
arguments[0] = Pop();
arguments[0] = Pop(CallInstruction.ExpectedTypeForThisPointer(constrainedPrefix ?? method.DeclaringType));
}
switch (method.DeclaringType.Kind) {
case TypeKind.Array:
@ -1224,6 +1227,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1224,6 +1227,7 @@ namespace ICSharpCode.Decompiler.IL
default:
var call = CallInstruction.Create(opCode, method);
call.ILStackWasEmpty = currentStack.IsEmpty;
call.ConstrainedTo = constrainedPrefix;
call.Arguments.AddRange(arguments);
if (call.ResultType != StackType.Void)
return Push(call);

27
ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

@ -74,6 +74,33 @@ namespace ICSharpCode.Decompiler.IL @@ -74,6 +74,33 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>
/// Gets the expected stack type for passing the this pointer in a method call.
/// Returns StackType.O for reference types (this pointer passed as object reference),
/// and StackType.Ref for type parameters and value types (this pointer passed as managed reference).
/// </summary>
internal static StackType ExpectedTypeForThisPointer(IType type)
{
if (type.Kind == TypeKind.TypeParameter)
return StackType.Ref;
return type.IsReferenceType == true ? StackType.O : StackType.Ref;
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
int firstArgument = (OpCode != OpCode.NewObj && !Method.IsStatic) ? 1 : 0;
Debug.Assert(Method.Parameters.Count + firstArgument == Arguments.Count);
if (firstArgument == 1) {
Debug.Assert(Arguments[0].ResultType == ExpectedTypeForThisPointer(ConstrainedTo ?? Method.DeclaringType),
$"Stack type mismatch in 'this' argument in call to {Method.Name}()");
}
for (int i = 0; i < Method.Parameters.Count; ++i) {
Debug.Assert(Arguments[firstArgument + i].ResultType == Method.Parameters[i].Type.GetStackType(),
$"Stack type mismatch in parameter {i} in call to {Method.Name}()");
}
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);

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

@ -437,6 +437,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -437,6 +437,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
IList<ILInstruction> arguments = null;
ILInstruction target = null;
IType targetType = null;
if (MatchGetMethodFromHandle(invocation.Arguments[0], out var member)) {
// static method
if (invocation.Arguments.Count != 2 || !MatchArgumentList(invocation.Arguments[1], out arguments)) {
@ -447,13 +448,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -447,13 +448,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
arguments = new List<ILInstruction>(invocation.Arguments.Skip(2));
}
if (!invocation.Arguments[0].MatchLdNull()) {
IType targetType;
(target, targetType) = ConvertInstruction(invocation.Arguments[0]);
if (target == null)
return (null, SpecialType.UnknownType);
if (targetType.IsReferenceType == false) {
target = new AddressOf(target);
}
}
}
if (arguments == null)
@ -473,17 +470,37 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -473,17 +470,37 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}, delegateType);
}
CallInstruction call;
if (method.IsAbstract || method.IsVirtual || method.IsOverridable) {
if (method.IsAbstract || method.IsVirtual || method.IsOverride) {
call = new CallVirt(method);
} else {
call = new Call(method);
}
if (target != null)
call.Arguments.Add(target);
if (target != null) {
call.Arguments.Add(PrepareCallTarget(method.DeclaringType, target, targetType));
}
call.Arguments.AddRange(arguments);
return (call, method.ReturnType);
}
ILInstruction PrepareCallTarget(IType expectedType, ILInstruction target, IType targetType)
{
switch (CallInstruction.ExpectedTypeForThisPointer(expectedType)) {
case StackType.Ref:
if (target.ResultType == StackType.Ref)
return target;
else
return new AddressOf(target);
case StackType.O:
if (targetType.IsReferenceType == false) {
return new Box(target, targetType);
} else {
return target;
}
default:
return target;
}
}
(ILInstruction, IType) ConvertCast(CallInstruction invocation, bool isChecked)
{
if (invocation.Arguments.Count < 2)
@ -651,7 +668,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -651,7 +668,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
arguments[i] = arg;
}
var call = new Call(invokeMethod);
var call = new CallVirt(invokeMethod);
call.Arguments.Add(target);
call.Arguments.AddRange(arguments);
return (call, invokeMethod.ReturnType);
@ -879,8 +896,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -879,8 +896,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (invocation.Arguments.Count < 2)
return (null, SpecialType.UnknownType);
ILInstruction target = null;
IType targetType = null;
if (!invocation.Arguments[0].MatchLdNull()) {
target = ConvertInstruction(invocation.Arguments[0]).Item1;
(target, targetType) = ConvertInstruction(invocation.Arguments[0]);
if (target == null)
return (null, SpecialType.UnknownType);
}
@ -896,15 +914,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -896,15 +914,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
}
}
if (target != null) {
arguments.Insert(0, target);
}
CallInstruction call;
if (member.IsAbstract || member.IsVirtual || member.IsOverridable) {
if (member.IsAbstract || member.IsVirtual || member.IsOverride) {
call = new CallVirt((IMethod)member);
} else {
call = new Call((IMethod)member);
}
if (target != null) {
call.Arguments.Add(PrepareCallTarget(member.DeclaringType, target, targetType));
}
call.Arguments.AddRange(arguments);
return (call, member.ReturnType);
}

Loading…
Cancel
Save