diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 4c3fcd1b6c03fd..13a3915f7b68cd 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -7574,7 +7574,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: @@ -7589,6 +7589,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 != nullptr) && (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; @@ -13482,7 +13490,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); + 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)); diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h index 9674423d0a46cb..6198eb0fdd05a1 100644 --- a/src/coreclr/gc/gcpriv.h +++ b/src/coreclr/gc/gcpriv.h @@ -2478,7 +2478,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);