Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Sollich <petersol@microsoft.com>2021-06-23 13:09:38 +0300
committerGitHub <noreply@github.com>2021-06-23 13:09:38 +0300
commitea3f4034314481acde910dc571da5006a571dbfa (patch)
tree38d511800d15253c8a9bde43c0a8ae314cd964c1 /src/coreclr/gc
parent97de5c5aff67892ae66fe65d1da971affe59bd76 (diff)
Fix finalizer issue with regions (#54550)
This fixes an issue in Server GC where an item in the finalizer queue became stale due to not being relocated. The problem was that a finalizable object was allocated on one heap, but registered in the finalizer queue of another heap (this is possible due to heap balancing). In CFinalize::UpdatePromotedGenerations, we ask for the generation of an object, and move the object to the correct section of the finalizer queue. In the error case, we obtained the wrong result for the generation of the object because it lived on another heap, and that heap hadn't set the final generation for the region containing the object yet. So we ended up moving the finalizer entry to the section corresponding to gen 2, and missed a relocation of the object occurring in a gen 1 collection afterwards. Fix: It seems best to make sure an object is always registered for finalization on the heap it's allocated from, so the fix simply fetches the heap from the alloc context after the allocation in the case of SOH, or determines it by calling gc_heap::heap_of in the case of LOH and POH. In the case of SOH, I added an assert to ensure that the heap obtained agrees with the result of calling gc_heap::heap_of. I also added some dprintf calls to the finalizer logic to aid in future investigations.
Diffstat (limited to 'src/coreclr/gc')
-rw-r--r--src/coreclr/gc/gc.cpp28
1 files changed, 28 insertions, 0 deletions
diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp
index 6a6c63d1ac2..9cb439e6504 100644
--- a/src/coreclr/gc/gc.cpp
+++ b/src/coreclr/gc/gc.cpp
@@ -42257,6 +42257,15 @@ GCHeap::Alloc(gc_alloc_context* context, size_t size, uint32_t flags REQD_ALIGN_
newAlloc = (Object*) hp->allocate_uoh_object (size + ComputeMaxStructAlignPadLarge(requiredAlignment), flags, gen_num, acontext->alloc_bytes_uoh);
ASSERT(((size_t)newAlloc & 7) == 0);
+#ifdef MULTIPLE_HEAPS
+ if (flags & GC_ALLOC_FINALIZE)
+ {
+ // the heap may have changed due to heap balancing - it's important
+ // to register the object for finalization on the heap it was allocated on
+ hp = gc_heap::heap_of ((uint8_t*)newAlloc);
+ }
+#endif //MULTIPLE_HEAPS
+
#ifdef FEATURE_STRUCTALIGN
newAlloc = (Object*) hp->pad_for_alignment_large ((uint8_t*) newAlloc, requiredAlignment, size);
#endif // FEATURE_STRUCTALIGN
@@ -42276,6 +42285,16 @@ GCHeap::Alloc(gc_alloc_context* context, size_t size, uint32_t flags REQD_ALIGN_
newAlloc = (Object*) hp->allocate (size + ComputeMaxStructAlignPad(requiredAlignment), acontext, flags);
}
+#ifdef MULTIPLE_HEAPS
+ if (flags & GC_ALLOC_FINALIZE)
+ {
+ // the heap may have changed due to heap balancing - it's important
+ // to register the object for finalization on the heap it was allocated on
+ hp = acontext->get_alloc_heap()->pGenGCHeap;
+ assert ((newAlloc == nullptr) || (hp == gc_heap::heap_of ((uint8_t*)newAlloc)));
+ }
+#endif //MULTIPLE_HEAPS
+
#ifdef FEATURE_STRUCTALIGN
newAlloc = (Object*) hp->pad_for_alignment ((uint8_t*) newAlloc, requiredAlignment, size, acontext);
#endif // FEATURE_STRUCTALIGN
@@ -44404,6 +44423,9 @@ CFinalize::RelocateFinalizationData (int gen, gc_heap* hp)
unsigned int Seg = gen_segment (gen);
Object** startIndex = SegQueue (Seg);
+
+ dprintf (3, ("RelocateFinalizationData gen=%d, [%Ix,%Ix[", gen, startIndex, SegQueue (FreeList)));
+
for (Object** po = startIndex; po < SegQueue (FreeList);po++)
{
GCHeap::Relocate (po, &sc);
@@ -44413,6 +44435,8 @@ CFinalize::RelocateFinalizationData (int gen, gc_heap* hp)
void
CFinalize::UpdatePromotedGenerations (int gen, BOOL gen_0_empty_p)
{
+ dprintf(3, ("UpdatePromotedGenerations gen=%d, gen_0_empty_p=%d", gen, gen_0_empty_p));
+
// update the generation fill pointers.
// if gen_0_empty is FALSE, test each object to find out if
// it was promoted or not
@@ -44437,6 +44461,8 @@ CFinalize::UpdatePromotedGenerations (int gen, BOOL gen_0_empty_p)
int new_gen = g_theGCHeap->WhichGeneration (*po);
if (new_gen != i)
{
+ dprintf (3, ("Moving object %Ix->%Ix from gen %d to gen %d", po, *po, i, new_gen));
+
if (new_gen > i)
{
//promotion
@@ -44468,6 +44494,8 @@ CFinalize::GrowArray()
}
memcpy (newArray, m_Array, oldArraySize*sizeof(Object*));
+ dprintf (3, ("Grow finalizer array [%Ix,%Ix[ -> [%Ix,%Ix[", m_Array, m_EndArray, newArray, &m_Array[newArraySize]));
+
//adjust the fill pointers
for (int i = 0; i < FreeList; i++)
{