Skip to content

[Apple][Android][CoreCLR] Don't pass the program path as managed args[0]; quarantine newly running runtime tests - #134767

Merged
lewing merged 14 commits into
mainfrom
lewing-apple-coreclr-drop-argv0
Sep 28, 2026
Merged

lewing merged 14 commits into
mainfrom
lewing-apple-coreclr-drop-argv0

Conversation

@lewing

@lewing lewing commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

The CoreCLR Apple host (runtime-coreclr.m) built managed arguments from NSProcessInfo.arguments, whose element 0 is the executable path. It passed the whole array to coreclr_execute_assembly, whose argv becomes Main's args. corerun and the dotnet host pass only the arguments after the program name, and the Mono Apple host is unaffected because mono_jit_exec treats argv[0] as the program name.

The merged runtime-test runner passes args[0] to AppleEntryPoint as the single method to run. So on every CoreCLR Apple runtime-test lane (iOS, iOS simulator, tvOS, maccatalyst), all tests were filtered out and reported as skipped with "No Known Skip Reason", while xharness reported success. See #134766.

This change passes argi - 1, managed_argv + 1 in the Apple host. The Android CoreCLR host (monodroid-coreclr.c) had the same bug: it prepended the bundle path to managed_argv. The fix drops it. The Mono hosts are unchanged, because mono_jit_exec expects the program name in argv[0].

Bundling FSharp.Core in mobile test apps

F# tests load FSharp.Core from CORE_ROOT everywhere else, including wasm, which runs through corerun. Apple and Android merged runners bundle only their own publish output, so F# tests failed with FileNotFoundException. Merged runners that reference an .fsproj now resolve FSharp.Core from the test_dependencies_fs restore and bundle it. That's the same source CORE_ROOT uses, and CORE_ROOT itself isn't laid out until after the managed test build.

Interpreter and ReadyToRun detection on Apple

  • CoreClrConfigurationDetection.IsCoreClrInterpreter (behind RuntimeTestModes.InterpreterActive) keeps meaning "some code may be interpreted". Its WebAssembly special case becomes a general no-JIT check. The result on wasm is unchanged, and it now also covers Apple mobile, which has no JIT.
  • Apple mobile CoreCLR ReadyToRun test apps, library and runtime tests alike, now set TEST_READY_TO_RUN_MODE=1 in tests.ioslike.targets, mirroring tests.browser.targets. PlatformDetection.IsReadyToRunCompiled is therefore true there. AssemblyTests.GetEntryAssembly's single-file R2R branch now excludes Apple mobile, so it keeps expecting AppleTestRunner.

Validation (local, CoreCLR)

Both full Pri0 suites were run locally, all 82 work items each: maccatalyst-arm64 Release, and android-arm64 Release on the emulator.

Suite Before After
maccatalyst-arm64, all 82 work items Every test skipped No failures or hangs remaining after the changes below
android-arm64 emulator, all 82 work items Every test skipped 3,968 passed, 1 failed (Runtime_90219, now skipped), 372 skipped in the 77-group run; the other 5 groups pass as well. No hangs

Selected work items:

App Before After
JIT/Regression_o_3 (maccatalyst) 167 run, 0 passed, 167 skipped 167 run, 158 passed, 0 failed, 9 conditionally skipped
JIT/Regression_2 (maccatalyst) — 107 run, 99 passed, 0 failed, 8 skipped (Runtime_87393 passes with FSharp.Core bundled)
GC (maccatalyst R2R) — 53 passed, including GetGeneration
System.Reflection.Tests (library, maccatalyst R2R) — 1,771 passed, 0 failed
System.Buffers.Tests (library runner, maccatalyst) — 85 run, 76 passed, 0 failed
Android: JIT/JIT_r 30 run, 0 passed, 30 skipped 30 run, 30 passed
Android: JIT/Regression_2 — 107 run, 101 passed, 0 failed
Android: JIT/Directed/Directed_do — 42 run, 41 passed, 0 failed (includes mutual_recursion)
Android: JIT/Regression/Regression_5 — Test_HndIndex_10_* pass (JIT present)
Android: JIT/Regression_o_3 — 168 run, 158 passed, 0 failed

Newly running tests: quarantines and skips

These lanes had not run any runtime tests, so turning them on surfaces failures. Quarantines are scoped to CoreCLR on Apple mobile (IsAppleMobile AND IsCoreCLR) unless noted:

Test Failure Change
b425314 (Regression_d), b426654 (Regression_1) Hang: a GC suspension never completes because the runtime can't suspend a tight R2R loop, which also blocks the test's timeout timer ActiveIssue #134770
JIT/Directed/tailcall/mutual_recursion (Directed_do) Fatal stack overflow: tail calls between R2R and interpreted code grow the stack ActiveIssue #134775
Test_HndIndex_10_Plain, Test_HndIndex_10_Reordered (Regression_5) The tests expect the JIT to reject invalid IL; without a JIT the interpreter runs it Existing SkipOnCoreClr(InterpreterActive) now applies on Apple
GC/API/GC/GetGeneration (GC) Interpreted frames and WebAssembly report stack roots as pinned Runs only when its own code is compiled (not interpreted, or ReadyToRun); skipped on Browser/Wasi (see #134803). Keeps running on Apple R2R
Runtime_90219 (Regression_o_3) Loads its own assembly from Assembly.Location, which is empty in an app bundle ConditionalFact(Utilities.HasAssemblyFiles) replaces the platform list

CI should catch device-only failures (iOS, tvOS).

Resolves #134766

Note

This PR description was generated with GitHub Copilot.

NSProcessInfo.arguments includes the executable path as element 0, and the CoreCLR
Apple host passed the whole array to coreclr_execute_assembly, whose argv becomes
Main's args. The merged runtime-test runner treats args[0] as the test to run, so
every runtime test on iOS, tvOS and maccatalyst was reported as skipped.

Fixes #134766

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@lewing

lewing commented Sep 28, 2026 •

Copy link
Copy Markdown
Member Author

discovered this while wondering why the tests from #134765 weren't also red on apple mobile previously

@lewing lewing added os-ios Apple iOS os-maccatalyst MacCatalyst OS os-tvos Apple tvOS labels Sep 28, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'os-maccatalyst': @vitek-karas, @kotlarmilos, @steveisok, @akoeplinger
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'os-tvos': @vitek-karas, @kotlarmilos, @steveisok, @akoeplinger
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'os-ios': @vitek-karas, @kotlarmilos, @steveisok, @akoeplinger
See info in area-owners.md if you want to be subscribed.

monodroid-coreclr.c prepended the bundle path to the arguments it passed to
coreclr_execute_assembly, whose argv becomes Main's args. The merged runtime-test
runner treats args[0] as the test to run, so every Android CoreCLR runtime test was
reported as skipped. The Mono host keeps argv[0] because mono_jit_exec expects the
program name there.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The test hangs on maccatalyst CoreCLR: a GC suspension never completes because the
runtime can't suspend a tight R2R loop, which also blocks the test's own timeout timer.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lewing lewing changed the title [Apple][CoreCLR] Don't pass the executable path as managed args[0] [Apple][Android][CoreCLR] Don't pass the program path as managed args[0]; quarantine newly running runtime tests Sep 28, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-android': @vitek-karas, @simonrozsival, @steveisok, @akoeplinger
See info in area-owners.md if you want to be subscribed.

Same GC suspension hang as b425314: a flip thread in a tight R2R loop can't be suspended.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
lewing and others added 3 commits September 28, 2026 00:58
F# tests load FSharp.Core from CORE_ROOT on other platforms, but Apple and Android merged runners bundle only their own publish output, so F# tests failed with FileNotFoundException. Resolve FSharp.Core from the test_dependencies_fs restore (the same source CORE_ROOT uses; CORE_ROOT itself is laid out after the managed test build) and add it to runners that reference an .fsproj.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
With FSharp.Core bundled, the test now runs and hits a fatal stack overflow: tail calls between R2R and interpreted code grow the stack.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The tests expect the JIT to reject invalid IL. Without a JIT (Apple mobile), crossgen2 skips the method and the interpreter runs it without an exception. The existing InterpreterActive skip only covers DOTNET_Interpreter/InterpMode and wasm; gate on Utilities.IsCoreClrInterpreter, which also covers the no-JIT case.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@jkotas

jkotas commented Sep 28, 2026

Copy link
Copy Markdown
Member

The existing InterpreterActive skip only covers DOTNET_Interpreter/InterpMode and wasm

Should we fix that? (Alternatively, deprecate this flag and use IsCoreClrInterpreter / IsNotCoreClrInterpreter instead.)

The test loads its own assembly from Assembly.Location, which is empty for assemblies bundled in an Android app. It is already skipped on the other bundled platforms (Browser, Wasi, iOS, tvOS, MacCatalyst) for the same reason.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
InterpreterActive was true for every wasm run, including ReadyToRun, and never true on Apple mobile, which has no JIT. Define it as DOTNET_Interpreter/InterpMode, or no JIT without ReadyToRun, and set TEST_READY_TO_RUN_MODE=1 in Apple mobile runtime-test apps when they are ReadyToRun-compiled so the runtime can tell.

Tests this now runs on wasm ReadyToRun: GetGeneration fails there (#134803, quarantined), and ManagedPointers.Validate_GeneratedILStubs_NullByRef hits the interpreter even with ReadyToRun, so it now requires a JIT via Utilities.IsNotCoreClrInterpreter.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lewing

lewing commented Sep 28, 2026

Copy link
Copy Markdown
Member Author

The existing InterpreterActive skip only covers DOTNET_Interpreter/InterpMode and wasm

Should we fix that? (Alternatively, deprecate this flag and use IsCoreClrInterpreter / IsNotCoreClrInterpreter instead.)

Yeah it should be fixed. Fixing it properly will change the subsets that are running on wasm so it expands the scope of testing required for this pr to wasm as well but I don't expect much in the way of actual problems.

Comment thread src/tests/JIT/Regression_o_3/Runtime_90219.cs Outdated
lewing and others added 2 commits September 28, 2026 11:32
The test loads its own assembly from Assembly.Location, so require Utilities.HasAssemblyFiles rather than listing every configuration that bundles assemblies.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…reterMode

Its meaning (an interpreter test mode) now differs from Utilities.IsCoreClrInterpreter and the library-test PlatformDetection.IsCoreClrInterpreter (no JIT, so some code may be interpreted). Give it a distinct name and document both.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lewing

lewing commented Sep 28, 2026

Copy link
Copy Markdown
Member Author

Should we fix that? (Alternatively, deprecate this flag and use IsCoreClrInterpreter / IsNotCoreClrInterpreter instead.)

Done in c4e410a and c210851. The InterpreterActive mode is now DOTNET_Interpreter/InterpMode, or no JIT and not ReadyToRun; the blanket wasm case is gone. Apple mobile R2R test apps now set TEST_READY_TO_RUN_MODE=1, as wasm does.

The mode's predicate is renamed to CoreClrConfigurationDetection.IsInterpreterMode. Utilities.IsCoreClrInterpreter, which means "no JIT, so some code may be interpreted" (the same as the library tests' PlatformDetection.IsCoreClrInterpreter), keeps its name.

On wasm R2R this started running two tests:

Note

This comment was generated with GitHub Copilot.

Comment thread src/tests/Common/CoreCLRTestLibrary/Utilities.cs Outdated
lewing and others added 3 commits September 28, 2026 12:25
The property's meaning is unchanged; only its call to the renamed CoreClrConfigurationDetection.IsInterpreterMode differs from main.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…st apps

Mirror tests.browser.targets so both library and runtime-test Apple apps report PlatformDetection.IsReadyToRunCompiled. AssemblyTests.GetEntryAssembly now reached its desktop single-file R2R branch on Apple, so exclude Apple mobile from it; it keeps expecting AppleTestRunner.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
… instead

Revert the InterpreterActive redefinition and the IsInterpreterMode rename. CoreClrConfigurationDetection.IsCoreClrInterpreter keeps meaning 'some code may be interpreted'; its WebAssembly special case becomes a general no-JIT check, which also covers Apple mobile. HndIndex and ManagedPointers go back to their existing InterpreterActive skips.

GetGeneration only needs its own code to be compiled, so it gets a local condition (not interpreted, or ReadyToRun) and a permanent WebAssembly skip because stack roots there are reported as pinned (#134803). It keeps running on Apple mobile ReadyToRun.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@jkotas

jkotas commented Sep 28, 2026

Copy link
Copy Markdown
Member

LGTM

@lewing
lewing marked this pull request as ready for review September 28, 2026 20:55
@lewing
lewing enabled auto-merge (squash) September 28, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Infrastructure-coreclr Only use for closed issues os-android os-ios Apple iOS os-maccatalyst MacCatalyst OS os-tvos Apple tvOS

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Apple][CoreCLR] Runtime-test merged runners skip every test: executable path is passed as args[0] and used as the test filter

3 participants