Browse Source

Fix race condition in QAlertDispatcher

It was possible that QAlertDispatcher::dispatch() could access (lock)
mutex that was destroyed by main thread. Fix this by moving mutex into a
tag.
adaptive-webui-19844
Ivan Sorokin 10 years ago
parent
commit
b995a9d75e
  1. 43
      src/qtlibtorrent/alertdispatcher.cpp
  2. 7
      src/qtlibtorrent/alertdispatcher.h

43
src/qtlibtorrent/alertdispatcher.cpp

@ -35,10 +35,21 @@ @@ -35,10 +35,21 @@
const size_t DEFAULT_ALERTS_CAPACITY = 32;
struct QAlertDispatcher::Tag {
Tag(QAlertDispatcher* dispatcher);
QAlertDispatcher* dispatcher;
QMutex alerts_mutex;
};
QAlertDispatcher::Tag::Tag(QAlertDispatcher* dispatcher)
: dispatcher(dispatcher)
{}
QAlertDispatcher::QAlertDispatcher(libtorrent::session *session, QObject* parent)
: QObject(parent)
, m_session(session)
, current_tag(new QAtomicPointer<QAlertDispatcher>(this))
, current_tag(new Tag(this))
, event_posted(false)
{
alerts.reserve(DEFAULT_ALERTS_CAPACITY);
@ -54,8 +65,8 @@ QAlertDispatcher::~QAlertDispatcher() { @@ -54,8 +65,8 @@ QAlertDispatcher::~QAlertDispatcher() {
// with invalid tag it simply discard an alert.
{
QMutexLocker lock(&alerts_mutex);
*current_tag = 0;
QMutexLocker lock(&current_tag->alerts_mutex);
current_tag->dispatcher = 0;
current_tag.clear();
}
@ -67,7 +78,7 @@ void QAlertDispatcher::getPendingAlertsNoWait(std::vector<libtorrent::alert*>& o @@ -67,7 +78,7 @@ void QAlertDispatcher::getPendingAlertsNoWait(std::vector<libtorrent::alert*>& o
Q_ASSERT(out.empty());
out.reserve(DEFAULT_ALERTS_CAPACITY);
QMutexLocker lock(&alerts_mutex);
QMutexLocker lock(&current_tag->alerts_mutex);
alerts.swap(out);
event_posted = false;
}
@ -76,34 +87,22 @@ void QAlertDispatcher::getPendingAlerts(std::vector<libtorrent::alert*>& out, un @@ -76,34 +87,22 @@ void QAlertDispatcher::getPendingAlerts(std::vector<libtorrent::alert*>& out, un
Q_ASSERT(out.empty());
out.reserve(DEFAULT_ALERTS_CAPACITY);
QMutexLocker lock(&alerts_mutex);
QMutexLocker lock(&current_tag->alerts_mutex);
while (alerts.empty())
alerts_condvar.wait(&alerts_mutex, time);
alerts_condvar.wait(&current_tag->alerts_mutex, time);
alerts.swap(out);
event_posted = false;
}
void QAlertDispatcher::dispatch(QSharedPointer<QAtomicPointer<QAlertDispatcher> > tag,
void QAlertDispatcher::dispatch(QSharedPointer<Tag> tag,
std::auto_ptr<libtorrent::alert> alert_ptr) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
QAlertDispatcher* that = tag->loadAcquire();
#else
QAlertDispatcher* that = *tag;
#endif
QMutexLocker lock(&(tag->alerts_mutex));
QAlertDispatcher* that = tag->dispatcher;
if (!that)
return;
QMutexLocker lock(&(that->alerts_mutex));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
if (!tag->load())
#else
if (!*tag)
#endif
return;
bool was_empty = that->alerts.empty();
that->alerts.push_back(alert_ptr.get());
@ -127,7 +126,7 @@ void QAlertDispatcher::enqueueToMainThread() { @@ -127,7 +126,7 @@ void QAlertDispatcher::enqueueToMainThread() {
void QAlertDispatcher::deliverSignal() {
emit alertsReceived();
QMutexLocker lock(&alerts_mutex);
QMutexLocker lock(&current_tag->alerts_mutex);
event_posted = false;
if (!alerts.empty())

7
src/qtlibtorrent/alertdispatcher.h

@ -42,6 +42,8 @@ class QAlertDispatcher : public QObject { @@ -42,6 +42,8 @@ class QAlertDispatcher : public QObject {
Q_OBJECT
Q_DISABLE_COPY(QAlertDispatcher)
struct Tag;
public:
QAlertDispatcher(libtorrent::session *session, QObject* parent);
~QAlertDispatcher();
@ -53,7 +55,7 @@ signals: @@ -53,7 +55,7 @@ signals:
void alertsReceived();
private:
static void dispatch(QSharedPointer<QAtomicPointer<QAlertDispatcher> >,
static void dispatch(QSharedPointer<Tag>,
std::auto_ptr<libtorrent::alert>);
void enqueueToMainThread();
@ -62,10 +64,9 @@ private slots: @@ -62,10 +64,9 @@ private slots:
private:
libtorrent::session *m_session;
QMutex alerts_mutex;
QWaitCondition alerts_condvar;
std::vector<libtorrent::alert*> alerts;
QSharedPointer<QAtomicPointer<QAlertDispatcher> > current_tag;
QSharedPointer<Tag> current_tag;
bool event_posted;
};

Loading…
Cancel
Save