diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-08-03 14:33:40 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2018-08-04 09:17:01 +0000 |
commit | c8daa17e9f4e753537a7069ad9bc27acd32bd29c (patch) | |
tree | a9a928a479c9b8fee90187c3237d59eaa771ed62 /src/qml/memory | |
parent | 895a3f08b4feade6b377c1818a7fff9b0b1052c6 (diff) |
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 <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/memory')
-rw-r--r-- | src/qml/memory/qv4mm.cpp | 14 |
1 files changed, 11 insertions, 3 deletions
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<Chunk *> 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() |