Skip to content

Fix SIP (sweep-in-plan) plan_allocated corruption in process_remaining_regions#131015

Open
cshung wants to merge 1 commit into
dotnet:mainfrom
cshung:fix-sip-plan-allocated
Open

Fix SIP (sweep-in-plan) plan_allocated corruption in process_remaining_regions#131015
cshung wants to merge 1 commit into
dotnet:mainfrom
cshung:fix-sip-plan-allocated

Conversation

@cshung

@cshung cshung commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Fix SIP (sweep-in-plan) plan_allocated corruption in process_remaining_regions

Problem

With the regions GC, setting DOTNET_GCEnableSpecialRegions=1 trips a _DEBUG GC assert shortly after startup (SIGABRT in a Checked build). Two different asserts can fire depending on heap layout:

  • fix_generation_boundsplan_allocated == mem
  • verify_regionsheap_segment_allocated <= heap_segment_reserved (FATAL_GC_ERROR)

Both trace back to a single root cause in process_remaining_regions.

Root cause

When the allocation region for a generation is itself swept-in-plan (SIP), heap_segment_non_sip() skips it and returns a different, empty region. The region chain is not address-ordered, so the returned region may be at a higher or lower address than the skipped SIP region.

The code then assigned that region's plan_allocated directly from the consing pointer:

heap_segment_plan_allocated (current_region) = generation_allocation_pointer (consing_gen);

But the consing pointer belongs to the skipped SIP region, not current_region, so it lies outside current_region's [mem, reserved] range:

  • Below mem → the region can later become gen0's start region, tripping fix_generation_bounds and corrupting gen0 bounds.
  • Above reservedfind_first_valid_region copies plan_allocated into allocated, making allocated > reserved and tripping verify_regions.

Fix

A region reached by skipping a SIP allocation region is empty regardless of address direction, so its plan_allocated is simply its mem. Clamp plan_allocated to mem whenever the consing pointer falls outside [mem, reserved]:

uint8_t* plan_alloc = generation_allocation_pointer (consing_gen);
if ((plan_alloc < heap_segment_mem (current_region)) ||
    (plan_alloc > heap_segment_reserved (current_region)))
{
    plan_alloc = heap_segment_mem (current_region);
}
heap_segment_plan_allocated (current_region) = plan_alloc;

The clamp only triggers on the SIP-skip path (consing pointer out of range), so the default path is unchanged.

Validation

Checked CLR, linux-x64.

  • Functional: 56/56 GC tests that pass by default (GC/API, GC/Scenarios, GC/Coverage) also pass with DOTNET_GCEnableSpecialRegions=1 after the fix. No regressions with the switch off.
  • Stress: DOTNET_GCStress=0xC and 0xF (the latter with a reduced gen0 size to force frequent compacting GCs) across allocation-heavy scenarios (linked-list, jagged-array, server-model, large-object). Results identical with the switch on and off.

…g_regions

When the allocation region for a generation is itself swept-in-plan (SIP),
heap_segment_non_sip() skips it and returns a different, empty region. The
region chain is not address-ordered, so the returned region may be at a higher
or lower address than the skipped SIP region. The code then set that region's
plan_allocated to the consing pointer, which belongs to the skipped SIP region
and therefore lies outside the returned region's [mem, reserved] range - either
below mem or above reserved.

Two asserts fired depending on direction:
 - consing pointer below mem: the region could later become gen0's start
   region, tripping fix_generation_bounds (plan_allocated == mem) and
   corrupting gen0 bounds.
 - consing pointer above reserved: find_first_valid_region copies
   plan_allocated into allocated, making allocated > reserved and tripping
   verify_regions (FATAL_GC_ERROR).

Since a region reached by skipping a SIP allocation region is empty regardless
of address direction, clamp plan_allocated to the region's mem whenever the
consing pointer falls outside [mem, reserved].
Copilot AI review requested due to automatic review settings July 18, 2026 14:24
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Jul 18, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

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 adjusts regions-GC planning in gc_heap::process_remaining_regions to prevent heap_segment_plan_allocated from being set to a pointer that falls outside the selected non-SIP region after SIP skipping, avoiding downstream state corruption and debug asserts.

Changes:

  • Replace direct assignment of heap_segment_plan_allocated(current_region) from the consing allocation pointer with a guarded/clamped assignment.
  • When the consing allocation pointer is outside [heap_segment_mem(current_region), heap_segment_reserved(current_region)], treat the region as empty and set plan_allocated to mem instead.

Copilot AI review requested due to automatic review settings July 18, 2026 16:39

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 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/gc/gcconfig.h
Copilot AI review requested due to automatic review settings July 18, 2026 19:35
@cshung
cshung force-pushed the fix-sip-plan-allocated branch from 8d35fc1 to 56e2bc8 Compare July 18, 2026 19:35

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 1 out of 1 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-GC-coreclr community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants