diff options
author | Jocelyn Turcotte <jturcotte@woboq.com> | 2015-04-02 16:16:33 +0300 |
---|---|---|
committer | Jocelyn Turcotte <jturcotte@woboq.com> | 2015-04-08 10:35:43 +0300 |
commit | 4a890eae38f86d5f689983e84da951a1b42c17d8 (patch) | |
tree | cac92df3861d7d091485837122eed0a7751079ff /src | |
parent | 760e11bc5d6fa6ace72bac4e536e95b023d41cea (diff) |
SyncEngine: Fix a crash caused by an invalid DiscoveryDirectoryResult::iterator #3051
The default constructor of the iterator points to NULL, which makes
it != end() but invalid to dereference.
Use an integer index instead to keep 0 as a valid default value that
can always correctly be checked against size().
Also make sure that no data is shared between threads by making the
csync_vio_file_stat_t copyable and passing it as const.
Diffstat (limited to 'src')
-rw-r--r-- | src/libsync/discoveryphase.cpp | 29 | ||||
-rw-r--r-- | src/libsync/discoveryphase.h | 58 |
2 files changed, 37 insertions, 50 deletions
diff --git a/src/libsync/discoveryphase.cpp b/src/libsync/discoveryphase.cpp index f68a6974b..b8c580a12 100644 --- a/src/libsync/discoveryphase.cpp +++ b/src/libsync/discoveryphase.cpp @@ -268,7 +268,7 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file,QMap } - csync_vio_file_stat_t *file_stat = propertyMapToFileStat(map); + FileStatPointer file_stat(propertyMapToFileStat(map)); file_stat->name = strdup(file.toUtf8()); if (!file_stat->etag || strlen(file_stat->etag) == 0) { qDebug() << "WARNING: etag of" << file_stat->name << "is" << file_stat->etag << " This must not happen."; @@ -319,15 +319,6 @@ void DiscoveryMainThread::setupHooks(DiscoveryJob *discoveryJob, const QString & connect(discoveryJob, SIGNAL(doOpendirSignal(QString,DiscoveryDirectoryResult*)), this, SLOT(doOpendirSlot(QString,DiscoveryDirectoryResult*)), Qt::QueuedConnection); - connect(discoveryJob, SIGNAL(doClosedirSignal(QString)), - this, SLOT(doClosedirSlot(QString)), - Qt::QueuedConnection); -} - -void DiscoveryMainThread::doClosedirSlot(QString path) -{ - //qDebug() << Q_FUNC_INFO << "Invalidating" << path; - deleteCacheEntry(path); } // Coming from owncloud_opendir -> DiscoveryJob::vio_opendir_hook -> doOpendirSignal @@ -352,8 +343,8 @@ void DiscoveryMainThread::doOpendirSlot(QString subPath, DiscoveryDirectoryResul // Schedule the DiscoverySingleDirectoryJob _singleDirJob = new DiscoverySingleDirectoryJob(_account, fullPath, this); - QObject::connect(_singleDirJob, SIGNAL(finishedWithResult(QLinkedList<csync_vio_file_stat_t *>)), - this, SLOT(singleDirectoryJobResultSlot(QLinkedList<csync_vio_file_stat_t*>))); + QObject::connect(_singleDirJob, SIGNAL(finishedWithResult(const QList<FileStatPointer> &)), + this, SLOT(singleDirectoryJobResultSlot(const QList<FileStatPointer> &))); QObject::connect(_singleDirJob, SIGNAL(finishedWithError(int,QString)), this, SLOT(singleDirectoryJobFinishedWithErrorSlot(int,QString))); QObject::connect(_singleDirJob, SIGNAL(firstDirectoryPermissions(QString)), @@ -364,7 +355,7 @@ void DiscoveryMainThread::doOpendirSlot(QString subPath, DiscoveryDirectoryResul } -void DiscoveryMainThread::singleDirectoryJobResultSlot(QLinkedList<csync_vio_file_stat_t *> result) +void DiscoveryMainThread::singleDirectoryJobResultSlot(const QList<FileStatPointer> & result) { if (!_currentDiscoveryDirectoryResult) { return; // possibly aborted @@ -372,11 +363,9 @@ void DiscoveryMainThread::singleDirectoryJobResultSlot(QLinkedList<csync_vio_fil qDebug() << Q_FUNC_INFO << "Have" << result.count() << "results for " << _currentDiscoveryDirectoryResult->path; - _directoryContents.insert(_currentDiscoveryDirectoryResult->path, result); - _currentDiscoveryDirectoryResult->list = result; _currentDiscoveryDirectoryResult->code = 0; - _currentDiscoveryDirectoryResult->iterator = _currentDiscoveryDirectoryResult->list.begin(); + _currentDiscoveryDirectoryResult->listIndex = 0; _currentDiscoveryDirectoryResult = 0; // the sync thread owns it now _discoveryJob->_vioMutex.lock(); @@ -414,7 +403,7 @@ void DiscoveryMainThread::abort() { if (_singleDirJob) { _singleDirJob->disconnect(SIGNAL(finishedWithError(int,QString)), this); _singleDirJob->disconnect(SIGNAL(firstDirectoryPermissions(QString)), this); - _singleDirJob->disconnect(SIGNAL(finishedWithResult(QLinkedList<csync_vio_file_stat_t*>)), this); + _singleDirJob->disconnect(SIGNAL(finishedWithResult(const QList<FileStatPointer> &)), this); _singleDirJob->abort(); } if (_currentDiscoveryDirectoryResult) { @@ -469,9 +458,8 @@ csync_vio_file_stat_t* DiscoveryJob::remote_vio_readdir_hook (csync_vio_handle_t DiscoveryJob *discoveryJob = static_cast<DiscoveryJob*>(userdata); if (discoveryJob) { DiscoveryDirectoryResult *directoryResult = static_cast<DiscoveryDirectoryResult*>(dhandle); - if (directoryResult->iterator != directoryResult->list.end()) { - csync_vio_file_stat_t *file_stat = *(directoryResult->iterator); - directoryResult->iterator++; + if (directoryResult->listIndex < directoryResult->list.size()) { + csync_vio_file_stat_t *file_stat = directoryResult->list.at(directoryResult->listIndex++).data(); // Make a copy, csync_update will delete the copy return csync_vio_file_stat_copy(file_stat); } @@ -487,7 +475,6 @@ void DiscoveryJob::remote_vio_closedir_hook (csync_vio_handle_t *dhandle, void QString path = directoryResult->path; qDebug() << Q_FUNC_INFO << discoveryJob << path; delete directoryResult; // just deletes the struct and the iterator, the data itself is owned by the SyncEngine/DiscoveryMainThread - emit discoveryJob->doClosedirSignal(path); } } diff --git a/src/libsync/discoveryphase.h b/src/libsync/discoveryphase.h index b1989d0a0..5ceb477e3 100644 --- a/src/libsync/discoveryphase.h +++ b/src/libsync/discoveryphase.h @@ -34,12 +34,36 @@ class Account; * if the files are new, or changed. */ +class FileStatPointer { +public: + FileStatPointer(csync_vio_file_stat_t *stat) + : _stat(stat) + { } + FileStatPointer(const FileStatPointer &other) + : _stat(csync_vio_file_stat_copy(other._stat)) + { } + ~FileStatPointer() { + csync_vio_file_stat_destroy(_stat); + } + FileStatPointer &operator=(const FileStatPointer &other) { + csync_vio_file_stat_destroy(_stat); + _stat = csync_vio_file_stat_copy(other._stat); + return *this; + } + inline csync_vio_file_stat_t *data() const { return _stat; } + inline csync_vio_file_stat_t *operator->() const { return _stat; } + +private: + csync_vio_file_stat_t *_stat; +}; + struct DiscoveryDirectoryResult { QString path; QString msg; int code; - QLinkedList<csync_vio_file_stat_t*>::iterator iterator; - QLinkedList<csync_vio_file_stat_t *> list; + QList<FileStatPointer> list; + int listIndex; + DiscoveryDirectoryResult() : code(0), listIndex(0) { } }; // Run in the main thread, reporting to the DiscoveryJobMainThread object @@ -53,14 +77,14 @@ public: signals: void firstDirectoryPermissions(const QString &); void etagConcatenation(const QString &); - void finishedWithResult(QLinkedList<csync_vio_file_stat_t*>); + void finishedWithResult(const QList<FileStatPointer> &); void finishedWithError(int csyncErrnoCode, QString msg); private slots: void directoryListingIteratedSlot(QString,QMap<QString,QString>); void lsJobFinishedWithoutErrorSlot(); void lsJobFinishedWithErrorSlot(QNetworkReply*); private: - QLinkedList<csync_vio_file_stat_t*> _results; + QList<FileStatPointer> _results; QString _subPath; QString _etagConcatenation; AccountPtr _account; @@ -73,11 +97,6 @@ class DiscoveryJob; class DiscoveryMainThread : public QObject { Q_OBJECT - // For non-recursive and recursive - // If it is not in this map it needs to be requested - QMap<QString, QLinkedList<csync_vio_file_stat_t*> > _directoryContents; - - QPointer<DiscoveryJob> _discoveryJob; QPointer<DiscoverySingleDirectoryJob> _singleDirJob; QString _pathPrefix; @@ -88,32 +107,15 @@ public: DiscoveryMainThread(AccountPtr account) : QObject(), _account(account), _currentDiscoveryDirectoryResult(0) { } - void deleteCacheEntry(QString path) { - //qDebug() << path << _directoryContents.value(path).count(); - foreach (csync_vio_file_stat_t* stat, _directoryContents.value(path)) { - csync_vio_file_stat_destroy(stat); - } - _directoryContents.remove(path); - } - - ~DiscoveryMainThread() { - // Delete the _contents_ of the list-map explicitly: - foreach (const QLinkedList<csync_vio_file_stat_t*> & list, _directoryContents) { - foreach (csync_vio_file_stat_t* stat, list) { - csync_vio_file_stat_destroy(stat); - } - } - } void abort(); public slots: // From DiscoveryJob: void doOpendirSlot(QString url, DiscoveryDirectoryResult* ); - void doClosedirSlot(QString path); // From Job: - void singleDirectoryJobResultSlot(QLinkedList<csync_vio_file_stat_t*>); + void singleDirectoryJobResultSlot(const QList<FileStatPointer> &); void singleDirectoryJobFinishedWithErrorSlot(int csyncErrnoCode, QString msg); void singleDirectoryJobFirstDirectoryPermissionsSlot(QString); signals: @@ -175,8 +177,6 @@ signals: // After the discovery job has been woken up again (_vioWaitCondition) void doOpendirSignal(QString url, DiscoveryDirectoryResult*); - // to tell the main thread to invalidate its directory data - void doClosedirSignal(QString path); }; } |