From 300c9cc9a9177413ff0e596cba851c962087b23f Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 11 Nov 2017 03:44:00 +0100 Subject: [PATCH] Do not convert while-true to while-condition loop or do-while loop, if the condition uses a variable that is captured inside the loop. --- .../TestCases/Correctness/Capturing.cs | 39 +++++++++++++++++++ .../IL/Transforms/HighLevelLoopTransform.cs | 13 +++++++ 2 files changed, 52 insertions(+) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Capturing.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Capturing.cs index 986a154a9..2d5820e6a 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Capturing.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Capturing.cs @@ -19,6 +19,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness OutsideLoopOverArray(); OutsideLoopOverArray2(); InsideLoopOverArray2(); + NotWhileDueToVariableInsideLoop(); + NotDoWhileDueToVariableInsideLoop(); } static void TestCase1() @@ -174,5 +176,42 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness Console.WriteLine(func()); } } + + static int nextVal; + + static int GetVal() + { + return ++nextVal & 7; + } + + static void NotWhileDueToVariableInsideLoop() + { + Console.WriteLine("NotWhileDueToVariableInsideLoop:"); + var functions = new List>(); + while (true) { + int v; + if ((v = GetVal()) == 0) + break; + functions.Add(() => v); + } + foreach (var f in functions) { + Console.WriteLine(f()); + } + } + + static void NotDoWhileDueToVariableInsideLoop() + { + Console.WriteLine("NotDoWhileDueToVariableInsideLoop:"); + var functions = new List>(); + while (true) { + int v = GetVal(); + functions.Add(() => v); + if (v == 0) + break; + } + foreach (var f in functions) { + Console.WriteLine(f()); + } + } } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs index 77eb629b9..955a8b05e 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs @@ -64,6 +64,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; if (!ifInstruction.FalseInst.MatchNop()) return false; + if (UsesVariableCapturedInLoop(loop, ifInstruction.Condition)) + return false; condition = ifInstruction; var trueInst = ifInstruction.TrueInst; if (!loop.EntryPoint.Instructions[1].MatchLeave(loop)) @@ -188,6 +190,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms while (i >= 0 && block.Instructions[i] is IfInstruction ifInst) { if (!ifInst.FalseInst.MatchNop()) break; + if (UsesVariableCapturedInLoop(loop, ifInst.Condition)) + break; if (swap) { if (!ifInst.TrueInst.MatchLeave(loop)) break; @@ -203,6 +207,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms return list; } + static bool UsesVariableCapturedInLoop(BlockContainer loop, ILInstruction condition) + { + foreach (var inst in condition.Descendants.OfType()) { + if (inst.Variable.CaptureScope == loop) + return true; + } + return false; + } + static bool MatchDoWhileConditionBlock(BlockContainer loop, Block block, out bool swapBranches) { // match the end of the block: