From a4d05c889f5845e9c3804c7a7db20fd433b35db3 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 17 Jun 2021 21:20:19 +0200 Subject: [PATCH] Fix #1638: YieldReturnDecompiler: Recognize Dispose method of yield fsm by looking at the method impls, if its name was mangled. --- .../IL/ControlFlow/YieldReturnDecompiler.cs | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs index fc98e4b43..ea5cfeef7 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs @@ -535,7 +535,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow { if (isCompiledWithMono) { - disposeMethod = metadata.GetTypeDefinition(enumeratorType).GetMethods().FirstOrDefault(m => metadata.GetString(metadata.GetMethodDefinition(m).Name) == "Dispose"); + disposeMethod = metadata.GetTypeDefinition(enumeratorType).GetMethods().FirstOrDefault(m => ImplementsDisposeMethod(m, "Dispose")); var function = CreateILAst(disposeMethod, context); BlockContainer body = (BlockContainer)function.Body; @@ -558,12 +558,48 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow else { // Non-Mono: analyze try-finally structure in Dispose() - disposeMethod = metadata.GetTypeDefinition(enumeratorType).GetMethods().FirstOrDefault(m => metadata.GetString(metadata.GetMethodDefinition(m).Name) == "System.IDisposable.Dispose"); + disposeMethod = metadata.GetTypeDefinition(enumeratorType).GetMethods().FirstOrDefault(m => ImplementsDisposeMethod(m, "System.IDisposable.Dispose")); var function = CreateILAst(disposeMethod, context); var rangeAnalysis = new StateRangeAnalysis(StateRangeAnalysisMode.IteratorDispose, stateField); rangeAnalysis.AssignStateRanges(function.Body, LongSet.Universe); finallyMethodToStateRange = rangeAnalysis.finallyMethodToStateRange; } + + bool ImplementsDisposeMethod(MethodDefinitionHandle m, string disposeMethodName) + { + var def = metadata.GetMethodDefinition(m); + var name = metadata.GetString(def.Name); + if (name == disposeMethodName) + return true; + foreach (var i in m.GetMethodImplementations(metadata)) + { + var impl = metadata.GetMethodImplementation(i); + switch (impl.MethodDeclaration.Kind) + { + case HandleKind.MethodDefinition: + var md = metadata.GetMethodDefinition((MethodDefinitionHandle)impl.MethodDeclaration); + if (!md.GetDeclaringType().GetFullTypeName(metadata).IsKnownType(KnownTypeCode.IDisposable)) + continue; + if (metadata.GetString(md.Name) != "Dispose") + continue; + return true; + case HandleKind.MemberReference: + var mr = metadata.GetMemberReference((MemberReferenceHandle)impl.MethodDeclaration); + if (mr.GetKind() != MemberReferenceKind.Method) + continue; + if (!mr.Parent.GetFullTypeName(metadata).IsKnownType(KnownTypeCode.IDisposable)) + continue; + if (metadata.GetString(mr.Name) != "Dispose") + continue; + return true; + default: + continue; + } + } + return false; + } + + } [Conditional("DEBUG")]