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

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

@ -209,8 +209,19 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -209,8 +209,19 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return false;
if (!block.Instructions[0].MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst))
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;
}
if (!array.MatchLdLoc(v))
return false;
if (!trueInst.MatchBranch(out Block notNullAndNotEmptyBlock))

40
ICSharpCode.Decompiler/IL/Instructions.cs

@ -3021,8 +3021,10 @@ namespace ICSharpCode.Decompiler.IL @@ -3021,8 +3021,10 @@ namespace ICSharpCode.Decompiler.IL
{
WriteILRange(output, options);
output.Write(OpCode);
output.Write(' ');
method.WriteTo(output);
if (method != null) {
output.Write(' ');
method.WriteTo(output);
}
}
public override void AcceptVisitor(ILVisitor visitor)
{
@ -3039,7 +3041,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3039,7 +3041,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
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 @@ -3069,8 +3071,10 @@ namespace ICSharpCode.Decompiler.IL
{
WriteILRange(output, options);
output.Write(OpCode);
output.Write(' ');
method.WriteTo(output);
if (method != null) {
output.Write(' ');
method.WriteTo(output);
}
output.Write('(');
Argument.WriteTo(output, options);
output.Write(')');
@ -3090,7 +3094,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3090,7 +3094,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
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 @@ -3129,8 +3133,10 @@ namespace ICSharpCode.Decompiler.IL
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
output.Write(' ');
method.WriteTo(output);
if (method != null) {
output.Write(' ');
method.WriteTo(output);
}
output.Write('(');
Argument.WriteTo(output, options);
output.Write(')');
@ -3150,7 +3156,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3150,7 +3156,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
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 @@ -4835,8 +4841,10 @@ namespace ICSharpCode.Decompiler.IL
{
WriteILRange(output, options);
output.Write(OpCode);
output.Write(' ');
method.WriteTo(output);
if (method != null) {
output.Write(' ');
method.WriteTo(output);
}
output.Write('(');
this.argument.WriteTo(output, options);
output.Write(')');
@ -4856,7 +4864,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4856,7 +4864,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
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)
{
@ -5074,8 +5082,10 @@ namespace ICSharpCode.Decompiler.IL @@ -5074,8 +5082,10 @@ namespace ICSharpCode.Decompiler.IL
{
WriteILRange(output, options);
output.Write(OpCode);
output.Write(' ');
method.WriteTo(output);
if (method != null) {
output.Write(' ');
method.WriteTo(output);
}
output.Write('(');
this.left.WriteTo(output, options);
output.Write(", ");
@ -5097,7 +5107,7 @@ namespace ICSharpCode.Decompiler.IL @@ -5097,7 +5107,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
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() @@ -1081,12 +1081,14 @@ protected override void Disconnected()
opCode.Members.Add("readonly IMethod method;");
opCode.ConstructorBody.Add("this.method = 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
+ "public IMethod Method { get { return method; } }");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("method.WriteTo(output);");
opCode.WriteOperand.Add("if (method != null) {");
opCode.WriteOperand.Add("\toutput.Write(' ');");
opCode.WriteOperand.Add("\tmethod.WriteTo(output);");
opCode.WriteOperand.Add("}");
opCode.Interfaces.Add("IInstructionWithMethodOperand");
};

Loading…
Cancel
Save