From 35c405b9730378d94bb4af2092a4f0db95e49898 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 25 Jun 2020 00:14:30 +0200 Subject: [PATCH] Translate the initializer of a `fixed` statement as managed reference and only apply the ref-to-pointer conversion at the end. This way we create compilable code when the pinned variable type does not match the initializer type. --- .../TestCases/ILPretty/Unsafe.cs | 10 +++++++ .../TestCases/ILPretty/Unsafe.il | 30 +++++++++++++++++++ .../CSharp/StatementBuilder.cs | 14 ++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs index 222c2bfc9..a5a2635ba 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.cs @@ -1,5 +1,6 @@ using System; using System.Reflection; +using System.Runtime.CompilerServices; [assembly: AssemblyFileVersion("4.0.0.0")] [assembly: AssemblyInformationalVersion("4.0.0.0")] @@ -12,6 +13,15 @@ using System.Reflection; [assembly: AssemblyProduct("Microsoft® .NET Framework")] [assembly: CLSCompliant(false)] +internal sealed class ExtraUnsafeTests +{ + public unsafe static void PinWithTypeMismatch(ref uint managedPtr) + { + fixed (ushort* ptr = &Unsafe.As(ref managedPtr)) { + } + } +} + namespace System.Runtime.CompilerServices { public static class Unsafe diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.il b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.il index 7ea5061df..e154e513c 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Unsafe.il @@ -437,3 +437,33 @@ } // end of class System.Runtime.CompilerServices.IsReadOnlyAttribute #endif + +.class private auto ansi sealed beforefieldinit ExtraUnsafeTests + extends [CORE_ASSEMBLY]System.Object +{ + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + .maxstack 1 + ldarg.0 + call instance void [CORE_ASSEMBLY]System.Object::.ctor() + ret + } // end of method ExtraUnsafeTests::.ctor + + .method public hidebysig static void PinWithTypeMismatch(uint32& managedPtr) + { + .maxstack 8 + .locals ( + [0] uint16& pinned + ) + // Pin: + ldarg.0 + stloc.0 + + // Unpin: + ldc.i4 0 + stloc.0 + + ret + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 52ffa500e..c84b2850b 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -832,7 +832,19 @@ namespace ICSharpCode.Decompiler.CSharp initExpr = exprBuilder.Translate(gpr.Argument); } } else { - initExpr = exprBuilder.Translate(inst.Init, typeHint: inst.Variable.Type).ConvertTo(inst.Variable.Type, exprBuilder); + IType refType = inst.Variable.Type; + if (refType is PointerType pointerType) { + refType = new ByReferenceType(pointerType.ElementType); + } + initExpr = exprBuilder.Translate(inst.Init, typeHint: refType).ConvertTo(refType, exprBuilder); + if (initExpr is DirectionExpression dirExpr) { + if (dirExpr.Expression is UnaryOperatorExpression uoe && uoe.Operator == UnaryOperatorType.Dereference) { + initExpr = uoe.Expression.Detach(); + } else { + initExpr = new UnaryOperatorExpression(UnaryOperatorType.AddressOf, dirExpr.Expression.Detach()) + .WithRR(new ResolveResult(inst.Variable.Type)); + } + } } fixedStmt.Variables.Add(new VariableInitializer(inst.Variable.Name, initExpr).WithILVariable(inst.Variable)); fixedStmt.EmbeddedStatement = Convert(inst.Body);