[release/10.0] Fix race condition in cached interface dispatch stubs#126690
Open
github-actions[bot] wants to merge 2 commits intorelease/10.0from
Open
[release/10.0] Fix race condition in cached interface dispatch stubs#126690github-actions[bot] wants to merge 2 commits intorelease/10.0from
github-actions[bot] wants to merge 2 commits intorelease/10.0from
Conversation
The dispatch cell has two fields (m_pStub, m_pCache) that are updated atomically together but read non-atomically by the caller and stub. A race during cache growth can cause a stub to read a stale m_pCache that doesn't match the expected cache size, reading past the cache allocation into unmapped memory. Add validation in each RhpInterfaceDispatchN stub: after loading m_pCache, check that the low 2 bits are zero (not an encoded interface pointer) and that m_cEntries matches the expected entry count. On mismatch, re-dispatch through the indirection cell to retry with the current stub and cache pair. Fix covers all architectures: amd64, arm64, arm, i386, loongarch64, and riscv64 (both MASM and GAS variants where applicable). Also adds OFFSETOF__InterfaceDispatchCache__m_cEntries and IDC_CACHE_POINTER_MASK constants to CoreCLR's asmconstants.h for amd64 and arm64 (NativeAOT already had them via AsmOffsets.h). Fixes #121632 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The same race that affects RhpInterfaceDispatchN stubs can also affect RhpVTableOffsetDispatch (CoreCLR-only): during the initial cell transition from RhpInitialInterfaceDispatch to RhpVTableOffsetDispatch, a concurrent reader could see the new stub but a stale m_pCache (encoded interface pointer with low bits set) instead of the expected vtable offset. Save the cell address in a scratch register (r10 on amd64, x12 on arm64) before overwriting it with m_pCache, then validate the low bits. On mismatch, re-dispatch through the indirection cell. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
|
Tagging subscribers to this area: @agocke |
This was referenced Apr 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport of #126471 to release/10.0
/cc @MichalStrehovsky
Customer Impact
#121632. Race condition in interface dispatch can cause a crash. Somewhat related to #126689.
The cached interface dispatch scheme operates with a cache that has a method pointer in the first field and method-pointer-specific data in the rest of the cache cell. The interface call sequence is:
A race condition window exists when the dispatch cell is updated. We can end up with a mismatch where the method we just called expects a different shape of the cache (the cache is a for a different function).
Regression
Not a regression, this bug existed since first release of .NET Native for UWP in 2015 or so.
Testing
This is a race condition that requires a lot of luck to hit. Testing is "code review" basically.
Risk
IMPORTANT: If this backport is for a servicing release, please verify that:
release/X.0-staging, notrelease/X.0.release/X.0(no-stagingsuffix).Package authoring no longer needed in .NET 9
IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.