Browse Source

Fix #1643: Handle unbox.any in TransformCatchVariable.

pull/1649/head
Daniel Grunwald 6 years ago
parent
commit
f1021cb300
  1. 74
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.cs
  2. 3
      ICSharpCode.Decompiler/IL/ILVariable.cs
  3. 37
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

74
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExceptionHandling.cs

@ -243,7 +243,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine("0"); Console.WriteLine("0");
} }
Console.WriteLine("End Try"); Console.WriteLine("End Try");
} catch { } catch {
@ -259,7 +259,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine("Catch2"); Console.WriteLine("Catch2");
} }
return B(10) && B(11); return B(10) && B(11);
} catch { } catch {
Console.WriteLine("Catch"); Console.WriteLine("Catch");
} finally { } finally {
Console.WriteLine("Finally"); Console.WriteLine("Finally");
@ -281,5 +281,75 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
} }
public void ReassignExceptionVar()
{
try {
Console.WriteLine("ReassignExceptionVar");
} catch (Exception innerException) {
if (innerException.InnerException != null) {
innerException = innerException.InnerException;
}
Console.WriteLine(innerException);
}
}
public int UseExceptionVarOutsideCatch()
{
Exception ex2;
try {
return 1;
} catch (Exception ex) {
ex2 = ex;
}
Console.WriteLine(ex2 != null);
return 2;
}
public void GenericException<TException>(int input) where TException : Exception
{
try {
Console.WriteLine(input);
} catch (TException val) {
Console.WriteLine(val.Message);
throw;
}
}
public void GenericException2<T>() where T : Exception
{
try {
Console.WriteLine("CatchT");
#if ROSLYN
} catch (T val) {
Console.WriteLine("{0} {1}", val, val.ToString());
}
#else
} catch (T arg) {
Console.WriteLine("{0} {1}", arg, arg.ToString());
}
#endif
}
#if CS60
public void GenericExceptionWithCondition<TException>(int input) where TException : Exception
{
try {
Console.WriteLine(input);
} catch (TException val) when (val.Message.Contains("Test")) {
Console.WriteLine(val.Message);
throw;
}
}
public void GenericException2WithCondition<TException>(int input) where TException : Exception
{
try {
Console.WriteLine(input);
} catch (TException val) when (val.Message.Contains("Test")) {
Console.WriteLine("{0} {1}", val, val.ToString());
}
}
#endif
} }
} }

3
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
@ -216,7 +217,7 @@ namespace ICSharpCode.Decompiler.IL
/// This list is automatically updated when adding/removing ldloc instructions from the ILAst. /// This list is automatically updated when adding/removing ldloc instructions from the ILAst.
/// </remarks> /// </remarks>
public IReadOnlyList<LdLoc> LoadInstructions => loadInstructions; public IReadOnlyList<LdLoc> LoadInstructions => loadInstructions;
/// <summary> /// <summary>
/// Number of store instructions referencing this variable, /// Number of store instructions referencing this variable,
/// plus 1 if HasInitialValue. /// plus 1 if HasInitialValue.

37
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -17,13 +17,10 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.IL.Transforms namespace ICSharpCode.Decompiler.IL.Transforms
{ {
@ -708,15 +705,41 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary> /// </summary>
void TransformCatchVariable(TryCatchHandler handler, Block entryPoint) void TransformCatchVariable(TryCatchHandler handler, Block entryPoint)
{ {
if (!entryPoint.Instructions[0].MatchStLoc(out var exceptionVar, out var exceptionSlotLoad)) if (!handler.Variable.IsSingleDefinition || handler.Variable.LoadCount != 1)
return; // handle.Variable already has non-trivial uses
if (!entryPoint.Instructions[0].MatchStLoc(out var exceptionVar, out var exceptionSlotLoad)) {
// Not the pattern with a second exceptionVar.
// However, it is still possible that we need to remove a pointless UnboxAny:
if (handler.Variable.LoadInstructions.Single().Parent is UnboxAny inlinedUnboxAny) {
if (inlinedUnboxAny.Type.Equals(handler.Variable.Type)) {
context.Step("TransformCatchVariable - remove inlined UnboxAny", inlinedUnboxAny);
inlinedUnboxAny.ReplaceWith(inlinedUnboxAny.Argument);
}
}
return; return;
if (!exceptionVar.IsSingleDefinition || exceptionVar.Kind != VariableKind.Local) }
if (exceptionVar.Kind != VariableKind.Local && exceptionVar.Kind != VariableKind.StackSlot)
return; return;
if (!exceptionSlotLoad.MatchLdLoc(handler.Variable) || !handler.Variable.IsSingleDefinition || handler.Variable.LoadCount != 1) if (exceptionSlotLoad is UnboxAny unboxAny) {
// When catching a type parameter, csc emits an unbox.any instruction
if (!unboxAny.Type.Equals(handler.Variable.Type))
return;
exceptionSlotLoad = unboxAny.Argument;
}
if (!exceptionSlotLoad.MatchLdLoc(handler.Variable))
return; return;
// Check that exceptionVar is only used within the catch block:
var allUses = exceptionVar.LoadInstructions
.Concat(exceptionVar.StoreInstructions.Cast<ILInstruction>())
.Concat(exceptionVar.AddressInstructions);
foreach (var inst in allUses) {
if (!inst.IsDescendantOf(handler))
return;
}
context.Step("TransformCatchVariable", entryPoint.Instructions[0]); context.Step("TransformCatchVariable", entryPoint.Instructions[0]);
handler.Variable = exceptionVar;
exceptionVar.Kind = VariableKind.ExceptionLocal; exceptionVar.Kind = VariableKind.ExceptionLocal;
exceptionVar.Type = handler.Variable.Type;
handler.Variable = exceptionVar;
entryPoint.Instructions.RemoveAt(0); entryPoint.Instructions.RemoveAt(0);
} }

Loading…
Cancel
Save