[release/10.0] Fix ARM64 interface dispatch cache torn read#126689
Open
github-actions[bot] wants to merge 3 commits intorelease/10.0from
Open
[release/10.0] Fix ARM64 interface dispatch cache torn read#126689github-actions[bot] wants to merge 3 commits intorelease/10.0from
github-actions[bot] wants to merge 3 commits intorelease/10.0from
Conversation
On ARM64, the CHECK_CACHE_ENTRY macro read m_pInstanceType and m_pTargetCode from a cache entry using two separate ldr instructions separated by a control dependency (cmp/bne). ARM64's weak memory model does not order loads across control dependencies, so the hardware can speculatively satisfy the second load (target) before the first (type) commits. When a concurrent thread atomically populates the entry via stlxp/casp (UpdateCacheEntryAtomically), the reader can observe the new m_pInstanceType but the old m_pTargetCode (0), then br to address 0. Fix by using ldp to load both fields in a single instruction (single-copy atomic on FEAT_LSE2 / ARMv8.4+ hardware), plus a cbz guard to catch torn reads on pre-LSE2 hardware where ldp pair atomicity is not architecturally guaranteed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instead of emitting an add instruction per cache entry when the ldp offset exceeds [-512,504], rebase x9 once when the threshold is crossed. This keeps the per-entry probe to a single ldp for all entries in the 32/64 slot stubs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apple ARM64 platforms all have FEAT_LSE2, which makes ldp single-copy atomic for 16-byte aligned pairs. The cbz torn-read guard is unnecessary there. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
|
Tagging subscribers to this area: @agocke |
4 tasks
Member
|
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
davidwrighton
approved these changes
Apr 15, 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 #126346 to release/10.0
/cc @MichalStrehovsky
Customer Impact
Reported by a first party. Torn read in ARM64 interface dispatch can cause a dispatch to null.
Interface dispatch cell is a pair or MethodTable and a code address. If the type of MethodTable matches the type of
this, we call the code address. The pair is written atomically, however the read is not atomic and on ARM64 a torn read can happen, matching the MethodTable, but still seeing a 0 code address.Regression
Not a regression, this bug has existed ever since ARM64 was added to .NET Native for UWP apps in 2017 or so.
Testing
This is a race condition that requires a lot of luck to hit. Testing is "code review" basically.
Risk
The risk is low, instead of loading two pointers individually, we load them together, and add an extra check for the race condition case.
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.