From c8daa17e9f4e753537a7069ad9bc27acd32bd29c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 3 Aug 2018 14:33:40 +0200 Subject: Fix crashes when GC'ing internal classes The destroy() method of internal classes tries to reference it's parent class to unregister itself there. This could go wrong if the parent class had been destroyed already and it's associated memory been freed by the GC. Fix this by only freeing actual memory at the end after the sweeping has been done. Change-Id: I85beb4792038d5a1a5708f5897af2c1950f8b8d1 Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/qml/memory') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index d9772e608e..451e7c485d 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -617,21 +617,29 @@ void BlockAllocator::sweep() // qDebug() << "BlockAlloc: sweep"; usedSlotsAfterLastSweep = 0; - auto isFree = [this] (Chunk *c) { + std::vector chunksToFree; + + auto isFree = [this, &chunksToFree] (Chunk *c) { bool isUsed = c->sweep(engine); if (isUsed) { c->sortIntoBins(freeBins, NumBins); usedSlotsAfterLastSweep += c->nUsedSlots(); } else { - Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage); - chunkAllocator->free(c); + chunksToFree.push_back(c); } return !isUsed; }; auto newEnd = std::remove_if(chunks.begin(), chunks.end(), isFree); chunks.erase(newEnd, chunks.end()); + + // only free the chunks at the end to avoid that the sweep() calls indirectly + // access freed memory + for (auto c : chunksToFree) { + Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage); + chunkAllocator->free(c); + } } void BlockAllocator::freeAll() -- cgit v1.2.3