From d24aa28b4c3841ecd35401c7c3064e68f7ec7589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Martsum?= Date: Tue, 5 Mar 2013 16:23:20 +0100 Subject: QMap - check if iterator arguments are valid (in debugmode) This patch adds a debug-tests in erase, insert (with hint) and insertMulti (with hint) that ensures the iterator-argument is valid (and e.g not from another map) Change-Id: I7920131bc9712543183cabf13c7603bd0e12880d Reviewed-by: Thiago Macieira --- src/corelib/tools/qmap.h | 18 +++++ tests/manual/corelib/tools/qmap/main.cpp | 111 +++++++++++++++++++++++++++ tests/manual/corelib/tools/qmap/qmaptest.pro | 2 + 3 files changed, 131 insertions(+) create mode 100644 tests/manual/corelib/tools/qmap/main.cpp create mode 100644 tests/manual/corelib/tools/qmap/qmaptest.pro diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 449fcbca0a..8c15afd9f8 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -557,6 +557,18 @@ public: private: void detach_helper(); + bool isValidIterator(const const_iterator &ci) const + { +#if defined(QT_DEBUG) && !defined(Q_MAP_NO_ITERATOR_DEBUG) + const QMapNodeBase *n = ci.i; + while (n->parent()) + n = n->parent(); + return n->left == d->root(); +#else + Q_UNUSED(ci); + return true; +#endif + } }; template @@ -670,6 +682,8 @@ typename QMap::iterator QMap::insert(const_iterator pos, const K if (d->ref.isShared()) return this->insert(akey, avalue); + Q_ASSERT_X(isValidIterator(pos), "QMap::insert", "The specified const_iterator argument 'it' is invalid"); + if (pos == constEnd()) { // Hint is that the Node is larger than (or equal to) the largest value. Node *n = static_cast(pos.i->left); @@ -753,6 +767,8 @@ typename QMap::iterator QMap::insertMulti(const_iterator pos, co if (d->ref.isShared()) return this->insertMulti(akey, avalue); + Q_ASSERT_X(isValidIterator(pos), "QMap::insertMulti", "The specified const_iterator argument 'pos' is invalid"); + if (pos == constEnd()) { // Hint is that the Node is larger than (or equal to) the largest value. Node *n = static_cast(pos.i->left); @@ -895,6 +911,8 @@ Q_OUTOFLINE_TEMPLATE typename QMap::iterator QMap::erase(iterato if (it == iterator(d->end())) return it; + Q_ASSERT_X(isValidIterator(const_iterator(it)), "QMap::erase", "The specified iterator argument 'it' is invalid"); + Node *n = it.i; ++it; d->deleteNode(n); diff --git a/tests/manual/corelib/tools/qmap/main.cpp b/tests/manual/corelib/tools/qmap/main.cpp new file mode 100644 index 0000000000..0d88e3f170 --- /dev/null +++ b/tests/manual/corelib/tools/qmap/main.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Thorbjørn Lund Martsum - tmartsum[at]gmail.com +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//#define Q_NO_DEBUGMAP_PARENT_TEST +// Comment in line above to skip the parent test. +#include +#include + +void noBugErase() +{ + QMap a, b; + a[10] = 11; + a[11] = 12; + b = a; + b.erase(b.begin()); +} + +void noBugInsertWithHints() +{ + QMap a; + QMap b; + for (int u = 100; u < 10000; u += 20) + a.insert(u, u); + b = a; + QMap::const_iterator b_ite(b.begin()); // b.begin() ensures correct detach() + ++b_ite; + b.insert(b_ite, 501, 501); + b.insert(b_ite, 115, 115); + QMap c; + c = b; + c.setSharable(false); +} + +void testInsertWithHintCorruption() +{ + qDebug() << "Starting testInsertWithHintCorruption"; + + QMap a; + QMap b; + for (int u = 100; u < 10000; u += 20) + a.insert(u, u); + b = a; + QMap::const_iterator b_ite = b.constBegin(); + ++b_ite; + b.insert(b_ite, 501, 501); + b.insert(b_ite, 115, 115); // insert with wrong hint. + QMap c; + c = b; + c.setSharable(false); + qDebug() << "End of testInsertWithHintCorruption - failed silently"; +} + +void testEraseCorruption() +{ + qDebug() << "Starting testEraseCorruption"; + + QMap a, b; + a[10] = 11; + a[11] = 12; + b = a; + b.erase(a.begin()); + qDebug() << "End of testEraseCorruption - failed silently"; +} + +int main() +{ + noBugErase(); + noBugInsertWithHints(); + + // testEraseCorruption(); + testInsertWithHintCorruption(); + return 0; +} diff --git a/tests/manual/corelib/tools/qmap/qmaptest.pro b/tests/manual/corelib/tools/qmap/qmaptest.pro new file mode 100644 index 0000000000..fbe7013144 --- /dev/null +++ b/tests/manual/corelib/tools/qmap/qmaptest.pro @@ -0,0 +1,2 @@ +TEMPLATE = app +SOURCES = main.cpp -- cgit v1.2.3