diff --git a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs index 5338bb7c99..6a2cc4ed34 100644 --- a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs @@ -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 @@ -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) { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/MonoFixed.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/MonoFixed.cs new file mode 100644 index 0000000000..f3ad7c3892 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/MonoFixed.cs @@ -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'; + } + } + } + } +} diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/MonoFixed.il b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/MonoFixed.il new file mode 100644 index 0000000000..0159dccf0a --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/MonoFixed.il @@ -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 + } +} diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs b/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs index ee0e616981..ba698e97e2 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs @@ -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 @@ -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);