Browse Source

Fix #2777: StackOverflowException with recursive delegates

pull/2766/head
Daniel Grunwald 3 years ago
parent
commit
0fbbb6d95e
  1. 6
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
  2. 59
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
  3. 49
      ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs

6
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs

@ -255,6 +255,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction @@ -255,6 +255,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction
}
private delegate void GenericDelegate<T>();
public delegate void RefRecursiveDelegate(ref RefRecursiveDelegate d);
public static Func<string, string, bool> test0 = (string a, string b) => string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b);
public static Func<string, string, bool> test1 = (string a, string b) => string.IsNullOrEmpty(a) || !string.IsNullOrEmpty(b);
@ -570,6 +571,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction @@ -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

59
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs

@ -18,6 +18,7 @@ @@ -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 @@ -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 @@ -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 @@ -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)
{

49
ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs

@ -326,6 +326,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -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 @@ -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)
{

Loading…
Cancel
Save