From 3dfeb5c7b06d3758210c6d79783757e41cab941ac37b87ca1f3f325e52a2e19a Mon Sep 17 00:00:00 2001 From: Dominique Leuenberger Date: Tue, 16 Feb 2016 08:27:41 +0000 Subject: [PATCH] Accepting request 359195 from KDE:Qt5 1 OBS-URL: https://build.opensuse.org/request/show/359195 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/libqt5-qtdeclarative?expand=0&rev=28 --- ...d-memory-leak-in-qsgbatchrenderer-re.patch | 43 ++++++ Refactor-FxViewItem-releasing-code.patch | 62 ++++++++ libqt5-qtdeclarative.changes | 15 +- libqt5-qtdeclarative.spec | 11 +- ...bleItems-list-after-model-insertions.patch | 141 ++++++++++++++++++ 5 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 0001-scene-graph-fixed-memory-leak-in-qsgbatchrenderer-re.patch create mode 100644 Refactor-FxViewItem-releasing-code.patch create mode 100644 sanitize-visibleItems-list-after-model-insertions.patch diff --git a/0001-scene-graph-fixed-memory-leak-in-qsgbatchrenderer-re.patch b/0001-scene-graph-fixed-memory-leak-in-qsgbatchrenderer-re.patch new file mode 100644 index 0000000..7076177 --- /dev/null +++ b/0001-scene-graph-fixed-memory-leak-in-qsgbatchrenderer-re.patch @@ -0,0 +1,43 @@ +From 19f54b2d2539171f682bcf32cdc7983294355e02 Mon Sep 17 00:00:00 2001 +From: Martin Banky +Date: Thu, 15 Oct 2015 23:07:32 -0700 +Subject: [PATCH] Scene Graph: Fixed memory leak in + QSGBatchRenderer::Renderer::map() + +In the uncommon case (m_context->hasBrokenIndexBufferObjects() +|| m_visualizeMode != VisualizeNothing) of mapping a buffer, malloc is +called without first freeing the previous malloc. + +Regression was introduced with: + qt5 commit: 9347499e78f03710eaf24af3c1e7ac650d0ef81d + qtdeclarative commit: a371bac3fba73f92aaa63a68d8ab1ae81a1d1031 + +[ChangeLog][QtQuick][Scene Graph] Fixed memory leak in +QSGBatchRenderer::Renderer::map() + +Task-number: QTBUG-48799 +Change-Id: I5ef4b7301d390463845aeb192851f86655962499 +--- + src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +index 60ada14..75923d7 100644 +--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp ++++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +@@ -902,7 +902,11 @@ void Renderer::map(Buffer *buffer, int byteSize, bool isIndexBuf) + pool.resize(byteSize); + buffer->data = pool.data(); + } else { +- buffer->data = (char *) malloc(byteSize); ++ if (buffer->size != byteSize) { ++ if (buffer->data) ++ free(buffer->data); ++ buffer->data = (char *) malloc(byteSize); ++ } + } + buffer->size = byteSize; + +-- +2.6.0 + diff --git a/Refactor-FxViewItem-releasing-code.patch b/Refactor-FxViewItem-releasing-code.patch new file mode 100644 index 0000000..0f1cdef --- /dev/null +++ b/Refactor-FxViewItem-releasing-code.patch @@ -0,0 +1,62 @@ +diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp +index 20b6dd5..96759b1 100644 +--- a/src/quick/items/qquicklistview.cpp ++++ b/src/quick/items/qquicklistview.cpp +@@ -81,6 +81,8 @@ public: + bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) Q_DECL_OVERRIDE; + void visibleItemsChanged() Q_DECL_OVERRIDE; + ++ void removeItem(FxViewItem *item); ++ + FxViewItem *newViewItem(int index, QQuickItem *item) Q_DECL_OVERRIDE; + void initializeViewItem(FxViewItem *item) Q_DECL_OVERRIDE; + bool releaseItem(FxViewItem *item) Q_DECL_OVERRIDE; +@@ -686,6 +688,18 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal + return changed; + } + ++void QQuickListViewPrivate::removeItem(FxViewItem *item) ++{ ++ if (item->transitionScheduledOrRunning()) { ++ qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << item->item->objectName(); ++ item->releaseAfterTransition = true; ++ releasePendingTransition.append(item); ++ } else { ++ qCDebug(lcItemViewDelegateLifecycle) << "\treleasing stationary item" << item->index << item->item->objectName(); ++ releaseItem(item); ++ } ++} ++ + bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) + { + FxViewItem *item = 0; +@@ -708,13 +722,7 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer + if (item->index != -1) + visibleIndex++; + visibleItems.removeAt(index); +- if (item->transitionScheduledOrRunning()) { +- qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << item->item->objectName(); +- item->releaseAfterTransition = true; +- releasePendingTransition.append(item); +- } else { +- releaseItem(item); +- } ++ removeItem(item); + if (index == 0) + break; + item = visibleItems.at(--index); +@@ -730,13 +738,7 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer + break; + qCDebug(lcItemViewDelegateLifecycle) << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position() << item->item->objectName(); + visibleItems.removeLast(); +- if (item->transitionScheduledOrRunning()) { +- qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item" << item->index << item->item->objectName(); +- item->releaseAfterTransition = true; +- releasePendingTransition.append(item); +- } else { +- releaseItem(item); +- } ++ removeItem(item); + changed = true; + } + diff --git a/libqt5-qtdeclarative.changes b/libqt5-qtdeclarative.changes index 3e32f0c..344bfb9 100644 --- a/libqt5-qtdeclarative.changes +++ b/libqt5-qtdeclarative.changes @@ -1,7 +1,20 @@ +------------------------------------------------------------------- +Sat Feb 13 01:54:31 UTC 2016 - matz@suse.com + +- Add 0001-scene-graph-fixed-memory-leak-in-qsgbatchrenderer-re.patch + fixing a memory leak, QTBUG#48799. + +------------------------------------------------------------------- +Mon Feb 1 17:00:44 UTC 2016 - hrvoje.senjan@gmail.com + +- Added sanitize-visibleItems-list-after-model-insertions.patch + and Refactor-FxViewItem-releasing-code.patch to help in resolving + kde#352055 and qtbug#48870 + ------------------------------------------------------------------- Fri Oct 16 20:22:26 UTC 2015 - hrvoje.senjan@gmail.com -- Update to 5.5.1 +- Update to 5.5.1 (boo#954149) * For more details please see: http://blog.qt.io/blog/2015/10/15/qt-5-5-1-released/ diff --git a/libqt5-qtdeclarative.spec b/libqt5-qtdeclarative.spec index b2df60a..d62cb13 100644 --- a/libqt5-qtdeclarative.spec +++ b/libqt5-qtdeclarative.spec @@ -1,7 +1,7 @@ # # spec file for package libqt5-qtdeclarative # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -35,6 +35,12 @@ Source: %{tar_version}.tar.xz Source1: baselibs.conf # PATCH-FIX-OPENSUSE sse2_nojit.patch -- enable JIT and sse2 only on sse2 case Patch100: sse2_nojit.patch +# PATCH-FIX-UPSTREAM Refactor-FxViewItem-releasing-code.patch +Patch101: Refactor-FxViewItem-releasing-code.patch +# PATCH-FIX-UPSTREAM sanitize-visibleItems-list-after-model-insertions.patch +Patch102: sanitize-visibleItems-list-after-model-insertions.patch +# PATCH-FIX-UPSTREAM QTBUG-48799 +Patch103: 0001-scene-graph-fixed-memory-leak-in-qsgbatchrenderer-re.patch BuildRequires: fdupes BuildRequires: libQt5Core-private-headers-devel >= %{version} BuildRequires: libQt5Gui-private-headers-devel >= %{version} @@ -72,6 +78,9 @@ handling. %prep %setup -q -n qtdeclarative-opensource-src-%{real_version} %patch100 -p1 +%patch101 -p1 +%patch102 -p1 +%patch103 -p1 %package -n %libname Summary: Qt 5 Declarative Library diff --git a/sanitize-visibleItems-list-after-model-insertions.patch b/sanitize-visibleItems-list-after-model-insertions.patch new file mode 100644 index 0000000..76b5a4d --- /dev/null +++ b/sanitize-visibleItems-list-after-model-insertions.patch @@ -0,0 +1,141 @@ +From be1ef858f44e1523ba264520a0361981cf9b37c6 Mon Sep 17 00:00:00 2001 +From: Gabriel de Dietrich +Date: Wed, 25 Nov 2015 12:14:52 -0800 +Subject: [PATCH] ListView: Sanitize visibleItems list after model insertions + +In QQuickListViewPrivate::applyInsertionChange(), we update the +visibleItems list by first shifting the currently visible items +and then we add as many items as the model was added and at the +right position. We do this in such a way that we won't create +items that will not be visible right away (and may be deleted +right after by removeNonVisibleItems()). However, this may leave +gaps in the item index sequence, and QQuickListView doesn't always +recover gracefully from it. + +The purpose of this patch is to make sure those gaps are cleared +right after inserting the new items. Since the insertions can happen +in two different places (either before or after the first visible +item) we need to update the visibleItems list accordingly. The way +we sanitize visibleItems is by removing those items that lie beyond +a possible index gap. If insertion happens before the first visible +item, we'll remove all those items before the insertion point. If +the insertion happens after the first visible item, we'll remove the +items after the insertion point. + +Besides that, the logic for inserting before the visible position was +wrong. As items are inserted bottom-up in that case, the insertion +would start by just accounting for the item's size until the condition + + pos > from && insertionIdx < visibleIndex + +would become false only because 'pos' would be small enough. After +that, the next loop run would start adding items before the 'from' +position, which is wrong. Our fix is to move the condition outside +the loop if the insertion index will be before the visible index +and just account for the items' size in that case. Otherwise, the +insertion happens as usual until pos < from. + +Change-Id: I35767cf6e9737bea1fe7677e580245fc7172710c +Task-number: QTBUG-48870 +--- + src/quick/items/qquicklistview.cpp | 59 ++++++++++++++++++---- + 1 files changed, 59 insertions(+), 4 deletions(-) + +diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp +index c7df855..9f53586 100644 +--- a/src/quick/items/qquicklistview.cpp ++++ b/src/quick/items/qquicklistview.cpp +@@ -3097,12 +3097,13 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch + int i = 0; + qreal from = tempPos - displayMarginBeginning - buffer; + +- for (i = count-1; i >= 0; --i) { +- if (pos > from && insertionIdx < visibleIndex) { +- // item won't be visible, just note the size for repositioning +- insertResult->sizeChangesBeforeVisiblePos += averageSize + spacing; +- pos -= averageSize + spacing; +- } else { ++ if (insertionIdx < visibleIndex) { ++ if (pos >= from) { ++ // items won't be visible, just note the size for repositioning ++ insertResult->sizeChangesBeforeVisiblePos += count * (averageSize + spacing); ++ } ++ } else { ++ for (i = count-1; i >= 0 && pos >= from; --i) { + // item is before first visible e.g. in cache buffer + FxViewItem *item = 0; + if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i)))) +@@ -3117,17 +3118,33 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch + insertResult->changedFirstItem = true; + if (!change.isMove()) { + addedItems->append(item); +- item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true); ++ if (transitioner) ++ item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true); ++ else ++ static_cast(item)->setPosition(pos, true); + } + insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing; + pos -= item->size() + spacing; ++ index++; ++ } ++ } ++ ++ int firstOkIdx = -1; ++ for (int i = 0; i <= insertionIdx && i < visibleItems.count() - 1; i++) { ++ if (visibleItems.at(i)->index + 1 != visibleItems.at(i + 1)->index) { ++ firstOkIdx = i + 1; ++ break; + } +- index++; + } ++ for (int i = 0; i < firstOkIdx; i++) { ++ FxViewItem *nvItem = visibleItems.takeFirst(); ++ addedItems->removeOne(nvItem); ++ removeItem(nvItem); ++ } ++ + } else { +- int i = 0; + qreal to = buffer + displayMarginEnd + tempPos + size(); +- for (i = 0; i < count && pos <= to; ++i) { ++ for (int i = 0; i < count && pos <= to; ++i) { + FxViewItem *item = 0; + if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i)))) + item->index = modelIndex + i; +@@ -3147,12 +3164,32 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch + movingIntoView->append(MovedItem(item, change.moveKey(item->index))); + } else { + addedItems->append(item); +- item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true); ++ if (transitioner) ++ item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true); ++ else ++ static_cast(item)->setPosition(pos, true); + } + insertResult->sizeChangesAfterVisiblePos += item->size() + spacing; + pos += item->size() + spacing; + ++index; + } ++ ++ if (0 < index && index < visibleItems.count()) { ++ FxViewItem *prevItem = visibleItems.at(index - 1); ++ FxViewItem *item = visibleItems.at(index); ++ if (prevItem->index != item->index - 1) { ++ int i = index; ++ qreal prevPos = prevItem->position(); ++ while (i < visibleItems.count()) { ++ FxListItemSG *nvItem = static_cast(visibleItems.takeLast()); ++ insertResult->sizeChangesAfterVisiblePos -= nvItem->size() + spacing; ++ addedItems->removeOne(nvItem); ++ if (nvItem->transitionScheduledOrRunning()) ++ nvItem->setPosition(prevPos + (nvItem->index - prevItem->index) * averageSize); ++ removeItem(nvItem); ++ } ++ } ++ } + } + + updateVisibleIndex(); +-- +2.6.2.2.g1b5ffa3