From b10f50bf1dbb5e4d44752b3924998f0ada852b82 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 3 Oct 2023 12:23:29 +0200 Subject: [PATCH] fixed bad assumption about object destruction state in garbage collector. The assumption was made that every object in the ToDestroy list wasn't destroyed yet. This assumption is wrong in case one object destroys an owned one on its own destruction. Instead this case must be properly dealt with and duplicate destruction be avoided. This happened with the panel sprite sentinel in SW's player object. --- source/common/objects/dobjgc.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/source/common/objects/dobjgc.cpp b/source/common/objects/dobjgc.cpp index 64f36a129..d388e4836 100644 --- a/source/common/objects/dobjgc.cpp +++ b/source/common/objects/dobjgc.cpp @@ -287,11 +287,22 @@ static size_t DestroyObjects(size_t count) while ((curr = ToDestroy) != nullptr && count-- > 0) { - assert(!(curr->ObjectFlags & OF_EuthanizeMe)); - bytes_destroyed += curr->GetClass()->Size + GCDESTROYCOST; - ToDestroy = curr->GCNext; - curr->GCNext = nullptr; - curr->Destroy(); + // Note that we cannot assume here that the object has not yet been destroyed. + // If destruction happens as the result of another object's destruction we may + // get entries here that have been destroyed already if that owning object was + // first in the list. + if (!(curr->ObjectFlags & OF_EuthanizeMe)) + { + bytes_destroyed += curr->GetClass()->Size + GCDESTROYCOST; + ToDestroy = curr->GCNext; + curr->GCNext = nullptr; + curr->Destroy(); + } + else + { + ToDestroy = curr->GCNext; + curr->GCNext = nullptr; + } } return bytes_destroyed; }