From e024641a5f55b9eb9a99a1a97971a925d97fdce8 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 8 Sep 2017 23:44:07 +0200 Subject: [PATCH] [async] Fix bug when async method uses this pointer. --- .../RoundtripAssembly.cs | 4 +-- .../CSharp/Transforms/DeclareVariables.cs | 2 +- .../IL/ControlFlow/AsyncAwaitDecompiler.cs | 31 +++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs index 38633358e..f8b9dbf5a 100644 --- a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs +++ b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs @@ -42,9 +42,9 @@ namespace ICSharpCode.Decompiler.Tests } [Test] - public void NewtonsoftJson_net40() + public void NewtonsoftJson_net45() { - RunWithTest("Newtonsoft.Json-net40", "Newtonsoft.Json.dll", "Newtonsoft.Json.Tests.dll"); + RunWithTest("Newtonsoft.Json-net45", "Newtonsoft.Json.dll", "Newtonsoft.Json.Tests.dll"); } [Test] diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs index 750231c49..ed9460248 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs @@ -361,7 +361,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms if (v.Type.Kind == TypeKind.ByReference) { expectedExpr = new DirectionExpression(FieldDirection.Ref, expectedExpr); } - if (assignment != null && assignment.Left.IsMatch(expectedExpr)) { + if (assignment != null && assignment.Operator == AssignmentOperatorType.Assign && assignment.Left.IsMatch(expectedExpr)) { AstType type; if (v.Type.ContainsAnonymousType()) { type = new SimpleType("var"); diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs index 0988298d1..e7e1bd67f 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs @@ -47,6 +47,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow IField stateField; int initialState; Dictionary fieldToParameterMap = new Dictionary(); + Dictionary cachedFieldToParameterMap = new Dictionary(); // These fields are set by AnalyzeMoveNext(): ILFunction moveNextFunction; @@ -70,6 +71,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow return; // abort if async/await decompilation is disabled this.context = context; fieldToParameterMap.Clear(); + cachedFieldToParameterMap.Clear(); awaitBlocks.Clear(); if (!MatchTaskCreationPattern(function)) return; @@ -90,6 +92,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow context.Step("Translate fields to local accesses", function); MarkGeneratedVariables(function); YieldReturnDecompiler.TranslateFieldsToLocalAccess(function, function, fieldToParameterMap); + TranslateCachedFieldsToLocals(); FinalizeInlineMoveNext(function); @@ -309,7 +312,22 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow throw new SymbolicAnalysisFailedException(); ++pos; } + while (blockContainer.EntryPoint.Instructions[pos] is StLoc stloc) { + // stloc V_1(ldfld <>4__this(ldloc this)) + if (!stloc.Variable.IsSingleDefinition) + throw new SymbolicAnalysisFailedException(); + if (!stloc.Value.MatchLdFld(out var target, out var field)) + throw new SymbolicAnalysisFailedException(); + if (!target.MatchLdThis()) + throw new SymbolicAnalysisFailedException(); + if (!fieldToParameterMap.TryGetValue((IField)field.MemberDefinition, out var param)) + throw new SymbolicAnalysisFailedException(); + cachedFieldToParameterMap[stloc.Variable] = param; + pos++; + } mainTryCatch = blockContainer.EntryPoint.Instructions[pos] as TryCatch; + if (mainTryCatch == null) + throw new SymbolicAnalysisFailedException(); // CatchHandler will be validated in ValidateCatchBlock() if (((BlockContainer)mainTryCatch.TryBlock).EntryPoint.Instructions[0] is StLoc initDoFinallyBodies @@ -861,5 +879,18 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow } return entryPoint; } + + void TranslateCachedFieldsToLocals() + { + foreach (var (cachedVar, param) in cachedFieldToParameterMap) { + Debug.Assert(cachedVar.StoreCount <= 1); + foreach (var inst in cachedVar.LoadInstructions.ToArray()) { + inst.Variable = param; + } + foreach (var inst in cachedVar.AddressInstructions.ToArray()) { + inst.Variable = param; + } + } + } } }