Skip to content

JIT: fix GC holes in large stack-target struct block ops#130352

Open
EgorBo wants to merge 1 commit into
dotnet:mainfrom
EgorBo:fix-gc-hole-stack-struct-blockops
Open

JIT: fix GC holes in large stack-target struct block ops#130352
EgorBo wants to merge 1 commit into
dotnet:mainfrom
EgorBo:fix-gc-hole-stack-struct-blockops

Conversation

@EgorBo

@EgorBo EgorBo commented Jul 8, 2026

Copy link
Copy Markdown
Member

Fixes #130286.

For a stack-target struct copy/zero containing GC pointers, LowerCopyBlockStore/LowerInitBlockStore correctly dropped write barriers but, above the unroll threshold, fell back to the managed CORINFO_HELP_MEMCPY (Memmove) / CORINFO_HELP_MEMZERO (ClearWithoutReferences) helpers. Those are GC-safe points, so a GC mid-operation could observe torn GC pointers in the partially-written, GC-reported stack destination and corrupt the heap.

Fix:

  • Copy: only take the "no write barriers" shortcut when the copy is actually unrolled (single non-interruptible region); otherwise stay on the GC-aware CpObj path.
  • Zero: route zeroing of any GC-pointer struct (stack or heap) to the atomic pointer-sized loop instead of the helper.

The copy regression was introduced by #128542.

Verified: SPMI replay -f benchmarks.run clean; asmdiffs limited to large GC structs now using the GC-safe path; before/after codegen confirms MEMCPYBULK_WRITEBARRIER and MEMZERO→zeroing loop.

Copilot AI review requested due to automatic review settings July 8, 2026 13:02
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR JIT lowering to avoid GC-safepoint helper calls for certain large struct block operations involving GC references, preventing GC from observing partially-updated GC-reference stack (and heap) locations. It also adds a JIT regression test to exercise the affected scenarios under GCStress.

Changes:

  • Adjust LowerCopyBlockStore so stack-target GC-pointer struct copies only drop the CpObj path when the copy is actually unrolled into a single non-interruptible region.
  • Adjust LowerInitBlockStore so zeroing GC-pointer-containing structs uses the pointer-sized zeroing loop (instead of helper-based zeroing) for both stack and heap destinations.
  • Add a JIT regression test (Runtime_130286) and wire it into Regression_ro_2.csproj.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/coreclr/jit/lower.cpp Changes lowering decisions for large GC-pointer block copy/zero to avoid managed helper safepoints that can expose GC holes.
src/tests/JIT/Regression/Regression_ro_2.csproj Includes the new JitBlue regression test source file in the regression suite.
src/tests/JIT/Regression/JitBlue/Runtime_130286/Runtime_130286.cs New regression test intended to reproduce the GC-hole scenarios (primarily under GCStress).

Comment thread src/tests/JIT/Regression/JitBlue/Runtime_130286/Runtime_130286.cs
Comment thread src/tests/JIT/Regression/JitBlue/Runtime_130286/Runtime_130286.cs
LowerCopyBlockStore/LowerInitBlockStore dropped write barriers for a
stack destination containing GC pointers (correct) but then, for sizes
above the unroll threshold, fell back to the managed CORINFO_HELP_MEMCPY
(SpanHelpers.Memmove) / CORINFO_HELP_MEMZERO (SpanHelpers.ClearWithoutReferences)
helpers. Those calls are GC-safe points, so a GC triggered mid-operation
could observe torn GC pointers in the partially-written, GC-reported
stack destination and corrupt the heap.

Only take the "no write barriers" copy shortcut when the copy is actually
unrolled into a single non-interruptible region; otherwise stay on the
GC-aware CpObj path. Route zeroing of any GC-pointer struct (stack or
heap) to the atomic pointer-sized zeroing loop instead of the helper.

Copy regression introduced by dotnet#128542.

Fixes dotnet#130286

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 8, 2026 13:11
@EgorBo EgorBo force-pushed the fix-gc-hole-stack-struct-blockops branch from f930e6d to 2df526f Compare July 8, 2026 13:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread src/tests/JIT/Regression/JitBlue/Runtime_130286/Runtime_130286.cs
Comment thread src/tests/JIT/Regression/JitBlue/Runtime_130286/Runtime_130286.cs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash in GC in the System.Globalization test

3 participants