Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MCS 2.6.4 pinned region with string variable #3015

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
Expand Down Expand Up @@ -269,6 +269,12 @@ public async Task EmptyBodies()
await Run();
}

[Test]
public async Task MonoFixed()
{
await Run();
}

async Task Run([CallerMemberName] string testName = null, DecompilerSettings settings = null,
AssemblerOptions assemblerOptions = AssemblerOptions.Library)
{
Expand Down
20 changes: 20 additions & 0 deletions ICSharpCode.Decompiler.Tests/TestCases/ILPretty/MonoFixed.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

public class MonoFixed
{
public unsafe void FixMultipleStrings(string text)
{
fixed (char* ptr = text)
{
fixed (char* ptr2 = Environment.UserName)
{
fixed (char* ptr3 = text)
{
*ptr = 'c';
*ptr2 = 'd';
*ptr3 = 'e';
}
}
}
}
}
74 changes: 74 additions & 0 deletions ICSharpCode.Decompiler.Tests/TestCases/ILPretty/MonoFixed.il
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 4:0:0:0
}
.assembly MonoFixed
{
.ver 1:0:0:0
}

.module MonoFixed.exe
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WindowsCui
.corflags 0x00000001 // ILOnly
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = (
01 00 00 00
)

.class public auto ansi beforefieldinit MonoFixed
extends [mscorlib]System.Object
{
.method public hidebysig instance void FixMultipleStrings (string text) cil managed
{
.maxstack 7
.locals init (
[0] char* pinned,
[1] char* pinned,
[2] char* pinned,
[3] string pinned,
[4] string pinned,
[5] string pinned
)

IL_0000: ldarg.1
IL_0001: stloc.3
IL_0002: ldloc.3
IL_0003: conv.i
IL_0004: call int32 [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
IL_0009: add
IL_000a: stloc.0
IL_000b: call string [mscorlib]System.Environment::get_UserName()
IL_0010: stloc.s 4
IL_0012: ldloc.s 4
IL_0014: conv.i
IL_0015: call int32 [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
IL_001a: add
IL_001b: stloc.1
IL_001c: ldarg.1
IL_001d: stloc.s 5
IL_001f: ldloc.s 5
IL_0021: conv.i
IL_0022: call int32 [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::get_OffsetToStringData()
IL_0027: add
IL_0028: stloc.2
IL_0029: ldloc.0
IL_002a: ldc.i4.s 99
IL_002c: stind.i2
IL_002d: ldloc.1
IL_002e: ldc.i4.s 100
IL_0030: stind.i2
IL_0031: ldloc.2
IL_0032: ldc.i4.s 101
IL_0034: stind.i2
IL_0035: ldnull
IL_0036: stloc.3
IL_0037: ldnull
IL_0038: stloc.s 4
IL_003a: ldnull
IL_003b: stloc.s 5
IL_003d: ret
}
}
46 changes: 31 additions & 15 deletions ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2016 Daniel Grunwald
// Copyright (c) 2016 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
Expand Down Expand Up @@ -878,28 +878,44 @@ void HandleStringToPointer(PinnedRegion pinnedRegion)
}
return;
}
if (body.EntryPoint.Instructions.Count != 3)
{
return;
}

if (nativeVar.Type.GetStackType() != StackType.I)
return;
if (!initInst.UnwrapConv(ConversionKind.StopGCTracking).MatchLdLoc(pinnedRegion.Variable))
return;
if (!IsBranchOnNull(body.EntryPoint.Instructions[1], nativeVar, out Block targetBlock))
return;
if (!body.EntryPoint.Instructions[2].MatchBranch(out Block adjustOffsetToStringData))
return;
if (!(adjustOffsetToStringData.Parent == body && adjustOffsetToStringData.IncomingEdgeCount == 1
&& IsOffsetToStringDataBlock(adjustOffsetToStringData, nativeVar, targetBlock)))

Block targetBlock;
Block adjustOffsetToStringData = null;
if (body.EntryPoint.Instructions.Count == 2)
{
if (!initInst.MatchBinaryNumericInstruction(BinaryNumericOperator.Add, out ILInstruction left, out ILInstruction right))
return;
if (!left.UnwrapConv(ConversionKind.StopGCTracking).MatchLdLoc(pinnedRegion.Variable))
return;
if (!IsOffsetToStringDataCall(right))
return;
if (!body.EntryPoint.Instructions[1].MatchBranch(out targetBlock))
return;
}
else if (body.EntryPoint.Instructions.Count == 3)
{
if (!initInst.UnwrapConv(ConversionKind.StopGCTracking).MatchLdLoc(pinnedRegion.Variable))
return;
if (!IsBranchOnNull(body.EntryPoint.Instructions[1], nativeVar, out targetBlock))
return;
if (!body.EntryPoint.Instructions[2].MatchBranch(out adjustOffsetToStringData))
return;
if (!(adjustOffsetToStringData.Parent == body && adjustOffsetToStringData.IncomingEdgeCount == 1
&& IsOffsetToStringDataBlock(adjustOffsetToStringData, nativeVar, targetBlock)))
return;
}
else
return;

context.Step("Handle pinned string (with adjustOffsetToStringData)", pinnedRegion);
if (targetBlock.Parent == body)
{
// remove old entry point
body.Blocks.RemoveAt(0);
body.Blocks.RemoveAt(adjustOffsetToStringData.ChildIndex);
if (adjustOffsetToStringData is not null)
body.Blocks.RemoveAt(adjustOffsetToStringData.ChildIndex);
// make targetBlock the new entry point
body.Blocks.RemoveAt(targetBlock.ChildIndex);
body.Blocks.Insert(0, targetBlock);
Expand Down