Skip to content

[browser][CoreCLR][R2R] Filesystem timestamp tests load kernel32.dll through guarded IsInAppContainer #133614

Closed

Description

@lewing

Description

Trimmed browser CoreCLR R2R library tests fail when filesystem timestamp tests initialize BaseGetSetTimes<T>. Its PlatformDetection.IsInAppContainer call throws DllNotFoundException for kernel32.dll, despite the helper having an early !IsWindows return before the Windows P/Invoke.

This is classified as R2R-only execution behavior rather than a missing trimming descriptor: a clean aggressively trimmed non-R2R run of an affected group passes. Eager P/Invoke fixup resolution is a possibility, but the precise cause has not been established.

Reproduction Steps

Build browser CoreCLR, libraries, host, packs, and host crossgen2. Reproduced on 798449390515fa02f4b20160bedc5e34f8fbdfb9 plus publishing prerequisite #133378 (245cb70d593f2c8f3a4e23bcc422e7da5926e15b), with the existing mobile filesystem and StreamConformance trimming descriptors also enabled for browser aggressive trimming.

XHARNESS_COMMAND=test-browser ./dotnet.sh build /t:Test \
  src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/System.IO.FileSystem.Tests.csproj \
  /p:TargetOS=browser /p:TargetArchitecture=wasm /p:RuntimeFlavor=CoreCLR /p:Configuration=Release \
  /p:PublishReadyToRun=true /p:EnableAggressiveTrimming=true \
  /p:Scenario=WasmTestOnChrome /p:InstallChromeForTests=true /p:XunitShowProgress=true

For the comparison, use clean project-specific browser-wasm obj/bin outputs, set PublishReadyToRun=false, retain EnableAggressiveTrimming=true, and add:

/p:WasmTestAppArgs="-class System.IO.Tests.File_GetSetTimes_SafeFileHandle"

Expected behavior

Browser execution should return false from PlatformDetection.IsInAppContainer without loading a Windows library, and the timestamp tests should run.

Actual behavior

The R2R suite completed with 6,454 total: 6,184 passed, 26 failed, 244 skipped. The failures share this type-initializer error:

System.TypeInitializationException: The type initializer for 'System.IO.Tests.BaseGetSetTimes`1' threw an exception.
---- System.DllNotFoundException: Unable to load shared library 'kernel32.dll' or one of its dependencies.
dynamic linking not enabled
   at System.PlatformDetection.get_IsInAppContainer()
   at System.IO.Tests.BaseGetSetTimes`1..cctor()

Affected methods are inherited timestamp cases such as SettingUpdatesProperties, SettingUpdatesPropertiesWhenReadOnly, SettingUpdatesPropertiesAfterAnother, TimesIncludeMillisecondPart, and TimesNotIncludeMillisecondPart, across File, FileInfo, Directory, and DirectoryInfo variants.

The clean trimmed non-R2R comparison group reports 14 total: 11 passed, 0 failed, 3 skipped.

Regression?

Unknown. Only R2R-on versus R2R-off was compared; both retain aggressive trimming.

Known Workarounds

Disable R2R. During library-test bring-up, quarantine the affected timestamp cases specifically for browser R2R while retaining interpreter coverage.

Configuration

Browser-wasm CoreCLR Release, macOS arm64 build host, Chromium 153.0.8010.0, SDK 11.0.100-rc.1.26420.103.

Other information

Found while standing up trimmed R2R library tests for #133193. #131874 describes different build-time P/Invoke/struct-mapping failures; this report concerns a runtime DLL load in a guarded platform-detection helper.

Note

This issue was generated by GitHub Copilot from local build and test results.

Activity

  1. dotnet-policy-service commented on Sep 10, 2026

    @dotnet-policy-service
    Contributor

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

  2. lewing commented on Sep 10, 2026

    @lewing
    MemberAuthor

    The same guarded-platform-probe failure affects networking: HTTP failed 577 cases through TestUtilities probes loading kernel32.dll or libSystem.Security.Cryptography.Native.Android, and WebSockets failed 117 cases through the Android ALPN probe.

    A narrowly scoped workaround is to keep only TestUtilities.dll interpreted, using PublishReadyToRunExclude. With aggressive trimming unchanged:

    • FileSystem: 6,210 passed, 244 skipped, zero failures, including all previously quarantined timestamp tests. Those timestamp quarantines have been removed.
    • HTTP functional: 809 passed, 120 skipped, zero failures.
    • WebSockets client: 315 passed, zero failures.

    The served HTTP test assembly and System.Net.Http WASM files byte-match their compiler-generated R2R images; no TestUtilities native R2R image is emitted. This does not disable library R2R coverage. It isolates the failure to compiling the support assembly, rather than missing trimming descriptors. Eager resolution of platform-specific P/Invoke fixups remains a hypothesis, not a fully proven VM root cause.

    Note

    This update was generated by GitHub Copilot from local build and execution results.

  3. dotnet-policy-service commented on Sep 10, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
    See info in area-owners.md if you want to be subscribed.

  4. jkotas commented on Sep 10, 2026

    @jkotas
    Member

    Duplicate of #133259

  5. added this to the 12.0.0 milestone on Sep 10, 2026
  6. removed
    untriagedNew issue has not been triaged by the area owner
    on Sep 10, 2026
  7. lewing commented on Sep 19, 2026

    @lewing
    MemberAuthor

    The failure still reproduces after #133773 with consistently rebuilt CI artifacts, so this is not SDK crossgen2 flow lag.

    Structured inspection of build 1603680's LibraryTestsCoreCLR_R2R Build.binlog shows System.Runtime.Extensions.Tests used the in-build compiler:

    Crossgen2InBuildDir = /__w/1/s/artifacts/bin/coreclr/browser.wasm.Release/x64/crossgen2/
    Crossgen2Path = /__w/1/s/artifacts/bin/coreclr/browser.wasm.Release/x64/crossgen2/crossgen2
    _CreateR2RImages > RunReadyToRunCompiler = .../crossgen2 --targetos:browser
    

    The corresponding Helix job 99979e03-c8ff-4e09-bed4-556341a52a41 finished all 24 work items. Three batches failed only through TestUtilities.AdminHelpers.IsProcessElevated reaching SystemNative_GetEUid:

    • System.Runtime.Extensions.Tests: 1 failure
    • System.IO.MemoryMappedFiles.Tests: 2 failures
    • System.IO.FileSystem.Tests: the read-only-file test family

    All report DllNotFoundException: libSystem.Native / dynamic linking not enabled. This means #133773's module-level classification is still insufficient for a direct System.Native P/Invoke whose test-only entrypoint is absent from the prebuilt framework call-helper table. The original runtime browser guard is intentionally retained; the temporary bring-up workaround remains to keep only TestUtilities.dll interpreted while product and test assemblies stay R2R.

    Note

    This update was generated with GitHub Copilot from CI binlog and Helix evidence.

  8. jkotas commented on Sep 19, 2026

    @jkotas
    Member

    TestUtilities.AdminHelpers.IsProcessElevated reaching SystemNative_GetEUid

    Tests that P/Invoke directly into SystemNative_... shims do not represent supported user scenarios. These shims are internal implementation details of the core libraries and are not part of the supported surface. Code outside the core libraries should not P/Invoke them directly.

  9. jkotas commented on Sep 19, 2026

    @jkotas
    Member

    Potential ways to fix this:

  10. lewing commented on Sep 19, 2026

    @lewing
    MemberAuthor

    Root-cause clarification: the remaining failure is specific to running browser per-app ReadyToRun compilation while WasmBuildNative=false.

    #133773's Crossgen2 policy is working as designed: configured modules retain direct PINVOKE_TARGET codegen. The browser app build currently passes framework modules such as System.Native to per-app Crossgen2 unconditionally. However, when native relinking is disabled, the app uses the prebuilt framework call-helper table, which was not generated from the app/test managed closure and therefore does not contain test-only entrypoints such as SystemNative_GetEUid.

    This creates a mismatched contract:

    • Crossgen2 is told that System.Native is directly available for TestUtilities.dll.
    • The actual prebuilt call-helper table exposes only the framework entrypoint subset, not GetEUid from the test assembly closure.
    • RyuJIT can therefore embed a PINVOKE_TARGET fixup for the guarded call, and resolving that fixup fails before normal managed control flow skips the P/Invoke.

    The focused follow-up fix is in browser build integration, not the compiler policy: browser ReadyToRun nested publishes must native-relink so the generated helper table and the per-app Crossgen2 direct-module policy are derived from the same managed closure. Explicit WasmBuildNative=false should remain an incompatible configuration for browser R2R. WASI already performs per-app host/helper relinking and is unaffected.

    A validated prototype preserves direct PINVOKE_TARGET codegen, generates DllImportEntry(SystemNative_GetEUid), and passes the full trimmed System.Runtime.Extensions.Tests suite (8,304 passed, 70 skipped, 0 failed). The current bring-up PR retains a narrow one-site #133614 guard until that follow-up lands.

    Note

    This update was generated with GitHub Copilot from CI binlog, Helix, R2RDump, and focused build-test evidence.

  11. lewing commented on Sep 20, 2026

    @lewing
    MemberAuthor

    Potential ways to fix this:

    I worked around it in the test pr by using a platform guard the linker understand for now. The real cause is building PublishReadyToRun=true with WasmBuildNative=false and reachable pinvoke. #134291 makes that a build error. If we want to support that scenario we need to turn off direct pinvokes for that configuration, I'll open that version as well.

  12. jkotas commented on Sep 20, 2026

    @jkotas
    Member

    The real cause is building PublishReadyToRun=true with WasmBuildNative=false and reachable pinvoke

    It is not some random reachable pinvoke. It is pinvoke into System.Native shim that no user code has a business of invoking. We should be treating tests as user code.

    I think the preferred solution is to update the test so that it does not call System,Native shim. If it is not feasible for some tests, the tests have good reason to PInvoke System.Native shim should declare that they link against native library and that will in turn trigger relinking just for those tests.

  13. jkotas commented on Sep 20, 2026

    @jkotas
    Member

    Interop.Sys.GetEUid PInvokes into SystemNative shim:

    [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetEUid")]
    . SystemNative shims are internal implementation detail of our libraries. It is not valid for user code to PInvoke into them. It is equivalent of private reflection.

    My suggestion would be replace this with pinvoke into libc directly, like what this test does:

    [DllImport("libc", SetLastError = true)]
    internal static extern unsafe uint geteuid();

  14. lewing commented on Sep 20, 2026

    @lewing
    MemberAuthor

    Final direction after maintainer review: this failure should be fixed in the test utility, not by extending browser ReadyToRun product support.

    TestUtilities.AdminHelpers is test/user code and should not call the runtime-owned Interop.Sys.GetEUid shim. Runtime interop shims are implementation details and are not a supported user-code P/Invoke surface. The supported test-side pattern is to declare the platform import directly:

    [DllImport("libc", SetLastError = true)]
    internal static extern unsafe uint geteuid();

    The existing runtime Browser guard remains. On Browser, it prevents the direct libc import from being called; on supported Unix platforms the test utility invokes libc directly. The .NET Framework target keeps the same runtime platform-check form.

    Local validation of this one-site change:

    • TestUtilities builds for both net10.0 and net481.
    • Trimmed CoreCLR browser ReadyToRun System.Runtime.Extensions.Tests: 8,304 passed, 70 skipped, 0 failed.

    The earlier relinking/build-policy investigation was useful for identifying the boundary mismatch, but product changes to support user code calling runtime interop shims are not the intended resolution for this issue. The separate prototype PR was closed.

    Note

    This update was generated with GitHub Copilot based on maintainer guidance and local validation.

  15. lewing commented on Sep 21, 2026

    @lewing
    MemberAuthor

    #133656 fixed the test-side unsupported interop usage by changing TestUtilities.AdminHelpers to P/Invoke libc!geteuid directly, while Browser and WASI return before making the import. The temporary TestUtilities.dll ReadyToRun exclusion was removed, and the trimmed browser R2R System.Runtime.Extensions.Tests validation passed 8,304 tests with zero failures.

    Note

    This closure comment was generated with GitHub Copilot assistance.

  16. locked and limited conversation to collaborators on Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions