From 0fbbb6d95e2ab8af48fd619cccef0f97dddfd268 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 4 Sep 2022 20:55:38 +0200 Subject: [PATCH] Fix #2777: StackOverflowException with recursive delegates --- .../TestCases/Pretty/DelegateConstruction.cs | 6 ++ .../Transforms/IntroduceUnsafeModifier.cs | 59 +++++++++---------- ...ransformFieldAndConstructorInitializers.cs | 49 ++++++++------- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs index 9b5123e8d..4046bebd1 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs @@ -255,6 +255,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction } private delegate void GenericDelegate(); + public delegate void RefRecursiveDelegate(ref RefRecursiveDelegate d); public static Func test0 = (string a, string b) => string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b); public static Func test1 = (string a, string b) => string.IsNullOrEmpty(a) || !string.IsNullOrEmpty(b); @@ -570,6 +571,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction }; } #endif + + public static void CallRecursiveDelegate(ref RefRecursiveDelegate d) + { + d(ref d); + } } public class Issue1867 diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs index d3bcef5cf..40ba71aca 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs @@ -18,6 +18,7 @@ using System.Linq; +using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.Semantics; using ICSharpCode.Decompiler.TypeSystem; @@ -127,34 +128,23 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms pre.CopyAnnotationsFrom(memberReferenceExpression); memberReferenceExpression.ReplaceWith(pre); } - var rr = memberReferenceExpression.GetResolveResult(); - if (rr != null) - { - if (IsUnsafeType(rr.Type)) - return true; - } - + if (HasUnsafeResolveResult(memberReferenceExpression)) + return true; return result; } public override bool VisitIdentifierExpression(IdentifierExpression identifierExpression) { bool result = base.VisitIdentifierExpression(identifierExpression); - var rr = identifierExpression.GetResolveResult(); - if (rr != null) - { - if (IsUnsafeType(rr.Type)) - return true; - } - + if (HasUnsafeResolveResult(identifierExpression)) + return true; return result; } public override bool VisitStackAllocExpression(StackAllocExpression stackAllocExpression) { bool result = base.VisitStackAllocExpression(stackAllocExpression); - var rr = stackAllocExpression.GetResolveResult(); - if (IsUnsafeType(rr?.Type)) + if (HasUnsafeResolveResult(stackAllocExpression)) return true; return result; } @@ -162,14 +152,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms public override bool VisitInvocationExpression(InvocationExpression invocationExpression) { bool result = base.VisitInvocationExpression(invocationExpression); - var rr = invocationExpression.GetResolveResult(); - if (IsUnsafeType(rr?.Type)) + if (HasUnsafeResolveResult(invocationExpression)) return true; - if ((rr as MemberResolveResult)?.Member is IParameterizedMember pm) - { - if (pm.Parameters.Any(p => IsUnsafeType(p.Type))) - return true; - } return result; } @@ -179,20 +163,33 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms return true; } - private bool IsUnsafeType(IType type) + private bool HasUnsafeResolveResult(AstNode node) { - if (type?.Kind == TypeKind.Delegate) + var rr = node.GetResolveResult(); + if (rr == null) + return false; + if (IsUnsafeType(rr.Type)) + return true; + if ((rr as MemberResolveResult)?.Member is IParameterizedMember pm) { - // Using a delegate which involves pointers in its signature needs the unsafe modifier - // https://github.com/icsharpcode/ILSpy/issues/949 - IMethod invoke = type.GetDelegateInvokeMethod(); - if (invoke != null && (ContainsPointer(invoke.ReturnType) || invoke.Parameters.Any(p => ContainsPointer(p.Type)))) + if (pm.Parameters.Any(p => IsUnsafeType(p.Type))) return true; } - return ContainsPointer(type); + else if (rr is MethodGroupResolveResult) + { + var chosenMethod = node.GetSymbol(); + if (chosenMethod is IParameterizedMember pm2) + { + if (IsUnsafeType(pm2.ReturnType)) + return true; + if (pm2.Parameters.Any(p => IsUnsafeType(p.Type))) + return true; + } + } + return false; } - private bool ContainsPointer(IType type) + private bool IsUnsafeType(IType type) { switch (type?.Kind) { diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs index 07be49c21..82b4666c2 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs @@ -326,6 +326,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms IMember fieldOrProperty = (assignment.Left.GetSymbol() as IMember)?.MemberDefinition; if (!(fieldOrProperty is IField || fieldOrProperty is IProperty) || !fieldOrProperty.IsStatic) break; + // Only move fields that are constants, if the declaring type is not marked beforefieldinit. + if (!declaringTypeIsBeforeFieldInit && fieldOrProperty is not IField { IsConst: true }) + { + break; + } var fieldOrPropertyDecl = members.FirstOrDefault(f => f.GetSymbol() == fieldOrProperty) as EntityDeclaration; if (fieldOrPropertyDecl == null) break; @@ -333,43 +338,35 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms { fieldOrPropertyDecl.Modifiers |= Modifiers.Unsafe; } - // Only move fields that are constants, if the declaring type is not marked beforefieldinit. - if (declaringTypeIsBeforeFieldInit || fieldOrProperty is IField { IsConst: true }) + if (fieldOrPropertyDecl is FieldDeclaration fd) { - if (fieldOrPropertyDecl is FieldDeclaration fd) + var v = fd.Variables.Single(); + if (v.Initializer.IsNull) { - var v = fd.Variables.Single(); - if (v.Initializer.IsNull) - { - v.Initializer = assignment.Right.Detach(); - } - else - { - var constant = v.Initializer.GetResolveResult(); - var expression = assignment.Right.GetResolveResult(); - if (!(constant.IsCompileTimeConstant && - TryEvaluateDecimalConstant(expression, out decimal value) && - value.Equals(constant.ConstantValue))) - { - // decimal values do not match, abort transformation - break; - } - } - } - else if (fieldOrPropertyDecl is PropertyDeclaration pd) - { - pd.Initializer = assignment.Right.Detach(); + v.Initializer = assignment.Right.Detach(); } else { - break; + var constant = v.Initializer.GetResolveResult(); + var expression = assignment.Right.GetResolveResult(); + if (!(constant.IsCompileTimeConstant && + TryEvaluateDecimalConstant(expression, out decimal value) && + value.Equals(constant.ConstantValue))) + { + // decimal values do not match, abort transformation + break; + } } - es.Remove(); + } + else if (fieldOrPropertyDecl is PropertyDeclaration pd) + { + pd.Initializer = assignment.Right.Detach(); } else { break; } + es.Remove(); } if (declaringTypeIsBeforeFieldInit && staticCtor.Body.Statements.Count == 0) {