Browse Source

Fix #2391: mark method as unsafe when passing `null` to a parameter of pointer type.

pull/2408/head
Daniel Grunwald 4 years ago
parent
commit
1292ff70d9
  1. 18
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  2. 43
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs

18
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs

@ -561,5 +561,23 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -561,5 +561,23 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
UsePointer(a ? ptr : null);
}
public unsafe void UseArrayOfPointers(int*[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
arr[i] = null;
}
}
public unsafe void PassNullPointer1()
{
PointerReferenceExpression(null);
}
public unsafe void PassNullPointer2()
{
UseArrayOfPointers(null);
}
}
}

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

@ -130,15 +130,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -130,15 +130,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var rr = memberReferenceExpression.GetResolveResult();
if (rr != null)
{
if (IsPointer(rr.Type))
return true;
if (rr is MemberResolveResult mrr && mrr.Member.ReturnType.Kind == TypeKind.Delegate)
{
var method = mrr.Member.ReturnType.GetDefinition()?.GetDelegateInvokeMethod();
if (method != null && (IsPointer(method.ReturnType) || method.Parameters.Any(p => IsPointer(p.Type))))
if (IsUnsafeType(rr.Type))
return true;
}
}
return result;
}
@ -149,15 +143,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -149,15 +143,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var rr = identifierExpression.GetResolveResult();
if (rr != null)
{
if (IsPointer(rr.Type))
return true;
if (rr is MemberResolveResult mrr && mrr.Member.ReturnType.Kind == TypeKind.Delegate)
{
var method = mrr.Member.ReturnType.GetDefinition()?.GetDelegateInvokeMethod();
if (method != null && (IsPointer(method.ReturnType) || method.Parameters.Any(p => IsPointer(p.Type))))
if (IsUnsafeType(rr.Type))
return true;
}
}
return result;
}
@ -166,7 +154,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -166,7 +154,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
bool result = base.VisitStackAllocExpression(stackAllocExpression);
var rr = stackAllocExpression.GetResolveResult();
if (IsPointer(rr?.Type))
if (IsUnsafeType(rr?.Type))
return true;
return result;
}
@ -175,8 +163,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -175,8 +163,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
bool result = base.VisitInvocationExpression(invocationExpression);
var rr = invocationExpression.GetResolveResult();
if (IsPointer(rr?.Type))
if (IsUnsafeType(rr?.Type))
return true;
if ((rr as MemberResolveResult)?.Member is IParameterizedMember pm)
{
if (pm.Parameters.Any(p => IsUnsafeType(p.Type)))
return true;
}
return result;
}
@ -186,7 +179,20 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -186,7 +179,20 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return true;
}
private bool IsPointer(IType type)
private bool IsUnsafeType(IType type)
{
if (type?.Kind == TypeKind.Delegate)
{
// 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))))
return true;
}
return ContainsPointer(type);
}
private bool ContainsPointer(IType type)
{
switch (type?.Kind)
{
@ -194,7 +200,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -194,7 +200,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
case TypeKind.FunctionPointer:
return true;
case TypeKind.ByReference:
return IsPointer(((ByReferenceType)type).ElementType);
case TypeKind.Array:
return IsUnsafeType(((Decompiler.TypeSystem.Implementation.TypeWithElementType)type).ElementType);
default:
return false;
}

Loading…
Cancel
Save