summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2014-09-19 20:34:31 (GMT)
committerTobias Markmann <tm@ayena.de>2014-09-20 10:48:55 (GMT)
commit49535506a9c8002baf27da3de629326e57982f44 (patch)
treee4b647cde5eaf52142e2b144ab1955d792c34ba1
parentdbdd30aa0d94c79742a602908890548030088bc9 (diff)
downloadswift-contrib-49535506a9c8002baf27da3de629326e57982f44.zip
swift-contrib-49535506a9c8002baf27da3de629326e57982f44.tar.bz2
Fix ASAN-reported heap-use-after-free bug.
ChatListModel used to notify Qt about its changed items via layoutChanged() signals. However, not only the layout changed but most times also the items and corrosponding QModelIndex objects and their internal pointers. After layout changed Qt tried to access now invalid QModelIndex objects and their internal pointers pointed to freed memory. Test-Information: Checked via ASAN. The previously perfect reproducable report by joining a MUC from the bookmarks went away. Change-Id: I71d2aa7e66a6b4caf2a9e0f68552ff5174291e1e License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.
-rw-r--r--Swift/QtUI/ChatList/ChatListModel.cpp41
-rw-r--r--Swift/QtUI/ChatList/ChatListModel.h6
2 files changed, 31 insertions, 16 deletions
diff --git a/Swift/QtUI/ChatList/ChatListModel.cpp b/Swift/QtUI/ChatList/ChatListModel.cpp
index d09b0dd..f08478f 100644
--- a/Swift/QtUI/ChatList/ChatListModel.cpp
+++ b/Swift/QtUI/ChatList/ChatListModel.cpp
@@ -1,127 +1,138 @@
/*
* Copyright (c) 2010-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swift/QtUI/ChatList/ChatListModel.h>
#include <QMimeData>
#include <QUrl>
#include <Swift/QtUI/ChatList/ChatListMUCItem.h>
#include <Swift/QtUI/ChatList/ChatListRecentItem.h>
#include <Swift/QtUI/ChatList/ChatListWhiteboardItem.h>
#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
ChatListModel::ChatListModel() : whiteboards_(NULL) {
root_ = new ChatListGroupItem("", NULL, false);
mucBookmarks_ = new ChatListGroupItem(tr("Bookmarked Rooms"), root_);
recents_ = new ChatListGroupItem(tr("Recent Chats"), root_, false);
#ifdef SWIFT_EXPERIMENTAL_WB
whiteboards_ = new ChatListGroupItem(tr("Opened Whiteboards"), root_, false);
root_->addItem(whiteboards_);
#endif
root_->addItem(recents_);
root_->addItem(mucBookmarks_);
+
+ QModelIndex idx = index(0, 0, QModelIndex());
+ while (idx.isValid()) {
+ if (idx.internalPointer() == mucBookmarks_) {
+ mucBookmarksIndex_ = idx;
+ } else if (idx.internalPointer() == recents_) {
+ recentsIndex_ = idx;
+ } else if (idx.internalPointer() == whiteboards_) {
+ whiteboardsIndex_ = idx;
+ }
+ idx = index(idx.row() + 1, 0, QModelIndex());
+ }
}
Qt::ItemFlags ChatListModel::flags(const QModelIndex& index) const {
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
if (dynamic_cast<ChatListRecentItem*>(getItemForIndex(index))) {
flags |= Qt::ItemIsDragEnabled;
}
return flags;
}
void ChatListModel::clearBookmarks() {
- emit layoutAboutToBeChanged();
+ beginRemoveRows(mucBookmarksIndex_, 0, mucBookmarks_->rowCount());
mucBookmarks_->clear();
- emit layoutChanged();
+ endRemoveRows();
}
void ChatListModel::addMUCBookmark(const Swift::MUCBookmark& bookmark) {
- emit layoutAboutToBeChanged();
+ beginInsertRows(mucBookmarksIndex_, 0, mucBookmarks_->rowCount());
mucBookmarks_->addItem(new ChatListMUCItem(bookmark, mucBookmarks_));
- emit layoutChanged();
- //QModelIndex index = createIndex(mucBookmarks_->rowCount() - 1, 0, mucBookmarks_);
- //emit dataChanged(index, index);
- //emit dataChanged(parent(index), parent(index));
+ endInsertRows();
}
void ChatListModel::removeMUCBookmark(const Swift::MUCBookmark& bookmark) {
for (int i = 0; i < mucBookmarks_->rowCount(); i++) {
ChatListMUCItem* item = dynamic_cast<ChatListMUCItem*>(mucBookmarks_->item(i));
if (item->getBookmark() == bookmark) {
- emit layoutAboutToBeChanged();
+ beginRemoveRows(mucBookmarksIndex_, i, i+1);
mucBookmarks_->remove(i);
- emit layoutChanged();
+ endRemoveRows();
break;
}
}
}
void ChatListModel::addWhiteboardSession(const ChatListWindow::Chat& chat) {
- emit layoutAboutToBeChanged();
+ beginInsertRows(whiteboardsIndex_, 0, whiteboards_->rowCount());
whiteboards_->addItem(new ChatListWhiteboardItem(chat, whiteboards_));
- emit layoutChanged();
+ endInsertRows();
}
void ChatListModel::removeWhiteboardSession(const JID& jid) {
for (int i = 0; i < whiteboards_->rowCount(); i++) {
ChatListWhiteboardItem* item = dynamic_cast<ChatListWhiteboardItem*>(whiteboards_->item(i));
if (item->getChat().jid == jid) {
- emit layoutAboutToBeChanged();
+ beginRemoveRows(whiteboardsIndex_, i, i+1);
whiteboards_->remove(i);
- emit layoutChanged();
+ endRemoveRows();
break;
}
}
}
void ChatListModel::setRecents(const std::list<ChatListWindow::Chat>& recents) {
- emit layoutAboutToBeChanged();
+ beginRemoveRows(recentsIndex_, 0, recents_->rowCount());
recents_->clear();
+ endRemoveRows();
+ beginInsertRows(recentsIndex_, 0, recents.size());
foreach (const ChatListWindow::Chat chat, recents) {
recents_->addItem(new ChatListRecentItem(chat, recents_));
//whiteboards_->addItem(new ChatListRecentItem(chat, whiteboards_));
}
- emit layoutChanged();
+ endInsertRows();
}
QMimeData* ChatListModel::mimeData(const QModelIndexList& indexes) const {
QMimeData* data = QAbstractItemModel::mimeData(indexes);
ChatListRecentItem *item = dynamic_cast<ChatListRecentItem*>(getItemForIndex(indexes.first()));
if (item == NULL) {
return data;
}
QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
const ChatListWindow::Chat& chat = item->getChat();
QString mimeType = "application/vnd.swift.contact-jid-list";
if (!chat.impromptuJIDs.size()) {
if (chat.isMUC) {
mimeType = "application/vnd.swift.contact-jid-muc";
}
dataStream << P2QSTRING(chat.jid.toString());
} else {
typedef std::map<std::string, JID> JIDMap;
foreach (const JIDMap::value_type& jid, chat.impromptuJIDs) {
dataStream << P2QSTRING(jid.second.toString());
}
}
data->setData(mimeType, itemData);
return data;
}
int ChatListModel::columnCount(const QModelIndex& /*parent*/) const {
return 1;
}
ChatListItem* ChatListModel::getItemForIndex(const QModelIndex& index) const {
diff --git a/Swift/QtUI/ChatList/ChatListModel.h b/Swift/QtUI/ChatList/ChatListModel.h
index a15cbcd..00bd5eb 100644
--- a/Swift/QtUI/ChatList/ChatListModel.h
+++ b/Swift/QtUI/ChatList/ChatListModel.h
@@ -1,43 +1,47 @@
/*
* Copyright (c) 2010-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <QAbstractItemModel>
-#include <QList>
+#include <QPersistentModelIndex>
#include <Swiften/MUC/MUCBookmark.h>
#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
#include <Swift/QtUI/ChatList/ChatListGroupItem.h>
namespace Swift {
class ChatListModel : public QAbstractItemModel {
Q_OBJECT
public:
ChatListModel();
Qt::ItemFlags flags(const QModelIndex& index) const;
void addMUCBookmark(const MUCBookmark& bookmark);
void removeMUCBookmark(const MUCBookmark& bookmark);
void addWhiteboardSession(const ChatListWindow::Chat& chat);
void removeWhiteboardSession(const JID& jid);
int columnCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex& index) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const;
ChatListItem* getItemForIndex(const QModelIndex& index) const;
void clearBookmarks();
void setRecents(const std::list<ChatListWindow::Chat>& recents);
QMimeData* mimeData(const QModelIndexList& indexes) const;
private:
ChatListGroupItem* mucBookmarks_;
ChatListGroupItem* recents_;
ChatListGroupItem* whiteboards_;
ChatListGroupItem* root_;
+
+ QPersistentModelIndex mucBookmarksIndex_;
+ QPersistentModelIndex recentsIndex_;
+ QPersistentModelIndex whiteboardsIndex_;
};
}