ActivityListModel: fix possible crash in slotActivitiesReceived
authorOlivier Goffart <ogoffart@woboq.com>
Mon, 6 Mar 2017 15:14:09 +0000 (16:14 +0100)
committerOlivier Goffart <olivier@woboq.com>
Mon, 6 Mar 2017 16:25:22 +0000 (17:25 +0100)
Backtrace from the crash reporter:

Crash: EXCEPTION_ACCESS_VIOLATION_READ at 0x401
  File "moc_activitylistmo_M5OEXJ7XGJYTWT.cpp", line 92, in OCC::ActivityListModel::qt_static_metacall
  File "qobject.cpp", line 3730, in QMetaObject::activate
  File "moc_networkjobs_7AMNCW4BBANVRK.cpp", line 1342, in OCC::JsonApiJob::jsonReceived
  File "networkjobs.cpp", line 714, in OCC::JsonApiJob::finished
  File "abstractnetworkjob.cpp", line 207, in OCC::AbstractNetworkJob::slotFinished
  File "moc_abstractnetwor_PFI2TXGQHRE33H.cpp", line 98, in OCC::AbstractNetworkJob::qt_static_metacall
  File "qobject.cpp", line 3730, in QMetaObject::activate
  File "moc_qnetworkreply.cpp", line 367, in QNetworkReply::finished
  File "qnetworkreplyhttpimpl.cpp", line 2100, in QNetworkReplyHttpImplPrivate::finished
  File "qnetworkreplyhttpimpl.cpp", line 279, in QNetworkReplyHttpImpl::abort

My theory is that the AccountState stored in a property of the job was destroyed.
before the job timed out.
Therefore, the qobject_cast within the qvariant_cast would call the metaObject()
virtual function on a dangling pointer.

Fix it by storing a QPointer instead which will track the deletion.

src/gui/activitylistmodel.cpp

index 7c83434bee6ea2dde1c6a2f0ca54aa487d670c4d..f6658db0050b3ab9fd2b2e50e87e027a8247da3e 100644 (file)
 #include "activitydata.h"
 #include "activitylistmodel.h"
 
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+Q_DECLARE_METATYPE(QPointer<OCC::AccountState>)
+#endif
+
 namespace OCC {
 
 ActivityListModel::ActivityListModel(QWidget *parent)
@@ -122,7 +126,7 @@ void ActivityListModel::startFetchJob(AccountState* s)
     JsonApiJob *job = new JsonApiJob(s->account(), QLatin1String("ocs/v1.php/cloud/activity"), this);
     QObject::connect(job, SIGNAL(jsonReceived(QVariantMap, int)),
                      this, SLOT(slotActivitiesReceived(QVariantMap, int)));
-    job->setProperty("AccountStatePtr", QVariant::fromValue<AccountState*>(s));
+    job->setProperty("AccountStatePtr", QVariant::fromValue<QPointer<AccountState>>(s));
 
     QList< QPair<QString,QString> > params;
     params.append(qMakePair(QString::fromLatin1("page"),     QString::fromLatin1("0")));
@@ -139,7 +143,10 @@ void ActivityListModel::slotActivitiesReceived(const QVariantMap& json, int stat
     auto activities = json.value("ocs").toMap().value("data").toList();
 
     ActivityList list;
-    AccountState* ast = qvariant_cast<AccountState*>(sender()->property("AccountStatePtr"));
+    auto ast = qvariant_cast<QPointer<AccountState>>(sender()->property("AccountStatePtr"));
+    if (!ast)
+        return;
+
     _currentlyFetching.remove(ast);
 
     foreach( auto activ, activities ) {