From b240be8b6e39f6c4344cbdd86cc9a214ae353252 Mon Sep 17 00:00:00 2001 From: Peter Sollich Date: Tue, 1 Sep 2020 12:23:21 +0200 Subject: [PATCH] Fix issue 41413 (#41445) Fix the AV issue in GCHeap::ApproxTotalBytesInUse: - The AV is fixed by stopping the iteration when seg1 becomes null - don't count segments that have been decommited - stop iterating when seg1 becomes freeable_soh_segment - this takes care of the case where we have put a segment on the list, but the OS call to decommit hasn't come back. These fixes will still leave a window where the result will be inaccurate. To reduce the chances of an inaccurate result, we try this 3 times. --- src/coreclr/src/gc/gc.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/coreclr/src/gc/gc.cpp b/src/coreclr/src/gc/gc.cpp index adb9fea..8d21e36 100644 --- a/src/coreclr/src/gc/gc.cpp +++ b/src/coreclr/src/gc/gc.cpp @@ -37867,15 +37867,26 @@ size_t GCHeap::ApproxTotalBytesInUse(BOOL small_heap_only) size_t totsize = 0; enter_spin_lock (&pGenGCHeap->gc_lock); - heap_segment* eph_seg = generation_allocation_segment (pGenGCHeap->generation_of (0)); - // Get small block heap size info - totsize = (pGenGCHeap->alloc_allocated - heap_segment_mem (eph_seg)); - heap_segment* seg1 = generation_start_segment (pGenGCHeap->generation_of (max_generation)); - while (seg1 != eph_seg) - { - totsize += heap_segment_allocated (seg1) - - heap_segment_mem (seg1); - seg1 = heap_segment_next (seg1); + // the complication with the following code is that background GC may + // remove the ephemeral segment while we are iterating + // if so, we retry a couple times and ultimately may report a slightly wrong result + for (int tries = 1; tries <= 3; tries++) + { + heap_segment* eph_seg = generation_allocation_segment (pGenGCHeap->generation_of (0)); + // Get small block heap size info + totsize = (pGenGCHeap->alloc_allocated - heap_segment_mem (eph_seg)); + heap_segment* seg1 = generation_start_segment (pGenGCHeap->generation_of (max_generation)); + while ((seg1 != eph_seg) && (seg1 != nullptr) && (seg1 != pGenGCHeap->freeable_soh_segment)) + { + if (!heap_segment_decommitted_p (seg1)) + { + totsize += heap_segment_allocated (seg1) - + heap_segment_mem (seg1); + } + seg1 = heap_segment_next (seg1); + } + if (seg1 == eph_seg) + break; } //discount the fragmentation -- 2.7.4