Skip to content

Fix Apple NativeAOT test harness crash from string P/Invoke marshalling#130341

Merged
kotlarmilos merged 3 commits into
dotnet:mainfrom
kotlarmilos:fix-apple-nativeaot-marshalling
Jul 9, 2026
Merged

Fix Apple NativeAOT test harness crash from string P/Invoke marshalling#130341
kotlarmilos merged 3 commits into
dotnet:mainfrom
kotlarmilos:fix-apple-nativeaot-marshalling

Conversation

@kotlarmilos

@kotlarmilos kotlarmilos commented Jul 8, 2026

Copy link
Copy Markdown
Member

Description

The Apple NativeAOT test harness aborts on startup with MarshalDirectiveException before any test runs. Its mono_ios_set_summary and mono_ios_append_output __Internal P/Invokes take a string, and the harness file is compiled into library test assemblies that apply [assembly: DisableRuntimeMarshalling] through src/libraries/Common/src/DisableRuntimeMarshalling.cs. Under that attribute the NativeAOT compiler disallows non-blittable string marshalling even with [MarshalAs(UnmanagedType.LPUTF8Str)], so it emits a stub that throws at startup. This change switches the externs to a blittable IntPtr and converts the string to a null-terminated UTF-8 buffer in managed code with Marshal.StringToCoTaskMemUTF8, matching the native const char* in src/tasks/AppleAppBuilder/Templates/main-console.m. A blittable P/Invoke needs no runtime marshalling and stays correct on Mono and NativeAOT.

Fixes #130219.

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 dotnet#130219

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Apple NativeAOT library test harness (SimpleTestRunner) to avoid unsupported string marshalling in __Internal P/Invokes by switching the native imports to a blittable IntPtr signature and performing explicit UTF-8 allocation/free in managed code. This aligns the managed interop with the native const char* functions used by the AppleAppBuilder template and prevents the harness from aborting before any tests execute on Apple NativeAOT legs.

Changes:

  • Replace string-typed DllImport("__Internal") declarations with IntPtr-typed native entrypoints.
  • Add managed wrappers that convert string to a null-terminated UTF-8 buffer via Marshal.StringToCoTaskMemUTF8 and free it with Marshal.FreeCoTaskMem.
Show a summary per file
File Description
src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs Switches mono_ios_* P/Invokes to blittable IntPtr and adds UTF-8 allocation/free wrappers to avoid runtime marshalling.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

@kotlarmilos kotlarmilos added this to the 11.0.0 milestone Jul 8, 2026
@kotlarmilos

Copy link
Copy Markdown
Member Author

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@MichalStrehovsky

Copy link
Copy Markdown
Member

Under that attribute the NativeAOT compiler disallows non-blittable string marshalling even with [MarshalAs(UnmanagedType.LPUTF8Str)]

Yes, this is not supposed to work and I don't think it works with CoreCLR either. The fact it works on Mono is a bit concerning because DisableRuntimeMarshalling is supposed to fully disable it. I guess if we didn't run into issues so far, it's probably fine for one more release.

Does [LibraryImport] work here? You could replace the [DllImport] with [LibraryImport] and that will do the marshalling for you.

@kotlarmilos

Copy link
Copy Markdown
Member Author

Under that attribute the NativeAOT compiler disallows non-blittable string marshalling even with [MarshalAs(UnmanagedType.LPUTF8Str)]

Yes, this is not supposed to work and I don't think it works with CoreCLR either. The fact it works on Mono is a bit concerning because DisableRuntimeMarshalling is supposed to fully disable it. I guess if we didn't run into issues so far, it's probably fine for one more release.

Does [LibraryImport] work here? You could replace the [DllImport] with [LibraryImport] and that will do the marshalling for you.

[LibraryImport] should work, but the generated stub is unsafe, which is why I went with it. If you prefer [LibraryImport] for consistency, I am happy to switch it.

@jkotas

jkotas commented Jul 8, 2026

Copy link
Copy Markdown
Member

[LibraryImport] should work, but the generated stub is unsafe, which is why I went with it.

The APIs you are calling directly are unsafe too, and they will require unsafe annotations in not-too-distant future as well.

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>
Copilot AI review requested due to automatic review settings July 8, 2026 16:24
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 1

Comment thread src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs
Copilot AI review requested due to automatic review settings July 8, 2026 16:29
@kotlarmilos

Copy link
Copy Markdown
Member Author

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 1

Comment thread src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs
@kotlarmilos

Copy link
Copy Markdown
Member Author

/ba-g unrelated extra-platforms failures, no marshalling Native AOT errors on Apple mobile

@kotlarmilos kotlarmilos merged commit 7600052 into dotnet:main Jul 9, 2026
182 of 200 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot modified the milestones: 11.0.0, 11.0-preview7 Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ci-scan] Apple NativeAOT test harness crash: mono_ios_set_summary requires marshalling not yet supported by ILC

4 participants