Skip to content

Commit fc41993

Browse files
Fixing a null ref exception related to function pointers and interfaces (#2354)
1 parent 53c5d48 commit fc41993

File tree

5 files changed

+114
-0
lines changed

5 files changed

+114
-0
lines changed

src/linker/Linker/TypeMapInfo.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,9 @@ static bool TypeMatch (TypeSpecification a, TypeSpecification b)
369369
if (a is IModifierType mta)
370370
return TypeMatch (mta, (IModifierType) b);
371371

372+
if (a is FunctionPointerType fpta)
373+
return TypeMatch (fpta, (FunctionPointerType) b);
374+
372375
return TypeMatch (a.ElementType, b.ElementType);
373376
}
374377

@@ -407,6 +410,39 @@ static bool TypeMatch (GenericParameter a, GenericParameter b)
407410
return true;
408411
}
409412

413+
static bool TypeMatch (FunctionPointerType a, FunctionPointerType b)
414+
{
415+
if (a.HasParameters != b.HasParameters)
416+
return false;
417+
418+
if (a.CallingConvention != b.CallingConvention)
419+
return false;
420+
421+
// we need to track what the generic parameter represent - as we cannot allow it to
422+
// differ between the return type or any parameter
423+
if (a.ReturnType is not TypeReference aReturnType ||
424+
b.ReturnType is not TypeReference bReturnType ||
425+
!TypeMatch (aReturnType, bReturnType))
426+
return false;
427+
428+
if (!a.HasParameters)
429+
return true;
430+
431+
var ap = a.Parameters;
432+
var bp = b.Parameters;
433+
if (ap.Count != bp.Count)
434+
return false;
435+
436+
for (int i = 0; i < ap.Count; i++) {
437+
if (a.Parameters[i].ParameterType is not TypeReference aParameterType ||
438+
b.Parameters[i].ParameterType is not TypeReference bParameterType ||
439+
!TypeMatch (aParameterType, bParameterType))
440+
return false;
441+
}
442+
443+
return true;
444+
}
445+
410446
static bool TypeMatch (TypeReference a, TypeReference b)
411447
{
412448
if (a is TypeSpecification || b is TypeSpecification) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Mono.Linker.Tests.Cases.Expectations.Assertions;
5+
using Mono.Linker.Tests.Cases.Expectations.Metadata;
6+
7+
namespace Mono.Linker.Tests.Cases.FunctionPointers
8+
{
9+
[SetupCompileArgument ("/unsafe")]
10+
unsafe class CanCompileInterfaceWithFunctionPointerParameter
11+
{
12+
public static void Main ()
13+
{
14+
new CanCompileInterfaceWithFunctionPointerParameter.B ().Method (null);
15+
}
16+
17+
[KeptMember (".ctor()")]
18+
class B : I
19+
{
20+
public void Unused (delegate* unmanaged<void> fnptr)
21+
{
22+
}
23+
24+
[Kept]
25+
public void Method (delegate* unmanaged<void> fnptr)
26+
{
27+
}
28+
}
29+
30+
interface I
31+
{
32+
void Unused (delegate* unmanaged<void> fnptr);
33+
34+
void Method (delegate* unmanaged<void> fnptr);
35+
}
36+
}
37+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Mono.Linker.Tests.Cases.Expectations.Assertions;
5+
using Mono.Linker.Tests.Cases.Expectations.Metadata;
6+
7+
namespace Mono.Linker.Tests.Cases.FunctionPointers
8+
{
9+
[SetupCompileArgument ("/unsafe")]
10+
unsafe class CanCompileMethodWithFunctionPointerParameter
11+
{
12+
public static void Main ()
13+
{
14+
new CanCompileMethodWithFunctionPointerParameter.B ().Method (null);
15+
}
16+
17+
[KeptMember (".ctor()")]
18+
class B
19+
{
20+
public void Unused (delegate* unmanaged<void> fnptr)
21+
{
22+
}
23+
24+
[Kept]
25+
public void Method (delegate* unmanaged<void> fnptr)
26+
{
27+
}
28+
}
29+
}
30+
}

test/Mono.Linker.Tests/TestCases/TestDatabase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ public static IEnumerable<TestCaseData> FeatureSettingsTests ()
8686
return NUnitCasesBySuiteName ("FeatureSettings");
8787
}
8888

89+
public static IEnumerable<TestCaseData> FunctionPointersTests ()
90+
{
91+
return NUnitCasesBySuiteName ("FunctionPointers");
92+
}
93+
8994
public static IEnumerable<TestCaseData> GenericsTests ()
9095
{
9196
return NUnitCasesBySuiteName ("Generics");

test/Mono.Linker.Tests/TestCases/TestSuites.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ public void FeatureSettingsTests (TestCase testCase)
103103
Run (testCase);
104104
}
105105

106+
[TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.FunctionPointersTests))]
107+
public void FunctionPointerTests (TestCase testCase)
108+
{
109+
Run (testCase);
110+
}
111+
106112
[TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.GenericsTests))]
107113
public void GenericsTests (TestCase testCase)
108114
{

0 commit comments

Comments
 (0)