From 33aa5f3da1b7a250b421398a8644ace9e35b88d6 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 8 Jul 2026 10:53:15 +0200 Subject: [PATCH 1/3] Fix Apple NativeAOT test harness crash from string P/Invoke marshalling AppleTestRunner.cs declares the mono_ios_set_summary and mono_ios_append_output __Internal P/Invokes with a string parameter. This file is compiled into every library test assembly. Several of those assemblies apply [assembly: DisableRuntimeMarshalling] through Common/src/DisableRuntimeMarshalling.cs, which disallows non-blittable P/Invoke marshalling. Under that attribute the NativeAOT compiler cannot marshal the string argument, even with [MarshalAs(UnmanagedType.LPUTF8Str)], so it emits a stub that throws MarshalDirectiveException. The harness aborts on startup before any test runs, failing every affected work item on the Apple NativeAOT test legs. Change the extern declarations to take a blittable IntPtr and convert the string to a null-terminated UTF-8 buffer in managed code with Marshal.StringToCoTaskMemUTF8, matching the native const char* signature in main-console.m. A blittable P/Invoke requires no runtime marshalling, so it compiles and runs under DisableRuntimeMarshalling and remains correct on Mono and NativeAOT. Fixes #130219 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../tests/AppleTestRunner/AppleTestRunner.cs | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs index 2af27adacbe6d0..c64e81184fb47c 100644 --- a/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs +++ b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs @@ -20,11 +20,37 @@ public class SimpleTestRunner : iOSApplicationEntryPoint, IDevice { // to be wired once https://github.com/dotnet/xharness/pull/46 is merged - [DllImport("__Internal")] - public extern static void mono_ios_append_output (string value); + [DllImport("__Internal", EntryPoint = "mono_ios_append_output")] + private extern static void mono_ios_append_output_native (IntPtr value); - [DllImport("__Internal")] - public extern static void mono_ios_set_summary (string value); + [DllImport("__Internal", EntryPoint = "mono_ios_set_summary")] + private extern static void mono_ios_set_summary_native (IntPtr value); + + private static void mono_ios_append_output (string value) + { + IntPtr ptr = Marshal.StringToCoTaskMemUTF8(value); + try + { + mono_ios_append_output_native(ptr); + } + finally + { + Marshal.FreeCoTaskMem(ptr); + } + } + + private static void mono_ios_set_summary (string value) + { + IntPtr ptr = Marshal.StringToCoTaskMemUTF8(value); + try + { + mono_ios_set_summary_native(ptr); + } + finally + { + Marshal.FreeCoTaskMem(ptr); + } + } private static List s_testLibs = new List(); private static List? s_testAssemblies; From d5db26c5fa55ee15d074e4089a2c7dc15d47b8f6 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 8 Jul 2026 18:24:21 +0200 Subject: [PATCH 2/3] Use `[LibraryImport]` for the Apple test harness P/Invokes Replace the manual `IntPtr` plus `Marshal.StringToCoTaskMemUTF8` marshalling of `mono_ios_set_summary` and `mono_ios_append_output` with source-generated `[LibraryImport]` using `StringMarshalling.Utf8`. The generator emits a blittable `byte*` inner P/Invoke and performs the UTF-8 conversion in managed code, so no runtime string marshalling crosses the P/Invoke boundary. This keeps the harness correct under `[assembly: DisableRuntimeMarshalling]` on NativeAOT and on Mono. The generated stubs require unsafe code, so `AllowUnsafeBlocks` is enabled for the harness project and the NativeAOT iOS-like test build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/testing/tests.ioslike.targets | 2 ++ .../tests/AppleTestRunner/AppleTestRunner.cs | 36 +++---------------- .../AppleTestRunner/AppleTestRunner.csproj | 1 + 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/eng/testing/tests.ioslike.targets b/eng/testing/tests.ioslike.targets index 24de43e2a24225..58ff717d2225a6 100644 --- a/eng/testing/tests.ioslike.targets +++ b/eng/testing/tests.ioslike.targets @@ -13,6 +13,8 @@ Static true <_SuppressNativeLibEventSourceWarning>true + + true diff --git a/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs index c64e81184fb47c..ef38eea9823e21 100644 --- a/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs +++ b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs @@ -17,40 +17,14 @@ using Microsoft.DotNet.XHarness.TestRunners.Common; using Microsoft.DotNet.XHarness.TestRunners.Xunit; -public class SimpleTestRunner : iOSApplicationEntryPoint, IDevice +public partial class SimpleTestRunner : iOSApplicationEntryPoint, IDevice { // to be wired once https://github.com/dotnet/xharness/pull/46 is merged - [DllImport("__Internal", EntryPoint = "mono_ios_append_output")] - private extern static void mono_ios_append_output_native (IntPtr value); + [LibraryImport("__Internal", EntryPoint = "mono_ios_append_output", StringMarshalling = StringMarshalling.Utf8)] + private static partial void mono_ios_append_output (string value); - [DllImport("__Internal", EntryPoint = "mono_ios_set_summary")] - private extern static void mono_ios_set_summary_native (IntPtr value); - - private static void mono_ios_append_output (string value) - { - IntPtr ptr = Marshal.StringToCoTaskMemUTF8(value); - try - { - mono_ios_append_output_native(ptr); - } - finally - { - Marshal.FreeCoTaskMem(ptr); - } - } - - private static void mono_ios_set_summary (string value) - { - IntPtr ptr = Marshal.StringToCoTaskMemUTF8(value); - try - { - mono_ios_set_summary_native(ptr); - } - finally - { - Marshal.FreeCoTaskMem(ptr); - } - } + [LibraryImport("__Internal", EntryPoint = "mono_ios_set_summary", StringMarshalling = StringMarshalling.Utf8)] + private static partial void mono_ios_set_summary (string value); private static List s_testLibs = new List(); private static List? s_testAssemblies; diff --git a/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.csproj b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.csproj index 4f33bc8b4a5655..c993673026325a 100644 --- a/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.csproj +++ b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.csproj @@ -2,6 +2,7 @@ Exe enable + true $(NetCoreAppCurrent) From 8f653bed1e606c08b9cb93690cdb21abb15c8069 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 8 Jul 2026 18:28:03 +0200 Subject: [PATCH 3/3] Drop redundant comment in tests.ioslike.targets Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/testing/tests.ioslike.targets | 1 - 1 file changed, 1 deletion(-) diff --git a/eng/testing/tests.ioslike.targets b/eng/testing/tests.ioslike.targets index 58ff717d2225a6..c1ea8a9e5e82aa 100644 --- a/eng/testing/tests.ioslike.targets +++ b/eng/testing/tests.ioslike.targets @@ -13,7 +13,6 @@ Static true <_SuppressNativeLibEventSourceWarning>true - true