Skip to content

.NET 11 rc1 SDK crashes on RHEL8 arm64 #133675

Closed

Description

@tmds

Running the .NET 11 rc1 SDK crashes on RHEL 8 arm64.

dotnet --info causes SIGSEGV.

Backtrace shows that the 4th arg of hostfxr_resolve_sdk2 is a thunk that loads a NULL function pointer.

Probably the offset calculation isn't working properly due to the RHEL8 arm64 64KB page size.

cc @jkotas @janvorli @MichalStrehovsky @VSadov @omajid

Activity

  1. added
    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
    on Sep 11, 2026
  2. dotnet-policy-service commented on Sep 11, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
    See info in area-owners.md if you want to be subscribed.

  3. EgorBo commented on Sep 11, 2026

    @EgorBo
    Member

    https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp#L218

    Looks like this instruction assumes it can encode page size into the reloc imm, which is not true for 64kb

    Image

    This seems to fix it (tested on a linux-arm64 ubuntu with 64kb page, see PAGESIZE on the screen).

    Leaving it for VM people to confirm/investigate other places if any since apparently we don't test 64kb pages on CI and there might be more places.

  4. EgorBo commented on Sep 11, 2026

    @EgorBo
    Member

    At very least, there seem to be an issue in GC as well:

    Default 4MiB regions have 32KiB mark bitmaps, so adjacent regions share an OS page. 
    Commit accounting double-counts that page, while decommit accounting fails to subtract it, causing the assertion.
    
    With temporary  DOTNET_GCRegionSize=800000  (hexadecimal 8MiB), the full normal Checked CoreCLR suite completed
    

    propsed fix:

    size_t min_gc_region_size =
        OS_PAGE_SIZE * (mark_word_size / sizeof(uint32_t));
  5. EgorBo commented on Sep 11, 2026

    @EgorBo
    Member

    A few more findings from the same 64KiB-page machine, separate from the thunk and GC bitmap-accounting issues above:

    1. GC pre-OOM reclamation has another 4KiB assumption. move_aged_regions compares a region's committed size against GC_PAGE_SIZE (4096), whereas its initial commitment is an OS page. Under LLDB, a free region with 65536 committed bytes was skipped by this special pre-OOM reclamation path. This reproduces even with the 8MiB-region workaround. The comparison should use the actual initial commitment.

    2. Empty memory-mapped views leak one OS-page mapping on Unix. CreateView maps one byte for an empty view but records a native length of zero. Disposal then calls munmap(address, 0), which fails. Reproduced against the locally built libraries: all 32 disposed empty views remained mapped. This isn't exclusive to 64KiB pages, but the leaked virtual mapping is 64KiB per view here, rather than 4KiB.

    3. Potential loss of file-backed loading for bundled ReadyToRun assemblies. The bundler uses 4KiB alignment on ARM64, while PAL's header mapping and section-overlap check can reject an image at a non-64KiB-aligned bundle offset on this host. That can lead to a Checked assertion or a Release fallback to a private image copy. This is a source-analysis finding; the skewed single-file case still needs an end-to-end repro.

  6. JulieLeeMSFT commented on Sep 11, 2026

    @JulieLeeMSFT
    Member
  7. added this to the 11.0.0 milestone on Sep 11, 2026
  8. removed
    untriagedNew issue has not been triaged by the area owner
    on Sep 11, 2026
  9. added and removed
    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
    on Sep 11, 2026
  10. dotnet-policy-service commented on Sep 11, 2026

    @dotnet-policy-service
    Contributor

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

  11. 4 remaining items

  12. jkotas commented on Sep 11, 2026

    @jkotas
    Member

    @tmds Can you validate that the fix proposed by @EgorBo above fixes the problem?

  13. dotnet-policy-service commented on Sep 11, 2026

    @dotnet-policy-service
    Contributor

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

  14. tmds commented on Sep 14, 2026

    @tmds
    MemberAuthor

    @tmds Can you validate that the fix proposed by @EgorBo above fixes the problem?

    I will try to do it today.

  15. tmds commented on Sep 14, 2026

    @tmds
    MemberAuthor

    I validated the fix. I did it by creating a separate reproducer for the issue because my source-built .NET 11 SDK seem to be taking a different execution path which doesn't crash. With the reproducer, the issue also occurred on the source-built SDK. With @EgorBo's patch, it no longer does.

    Thanks @EgorBo!

    Copy-pastable patch (for anyone that wants it):

    diff --git a/src/runtime/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp b/src/runtime/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp
    index 9e00ebeded19..8bc636b2ba05 100644
    --- a/src/runtime/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp
    +++ b/src/runtime/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp
    @@ -215,7 +215,7 @@ EXTERN_C HRESULT QCALLTYPE RhAllocateThunksMapping(void** ppThunksSection)
     #elif TARGET_ARM64
     
                 //adr      xip0, <delta PC to thunk data address>
    -            //ldr      xip1, [xip0, <delta to get to last qword in data page>]
    +            //ldr      xip1, <delta PC to last qword in data page>
                 //br       xip1
                 //brk      0xf000 //Stubs need to be 16 byte aligned therefore we fill with a break here
     
    @@ -223,7 +223,10 @@ EXTERN_C HRESULT QCALLTYPE RhAllocateThunksMapping(void** ppThunksSection)
                 *((uint32_t*)pCurrentThunkAddress) = 0x10000010 | (((delta & 0x03) << 29) | (((delta & 0x1FFFFC) >> 2) << 5));
                 pCurrentThunkAddress += 4;
     
    -            *((uint32_t*)pCurrentThunkAddress) = 0xF9400211 | (((uint32_t)((OS_PAGE_SIZE - POINTER_SIZE - (i * POINTER_SIZE * 2)) / 8) << 10));
    +            // Use a PC-relative load: the unsigned offset from xip0 cannot span a 64 KB page.
    +            delta = (int)(pDataBlockAddress + OS_PAGE_SIZE - POINTER_SIZE - pCurrentThunkAddress);
    +            ASSERT((-0x100000 <= delta) && (delta < 0x100000) && ((delta & 3) == 0));
    +            *((uint32_t*)pCurrentThunkAddress) = 0x58000011 | (((delta & 0x1FFFFC) >> 2) << 5);
                 pCurrentThunkAddress += 4;
     
                 *((uint32_t*)pCurrentThunkAddress) = 0xD61F0220;
    
  16. linked a pull request that will close this issueFix .NET 11 rc1 SDK crash on RHEL8 arm64 #133887on Sep 14, 2026
  17. tmds commented on Sep 15, 2026

    @tmds
    MemberAuthor

    since apparently we don't test 64kb pages on CI

    Could such a config be added to the CI?

  18. jkotas commented on Sep 15, 2026

    @jkotas
    Member

    Could such a config be added to the CI?

    Opened #133944

  19. added a commit that references this issue on Sep 17, 2026
    8e45f4d
  20. added a commit that references this issue on Sep 18, 2026
    bd0eebf
  21. locked and limited conversation to collaborators on Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

  • Status
    No status

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions