mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-11 15:27:54 +00:00
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.
This commit is contained in:
parent
333978f1ff
commit
b995a9d75e
@ -35,10 +35,21 @@
|
|||||||
|
|
||||||
const size_t DEFAULT_ALERTS_CAPACITY = 32;
|
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)
|
QAlertDispatcher::QAlertDispatcher(libtorrent::session *session, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_session(session)
|
, m_session(session)
|
||||||
, current_tag(new QAtomicPointer<QAlertDispatcher>(this))
|
, current_tag(new Tag(this))
|
||||||
, event_posted(false)
|
, event_posted(false)
|
||||||
{
|
{
|
||||||
alerts.reserve(DEFAULT_ALERTS_CAPACITY);
|
alerts.reserve(DEFAULT_ALERTS_CAPACITY);
|
||||||
@ -54,8 +65,8 @@ QAlertDispatcher::~QAlertDispatcher() {
|
|||||||
// with invalid tag it simply discard an alert.
|
// with invalid tag it simply discard an alert.
|
||||||
|
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&alerts_mutex);
|
QMutexLocker lock(¤t_tag->alerts_mutex);
|
||||||
*current_tag = 0;
|
current_tag->dispatcher = 0;
|
||||||
current_tag.clear();
|
current_tag.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +78,7 @@ void QAlertDispatcher::getPendingAlertsNoWait(std::vector<libtorrent::alert*>& o
|
|||||||
Q_ASSERT(out.empty());
|
Q_ASSERT(out.empty());
|
||||||
out.reserve(DEFAULT_ALERTS_CAPACITY);
|
out.reserve(DEFAULT_ALERTS_CAPACITY);
|
||||||
|
|
||||||
QMutexLocker lock(&alerts_mutex);
|
QMutexLocker lock(¤t_tag->alerts_mutex);
|
||||||
alerts.swap(out);
|
alerts.swap(out);
|
||||||
event_posted = false;
|
event_posted = false;
|
||||||
}
|
}
|
||||||
@ -76,34 +87,22 @@ void QAlertDispatcher::getPendingAlerts(std::vector<libtorrent::alert*>& out, un
|
|||||||
Q_ASSERT(out.empty());
|
Q_ASSERT(out.empty());
|
||||||
out.reserve(DEFAULT_ALERTS_CAPACITY);
|
out.reserve(DEFAULT_ALERTS_CAPACITY);
|
||||||
|
|
||||||
QMutexLocker lock(&alerts_mutex);
|
QMutexLocker lock(¤t_tag->alerts_mutex);
|
||||||
|
|
||||||
while (alerts.empty())
|
while (alerts.empty())
|
||||||
alerts_condvar.wait(&alerts_mutex, time);
|
alerts_condvar.wait(¤t_tag->alerts_mutex, time);
|
||||||
|
|
||||||
alerts.swap(out);
|
alerts.swap(out);
|
||||||
event_posted = false;
|
event_posted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAlertDispatcher::dispatch(QSharedPointer<QAtomicPointer<QAlertDispatcher> > tag,
|
void QAlertDispatcher::dispatch(QSharedPointer<Tag> tag,
|
||||||
std::auto_ptr<libtorrent::alert> alert_ptr) {
|
std::auto_ptr<libtorrent::alert> alert_ptr) {
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
QMutexLocker lock(&(tag->alerts_mutex));
|
||||||
QAlertDispatcher* that = tag->loadAcquire();
|
QAlertDispatcher* that = tag->dispatcher;
|
||||||
#else
|
|
||||||
QAlertDispatcher* that = *tag;
|
|
||||||
#endif
|
|
||||||
if (!that)
|
if (!that)
|
||||||
return;
|
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();
|
bool was_empty = that->alerts.empty();
|
||||||
|
|
||||||
that->alerts.push_back(alert_ptr.get());
|
that->alerts.push_back(alert_ptr.get());
|
||||||
@ -127,7 +126,7 @@ void QAlertDispatcher::enqueueToMainThread() {
|
|||||||
void QAlertDispatcher::deliverSignal() {
|
void QAlertDispatcher::deliverSignal() {
|
||||||
emit alertsReceived();
|
emit alertsReceived();
|
||||||
|
|
||||||
QMutexLocker lock(&alerts_mutex);
|
QMutexLocker lock(¤t_tag->alerts_mutex);
|
||||||
event_posted = false;
|
event_posted = false;
|
||||||
|
|
||||||
if (!alerts.empty())
|
if (!alerts.empty())
|
||||||
|
@ -42,6 +42,8 @@ class QAlertDispatcher : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_DISABLE_COPY(QAlertDispatcher)
|
Q_DISABLE_COPY(QAlertDispatcher)
|
||||||
|
|
||||||
|
struct Tag;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QAlertDispatcher(libtorrent::session *session, QObject* parent);
|
QAlertDispatcher(libtorrent::session *session, QObject* parent);
|
||||||
~QAlertDispatcher();
|
~QAlertDispatcher();
|
||||||
@ -53,7 +55,7 @@ signals:
|
|||||||
void alertsReceived();
|
void alertsReceived();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void dispatch(QSharedPointer<QAtomicPointer<QAlertDispatcher> >,
|
static void dispatch(QSharedPointer<Tag>,
|
||||||
std::auto_ptr<libtorrent::alert>);
|
std::auto_ptr<libtorrent::alert>);
|
||||||
void enqueueToMainThread();
|
void enqueueToMainThread();
|
||||||
|
|
||||||
@ -62,10 +64,9 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
libtorrent::session *m_session;
|
libtorrent::session *m_session;
|
||||||
QMutex alerts_mutex;
|
|
||||||
QWaitCondition alerts_condvar;
|
QWaitCondition alerts_condvar;
|
||||||
std::vector<libtorrent::alert*> alerts;
|
std::vector<libtorrent::alert*> alerts;
|
||||||
QSharedPointer<QAtomicPointer<QAlertDispatcher> > current_tag;
|
QSharedPointer<Tag> current_tag;
|
||||||
bool event_posted;
|
bool event_posted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user