From 5fe272f68a59724022f545ac15c2f7d758c5ea86 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Tue, 25 Sep 2012 23:50:01 +0200 Subject: QSqlTableModel: fix segfault when overriding selectRow() The STL-style iteration over the cache in submitAll() assumed the iterator would remain valid until reaching cache.end(). This failed to consider that virtual selectRow() might be overridden so that it removes rows from the cache. For example, it might call select() which would empty the cache. The new approach checks at each iteration whether the row is still in the cache. Using foreach here is justified by its fitness for purpose and readability. New test included. Change-Id: Idee8807ede239c3ba56ff1604574c49f47385ad2 Reviewed-by: David Faure (fixes for KDE) --- src/sql/models/qsqltablemodel.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'src/sql/models/qsqltablemodel.cpp') diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index 95cd0d80d2..56838a4e8f 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -718,20 +718,25 @@ bool QSqlTableModel::submitAll() bool success = true; - for (QSqlTableModelPrivate::CacheMap::Iterator it = d->cache.begin(); - it != d->cache.end(); ++it) { - if (it.value().submitted()) + foreach (int row, d->cache.keys()) { + // be sure cache *still* contains the row since overriden selectRow() could have called select() + QSqlTableModelPrivate::CacheMap::iterator it = d->cache.find(row); + if (it == d->cache.end()) continue; - switch (it.value().op()) { + QSqlTableModelPrivate::ModifiedRow &mrow = it.value(); + if (mrow.submitted()) + continue; + + switch (mrow.op()) { case QSqlTableModelPrivate::Insert: - success = insertRowIntoTable(it.value().rec()); + success = insertRowIntoTable(mrow.rec()); break; case QSqlTableModelPrivate::Update: - success = updateRowInTable(it.key(), it.value().rec()); + success = updateRowInTable(row, mrow.rec()); break; case QSqlTableModelPrivate::Delete: - success = deleteRowFromTable(it.key()); + success = deleteRowFromTable(row); break; case QSqlTableModelPrivate::None: Q_ASSERT_X(false, "QSqlTableModel::submitAll()", "Invalid cache operation"); @@ -739,9 +744,9 @@ bool QSqlTableModel::submitAll() } if (success) { - it.value().setSubmitted(); + mrow.setSubmitted(); if (d->strategy != OnManualSubmit) - success = selectRow(it.key()); + success = selectRow(row); } if (!success) -- cgit v1.2.3