Skip to content

Commit b910310

Browse files
Convert invalid C# uses of UnmanagedCallersOnly to IL. (#42146)
* Convert invalid C# uses of UnmanagedCallersOnly to IL for negative testing.
1 parent c867337 commit b910310

File tree

4 files changed

+107
-32
lines changed

4 files changed

+107
-32
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk.IL">
2+
<PropertyGroup>
3+
<OutputType>library</OutputType>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<Compile Include="InvalidCallbacks.il" />
7+
</ItemGroup>
8+
</Project>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
.assembly extern System.Runtime { }
5+
.assembly extern System.Runtime.InteropServices { }
6+
7+
.assembly InvalidCSharp { }
8+
9+
.class public auto ansi beforefieldinit InvalidCSharp.GenericClass`1<T>
10+
extends System.Object
11+
{
12+
.method public hidebysig static
13+
void CallbackMethod (
14+
int32 n
15+
) cil managed preservesig
16+
{
17+
.custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = (
18+
01 00 00 00
19+
)
20+
.maxstack 8
21+
IL_0000: ldstr "Functions with attribute UnmanagedCallersOnlyAttribute within a generic type are invalid"
22+
IL_0005: newobj instance void [System.Runtime]System.Exception::.ctor(string)
23+
IL_000a: throw
24+
}
25+
26+
.method public hidebysig specialname rtspecialname
27+
instance void .ctor () cil managed
28+
{
29+
.maxstack 8
30+
IL_0000: ldarg.0
31+
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
32+
IL_0006: ret
33+
}
34+
}
35+
36+
.class public auto ansi beforefieldinit InvalidCSharp.Callbacks
37+
extends [System.Runtime]System.Object
38+
{
39+
.method public hidebysig static
40+
int32 CallbackMethodGeneric<T> (
41+
!!T arg
42+
) cil managed preservesig
43+
{
44+
.custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = (
45+
01 00 00 00
46+
)
47+
.maxstack 8
48+
IL_0000: ldstr "Functions with attribute UnmanagedCallersOnlyAttribute cannot have generic arguments"
49+
IL_0005: newobj instance void [System.Runtime]System.Exception::.ctor(string)
50+
IL_000a: throw
51+
}
52+
53+
.method public hidebysig
54+
instance int32 CallbackNonStatic (
55+
int32 val
56+
) cil managed preservesig
57+
{
58+
.custom instance void [System.Runtime.InteropServices]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = (
59+
01 00 00 00
60+
)
61+
.maxstack 8
62+
IL_0000: ldstr "Instance functions with attribute UnmanagedCallersOnlyAttribute are invalid"
63+
IL_0005: newobj instance void [System.Runtime]System.Exception::.ctor(string)
64+
IL_000a: throw
65+
}
66+
67+
.method public hidebysig specialname rtspecialname
68+
instance void .ctor () cil managed
69+
{
70+
.maxstack 8
71+
IL_0000: ldarg.0
72+
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
73+
IL_0006: ret
74+
}
75+
}

src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Diagnostics;
6-
using System.Runtime.CompilerServices;
76
using System.Reflection;
87
using System.Reflection.Emit;
8+
using System.Runtime.CompilerServices;
99
using System.Runtime.InteropServices;
1010
using System.Threading;
1111
using TestLibrary;
@@ -35,6 +35,20 @@ public static class UnmanagedCallersOnlyDll
3535
public static extern int PInvokeMarkedWithUnmanagedCallersOnly(int n);
3636
}
3737

38+
private const string InvalidCSharpAssemblyName = "InvalidCSharp";
39+
40+
public static Type GetCallbacksType()
41+
{
42+
var asm = Assembly.Load(InvalidCSharpAssemblyName);
43+
return asm.GetType("InvalidCSharp.Callbacks");
44+
}
45+
46+
public static Type GetGenericClassOfIntType()
47+
{
48+
var asm = Assembly.Load(InvalidCSharpAssemblyName);
49+
return asm.GetType("InvalidCSharp.GenericClass`1").MakeGenericType(typeof(int));
50+
}
51+
3852
private delegate int IntNativeMethodInvoker();
3953
private delegate void NativeMethodInvoker();
4054

@@ -338,12 +352,6 @@ void CallAsDelegate()
338352
}
339353
}
340354

341-
[UnmanagedCallersOnly]
342-
public int CallbackNonStatic(int val)
343-
{
344-
Assert.Fail($"Instance functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} are invalid");
345-
return -1;
346-
}
347355

348356
public static void NegativeTest_NonStaticMethod()
349357
{
@@ -354,7 +362,7 @@ void TestUnmanagedCallersOnlyNonStatic()
354362
{
355363
.locals init ([0] native int ptr)
356364
nop
357-
ldftn int CallbackNonStatic(int)
365+
ldftn int GetCallbacksType().CallbackNonStatic(int)
358366
stloc.0
359367
360368
ldloc.0
@@ -371,7 +379,7 @@ ldftn int CallbackNonStatic(int)
371379
il.Emit(OpCodes.Nop);
372380

373381
// Get native function pointer of the callback
374-
il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackNonStatic)));
382+
il.Emit(OpCodes.Ldftn, GetCallbacksType().GetMethod("CallbackNonStatic"));
375383
il.Emit(OpCodes.Stloc_0);
376384
il.Emit(OpCodes.Ldloc_0);
377385

@@ -436,13 +444,6 @@ ldftn int CallbackMethodNonBlittable(bool)
436444
Assert.Throws<InvalidProgramException>(() => { testNativeMethod(); });
437445
}
438446

439-
[UnmanagedCallersOnly]
440-
public static int CallbackMethodGeneric<T>(T arg)
441-
{
442-
Assert.Fail($"Functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} cannot have generic arguments");
443-
return -1;
444-
}
445-
446447
public static void NegativeTest_NonInstantiatedGenericArguments()
447448
{
448449
Console.WriteLine($"Running {nameof(NegativeTest_NonInstantiatedGenericArguments)}...");
@@ -452,7 +453,7 @@ void TestUnmanagedCallersOnlyNonInstGenericArguments()
452453
{
453454
.locals init ([0] native int ptr)
454455
IL_0000: nop
455-
IL_0001: ldftn void CallbackMethodGeneric(T)
456+
IL_0001: ldftn void InvalidCSharp.Callbacks.CallbackMethodGeneric(T)
456457
IL_0007: stloc.0
457458
IL_0008: ret
458459
}
@@ -463,7 +464,7 @@ .locals init ([0] native int ptr)
463464
il.Emit(OpCodes.Nop);
464465

465466
// Get native function pointer of the callback
466-
il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodGeneric)));
467+
il.Emit(OpCodes.Ldftn, GetCallbacksType().GetMethod("CallbackMethodGeneric"));
467468
il.Emit(OpCodes.Stloc_0);
468469

469470
il.Emit(OpCodes.Ret);
@@ -482,7 +483,7 @@ void TestUnmanagedCallersOnlyInstGenericArguments()
482483
{
483484
.locals init ([0] native int ptr)
484485
nop
485-
ldftn void CallbackMethodGeneric(int)
486+
ldftn void InvalidCSharp.Callbacks.CallbackMethodGeneric(int)
486487
stloc.0
487488
488489
ldloc.0
@@ -499,7 +500,7 @@ ldftn void CallbackMethodGeneric(int)
499500
il.Emit(OpCodes.Nop);
500501

501502
// Get native function pointer of the instantiated generic callback
502-
il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodGeneric)).MakeGenericMethod(new [] { typeof(int) }));
503+
il.Emit(OpCodes.Ldftn, GetCallbacksType().GetMethod("CallbackMethodGeneric").MakeGenericMethod(new [] { typeof(int) }));
503504
il.Emit(OpCodes.Stloc_0);
504505
il.Emit(OpCodes.Ldloc_0);
505506

@@ -515,15 +516,6 @@ ldftn void CallbackMethodGeneric(int)
515516
Assert.Throws<InvalidProgramException>(() => { testNativeMethod(); });
516517
}
517518

518-
public class GenericClass<T>
519-
{
520-
[UnmanagedCallersOnly]
521-
public static void CallbackMethod(int n)
522-
{
523-
Assert.Fail($"Functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} within a generic type are invalid");
524-
}
525-
}
526-
527519
public static void NegativeTest_FromInstantiatedGenericClass()
528520
{
529521
Console.WriteLine($"Running {nameof(NegativeTest_FromInstantiatedGenericClass)}...");
@@ -533,7 +525,7 @@ void TestUnmanagedCallersOnlyInstGenericType()
533525
{
534526
.locals init ([0] native int ptr)
535527
nop
536-
ldftn int GenericClass<int>::CallbackMethod(int)
528+
ldftn int InvalidCSharp.GenericClass<int>::CallbackMethod(int)
537529
stloc.0
538530
539531
ldloc.0
@@ -550,7 +542,7 @@ .locals init ([0] native int ptr)
550542
il.Emit(OpCodes.Nop);
551543

552544
// Get native function pointer of the callback from the instantiated generic class.
553-
il.Emit(OpCodes.Ldftn, typeof(GenericClass<int>).GetMethod(nameof(GenericClass<int>.CallbackMethod)));
545+
il.Emit(OpCodes.Ldftn, GetGenericClassOfIntType().GetMethod("CallbackMethod"));
554546
il.Emit(OpCodes.Stloc_0);
555547
il.Emit(OpCodes.Ldloc_0);
556548

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<OutputType>Exe</OutputType>
4-
<CLRTestPriority>1</CLRTestPriority>
54
</PropertyGroup>
65
<ItemGroup>
76
<Compile Include="UnmanagedCallersOnlyTest.cs" />
@@ -10,5 +9,6 @@
109
<!-- This is needed to make sure native binary gets installed in the right location -->
1110
<ProjectReference Include="CMakeLists.txt" />
1211
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
12+
<ProjectReference Include="InvalidCSharp.ilproj" />
1313
</ItemGroup>
1414
</Project>

0 commit comments

Comments
 (0)