From 3c847b56a29d27cf6330bbd146a98569aa547f64 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 16 Jul 2022 12:20:12 +0200 Subject: [PATCH] Fix decompilation of async streams compiled with Roslyn 4.2 --- .../IL/ControlFlow/AsyncAwaitDecompiler.cs | 16 ++++++++++++---- .../IL/Instructions/PatternMatching.cs | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs index 335dffa36..c6b54ad44 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs @@ -725,6 +725,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow throw new SymbolicAnalysisFailedException(); finalStateKnown = true; pos++; + if (pos + 2 == block.Instructions.Count && block.MatchIfAtEndOfBlock(out var condition, out var trueInst, out var falseInst)) { if (MatchDisposeCombinedTokens(blockContainer, condition, trueInst, falseInst, blocksAnalyzed, out var setResultAndExitBlock)) @@ -807,7 +808,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow // https://github.com/dotnet/roslyn/pull/39735 hoisted local cleanup if (!target.MatchLdThis()) throw new SymbolicAnalysisFailedException(); - if (!(value.MatchLdNull() || value is DefaultValue)) + if (!value.MatchDefaultOrNullOrZero()) throw new SymbolicAnalysisFailedException(); pos++; } @@ -1441,13 +1442,20 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow pos--; } - if (pos < 0 || !block.Instructions[pos].MatchStFld(out var target, out var field, out yieldValue)) + if (pos < 0 || !MatchCurrentAssignment(block.Instructions[pos], out yieldValue)) + return false; + + block.Instructions.RemoveRange(pos, block.Instructions.Count - pos); + return true; + } + + bool MatchCurrentAssignment(ILInstruction inst, out ILInstruction value) + { + if (!inst.MatchStFld(out var target, out var field, out value)) return false; if (!StackSlotValue(target).MatchLdThis()) return false; // TODO: check that we are accessing the current field (compare with get_Current) - - block.Instructions.RemoveRange(pos, block.Instructions.Count - pos); return true; } #endregion diff --git a/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs b/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs index aa42395b4..5c5391723 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs @@ -553,6 +553,23 @@ namespace ICSharpCode.Decompiler.IL return false; } + public bool MatchDefaultOrNullOrZero() + { + switch (this) + { + case LdNull _: + case LdcF4 { Value: 0 }: + case LdcF8 { Value: 0 }: + case LdcI4 { Value: 0 }: + case LdcI8 { Value: 0 }: + case DefaultValue _: + return true; + default: + return false; + } + } + + /// /// If this instruction is a conversion of the specified kind, return its argument. /// Otherwise, return the instruction itself.