From adc1262e985e514268aa1c5ea3e582505f739244 Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Tue, 14 Apr 2026 17:32:05 -0700 Subject: [PATCH 1/3] fix for largepages with agressive decommit --- src/coreclr/gc/regions_segments.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/coreclr/gc/regions_segments.cpp b/src/coreclr/gc/regions_segments.cpp index 1518ef8c0b8e47..b1fac254b28af1 100644 --- a/src/coreclr/gc/regions_segments.cpp +++ b/src/coreclr/gc/regions_segments.cpp @@ -1835,6 +1835,12 @@ void gc_heap::distribute_free_regions() if (end_space > 0) { virtual_decommit (aligned_allocated, end_space, gen_to_oh (i), hn); + // Large pages: virtual_decommit is a no-op so the memory retains stale data. + // Clear it before lowering used, matching what decommit_region does. + if (use_large_pages_p && (heap_segment_used (region) > aligned_allocated)) + { + memclr (aligned_allocated, heap_segment_used (region) - aligned_allocated); + } heap_segment_committed (region) = aligned_allocated; heap_segment_used (region) = min (heap_segment_used (region), heap_segment_committed (region)); assert (heap_segment_committed (region) > heap_segment_mem (region)); From 3a643c577051025af348cacfdb9942074192910a Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Wed, 15 Apr 2026 07:27:02 -0700 Subject: [PATCH 2/3] CR Feedback --- src/coreclr/gc/gcpriv.h | 2 +- src/coreclr/gc/memory.cpp | 10 +++++++++- src/coreclr/gc/regions_segments.cpp | 8 +------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h index 00d36794a6e834..501c93d154ad23 100644 --- a/src/coreclr/gc/gcpriv.h +++ b/src/coreclr/gc/gcpriv.h @@ -2485,7 +2485,7 @@ class gc_heap PER_HEAP_METHOD void decommit_heap_segment (heap_segment* seg); PER_HEAP_ISOLATED_METHOD bool virtual_alloc_commit_for_heap (void* addr, size_t size, int h_number); PER_HEAP_ISOLATED_METHOD bool virtual_commit (void* address, size_t size, int bucket, int h_number=-1, bool* hard_limit_exceeded_p=NULL); - PER_HEAP_ISOLATED_METHOD bool virtual_decommit (void* address, size_t size, int bucket, int h_number=-1); + PER_HEAP_ISOLATED_METHOD bool virtual_decommit (void* address, size_t size, int bucket, int h_number=-1, void* end_of_data=nullptr); PER_HEAP_ISOLATED_METHOD void reduce_committed_bytes (void* address, size_t size, int bucket, int h_number, bool decommit_succeeded_p); friend void destroy_card_table (uint32_t*); PER_HEAP_ISOLATED_METHOD void destroy_card_table_helper (uint32_t* c_table); diff --git a/src/coreclr/gc/memory.cpp b/src/coreclr/gc/memory.cpp index cd533a16e8036d..17eb222595e9f5 100644 --- a/src/coreclr/gc/memory.cpp +++ b/src/coreclr/gc/memory.cpp @@ -161,7 +161,7 @@ void gc_heap::reduce_committed_bytes (void* address, size_t size, int bucket, in } } -bool gc_heap::virtual_decommit (void* address, size_t size, int bucket, int h_number) +bool gc_heap::virtual_decommit (void* address, size_t size, int bucket, int h_number, void* end_of_data) { /** * Here are all possible cases for the decommits: @@ -173,6 +173,14 @@ bool gc_heap::virtual_decommit (void* address, size_t size, int bucket, int h_nu bool decommit_succeeded_p = ((bucket != recorded_committed_bookkeeping_bucket) && use_large_pages_p) ? true : GCToOSInterface::VirtualDecommit (address, size); + // Large pages: the decommit above is a no-op so memory retains stale data. + // Clear up to end_of_data if the caller provided it so that the heap never + // observes leftover object references after the region is reused. + if (use_large_pages_p && (end_of_data > address)) + { + memclr ((uint8_t*)address, (uint8_t*)end_of_data - (uint8_t*)address); + } + reduce_committed_bytes (address, size, bucket, h_number, decommit_succeeded_p); return decommit_succeeded_p; diff --git a/src/coreclr/gc/regions_segments.cpp b/src/coreclr/gc/regions_segments.cpp index b1fac254b28af1..ee51642d5afd8a 100644 --- a/src/coreclr/gc/regions_segments.cpp +++ b/src/coreclr/gc/regions_segments.cpp @@ -1834,13 +1834,7 @@ void gc_heap::distribute_free_regions() size_t end_space = heap_segment_committed (region) - aligned_allocated; if (end_space > 0) { - virtual_decommit (aligned_allocated, end_space, gen_to_oh (i), hn); - // Large pages: virtual_decommit is a no-op so the memory retains stale data. - // Clear it before lowering used, matching what decommit_region does. - if (use_large_pages_p && (heap_segment_used (region) > aligned_allocated)) - { - memclr (aligned_allocated, heap_segment_used (region) - aligned_allocated); - } + virtual_decommit (aligned_allocated, end_space, gen_to_oh (i), hn, heap_segment_used (region)); heap_segment_committed (region) = aligned_allocated; heap_segment_used (region) = min (heap_segment_used (region), heap_segment_committed (region)); assert (heap_segment_committed (region) > heap_segment_mem (region)); From 009ad4dcedae9d5c024e3063db2c7cbf651e8326 Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Wed, 15 Apr 2026 07:49:08 -0700 Subject: [PATCH 3/3] adding null check for clarity --- src/coreclr/gc/memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/gc/memory.cpp b/src/coreclr/gc/memory.cpp index 17eb222595e9f5..78a162e06bb34c 100644 --- a/src/coreclr/gc/memory.cpp +++ b/src/coreclr/gc/memory.cpp @@ -176,7 +176,7 @@ bool gc_heap::virtual_decommit (void* address, size_t size, int bucket, int h_nu // Large pages: the decommit above is a no-op so memory retains stale data. // Clear up to end_of_data if the caller provided it so that the heap never // observes leftover object references after the region is reused. - if (use_large_pages_p && (end_of_data > address)) + if (use_large_pages_p && (end_of_data != nullptr) && (end_of_data > address)) { memclr ((uint8_t*)address, (uint8_t*)end_of_data - (uint8_t*)address); }