Skip to content

NativeAOT: missing acquire ordering in SyncTable readers #135173

Description

@EgorBo

Description

SyncTable.Grow publishes the expanded table with Volatile.Write, and the sync index is subsequently published in the object header with Interlocked.CompareExchange.

The lock-free readers use ordinary loads for both the header and s_entries. On ARM64, the independent table load can execute before the header load.

Reproduction Steps

Source-level interleaving; no ARM64 runtime repro yet:

  1. A reader speculatively loads the current 128-entry s_entries.
  2. Another thread grows the table to 256 entries, initializes entry 128, and publishes index 128 in an object's header.
  3. The reader observes the new index while still using the old table snapshot.

Expected behavior

Observing a published sync index also makes the preceding table expansion and entry initialization visible.

Actual behavior

A reader can combine a newly published sync index with an older table snapshot that does not contain that entry.

Configuration

NativeAOT on ARM64; source inspected at 6f1d933.

Other information

Relevant code: object-header read, SyncTable lookup.

Using acquire reads for the object headers on lock-free lookup paths would provide the required ordering. Making only the s_entries load volatile does not order the preceding header read.

Minimal fix: put read barrier here.

Activity

  1. dotnet-policy-service commented on Oct 3, 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.

  2. added a commit that references this issue on Oct 5, 2026
    d148189
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

  • Status
    No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions