Browse Source

Fix #1853: Detect pinning of multi-dimensional array

pull/1880/head
Daniel Grunwald 6 years ago
parent
commit
bbb2397083
  1. 11
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  2. 13
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  3. 40
      ICSharpCode.Decompiler/IL/Instructions.cs
  4. 8
      ICSharpCode.Decompiler/IL/Instructions.tt

11
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs

@ -364,15 +364,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return ptr->ToString(); return ptr->ToString();
} }
public unsafe void FixedMultiDimArray(int[,] arr)
{
fixed (int* ptr = arr) {
UsePointer(ptr);
}
}
#if CS73 #if CS73
public unsafe void PinSpan(Span<int> span) public unsafe void FixedSpan(Span<int> span)
{ {
fixed (int* ptr = span) { fixed (int* ptr = span) {
UsePointer(ptr); UsePointer(ptr);
} }
} }
//public unsafe void CustomPinReferenceType(CustomPinnable mem) //public unsafe void FixedCustomReferenceType(CustomPinnable mem)
//{ //{
// fixed (int* ptr = mem) { // fixed (int* ptr = mem) {
// UsePointer(ptr); // UsePointer(ptr);

13
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -209,8 +209,19 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return false; return false;
if (!block.Instructions[0].MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst)) if (!block.Instructions[0].MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst))
return false; return false;
if (!condition.UnwrapConv(ConversionKind.Truncate).MatchLdLen(StackType.I, out ILInstruction array)) condition = condition.UnwrapConv(ConversionKind.Truncate);
if (condition.MatchLdLen(StackType.I, out ILInstruction array)) {
// OK
} else if (condition is CallInstruction call && call.Method.Name == "get_Length") {
// Used instead of ldlen for multi-dimensional arrays
if (!call.Method.DeclaringType.IsKnownType(KnownTypeCode.Array))
return false;
if (call.Arguments.Count != 1)
return false;
array = call.Arguments[0];
} else {
return false; return false;
}
if (!array.MatchLdLoc(v)) if (!array.MatchLdLoc(v))
return false; return false;
if (!trueInst.MatchBranch(out Block notNullAndNotEmptyBlock)) if (!trueInst.MatchBranch(out Block notNullAndNotEmptyBlock))

40
ICSharpCode.Decompiler/IL/Instructions.cs

@ -3021,8 +3021,10 @@ namespace ICSharpCode.Decompiler.IL
{ {
WriteILRange(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); if (method != null) {
method.WriteTo(output); output.Write(' ');
method.WriteTo(output);
}
} }
public override void AcceptVisitor(ILVisitor visitor) public override void AcceptVisitor(ILVisitor visitor)
{ {
@ -3039,7 +3041,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 LdFtn; var o = other as LdFtn;
return o != null && method.Equals(o.method); return o != null && object.Equals(method, o.method);
} }
} }
} }
@ -3069,8 +3071,10 @@ namespace ICSharpCode.Decompiler.IL
{ {
WriteILRange(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); if (method != null) {
method.WriteTo(output); output.Write(' ');
method.WriteTo(output);
}
output.Write('('); output.Write('(');
Argument.WriteTo(output, options); Argument.WriteTo(output, options);
output.Write(')'); output.Write(')');
@ -3090,7 +3094,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 LdVirtFtn; var o = other as LdVirtFtn;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && method.Equals(o.method); return o != null && this.Argument.PerformMatch(o.Argument, ref match) && object.Equals(method, o.method);
} }
} }
} }
@ -3129,8 +3133,10 @@ namespace ICSharpCode.Decompiler.IL
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
output.Write(' '); if (method != null) {
method.WriteTo(output); output.Write(' ');
method.WriteTo(output);
}
output.Write('('); output.Write('(');
Argument.WriteTo(output, options); Argument.WriteTo(output, options);
output.Write(')'); output.Write(')');
@ -3150,7 +3156,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 LdVirtDelegate; var o = other as LdVirtDelegate;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type) && method.Equals(o.method); return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type) && object.Equals(method, o.method);
} }
} }
} }
@ -4835,8 +4841,10 @@ namespace ICSharpCode.Decompiler.IL
{ {
WriteILRange(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); if (method != null) {
method.WriteTo(output); output.Write(' ');
method.WriteTo(output);
}
output.Write('('); output.Write('(');
this.argument.WriteTo(output, options); this.argument.WriteTo(output, options);
output.Write(')'); output.Write(')');
@ -4856,7 +4864,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 GetPinnableReference; var o = other as GetPinnableReference;
return o != null && this.argument.PerformMatch(o.argument, ref match) && method.Equals(o.method); return o != null && this.argument.PerformMatch(o.argument, ref match) && object.Equals(method, o.method);
} }
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase)
{ {
@ -5074,8 +5082,10 @@ namespace ICSharpCode.Decompiler.IL
{ {
WriteILRange(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); if (method != null) {
method.WriteTo(output); output.Write(' ');
method.WriteTo(output);
}
output.Write('('); output.Write('(');
this.left.WriteTo(output, options); this.left.WriteTo(output, options);
output.Write(", "); output.Write(", ");
@ -5097,7 +5107,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 UserDefinedLogicOperator; var o = other as UserDefinedLogicOperator;
return o != null && method.Equals(o.method) && this.left.PerformMatch(o.left, ref match) && this.right.PerformMatch(o.right, ref match); return o != null && object.Equals(method, o.method) && this.left.PerformMatch(o.left, ref match) && this.right.PerformMatch(o.right, ref match);
} }
} }
} }

8
ICSharpCode.Decompiler/IL/Instructions.tt

@ -1081,12 +1081,14 @@ protected override void Disconnected()
opCode.Members.Add("readonly IMethod method;"); opCode.Members.Add("readonly IMethod method;");
opCode.ConstructorBody.Add("this.method = method;"); opCode.ConstructorBody.Add("this.method = method;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IMethod", Name = "method", FieldName = "Method" }); opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IMethod", Name = "method", FieldName = "Method" });
opCode.PerformMatchConditions.Add("method.Equals(o.method)"); opCode.PerformMatchConditions.Add("object.Equals(method, o.method)");
opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine opCode.Members.Add("/// <summary>Returns the method operand.</summary>" + Environment.NewLine
+ "public IMethod Method { get { return method; } }"); + "public IMethod Method { get { return method; } }");
opCode.GenerateWriteTo = true; opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');"); opCode.WriteOperand.Add("if (method != null) {");
opCode.WriteOperand.Add("method.WriteTo(output);"); opCode.WriteOperand.Add("\toutput.Write(' ');");
opCode.WriteOperand.Add("\tmethod.WriteTo(output);");
opCode.WriteOperand.Add("}");
opCode.Interfaces.Add("IInstructionWithMethodOperand"); opCode.Interfaces.Add("IInstructionWithMethodOperand");
}; };

Loading…
Cancel
Save