aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/memory
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-08-03 14:33:40 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2018-08-04 09:17:01 +0000
commitc8daa17e9f4e753537a7069ad9bc27acd32bd29c (patch)
treea9a928a479c9b8fee90187c3237d59eaa771ed62 /src/qml/memory
parent895a3f08b4feade6b377c1818a7fff9b0b1052c6 (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.cpp14
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()