Merge pull request #6524 from jbroadus/closure-timing-hole

Fix closure timing hole.
This commit is contained in:
John Maguire 2020-01-12 13:58:04 +00:00 committed by GitHub
commit 56a043a9ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 4 deletions

View File

@ -37,8 +37,15 @@ ObjectHelper* ClosureBase::helper() const { return helper_; }
ObjectHelper::ObjectHelper(QObject* sender, const char* signal,
ClosureBase* closure)
: closure_(closure) {
connect(sender, signal, SLOT(Invoked()));
connect(sender, SIGNAL(destroyed()), SLOT(deleteLater()));
connection_ = connect(sender, signal, SLOT(Invoked()));
connect(sender, SIGNAL(destroyed()), SLOT(TearDown()));
}
void ObjectHelper::TearDown() {
// For the case that the receiver has been destroyed, disconnect the signal
// so that Invoke isn't called.
disconnect(connection_);
deleteLater();
}
void ObjectHelper::Invoked() {

View File

@ -58,10 +58,14 @@ class ObjectHelper : public QObject {
public:
ObjectHelper(QObject* parent, const char* signal, ClosureBase* closure);
public slots:
void TearDown();
private slots:
void Invoked();
private:
QMetaObject::Connection connection_;
std::unique_ptr<ClosureBase> closure_;
Q_DISABLE_COPY(ObjectHelper)
};
@ -97,8 +101,11 @@ class Closure : public ClosureBase {
const int index = meta_receiver->indexOfSlot(normalised_slot.constData());
Q_ASSERT(index != -1);
slot_ = meta_receiver->method(index);
QObject::connect(receiver_, SIGNAL(destroyed()), helper_,
SLOT(deleteLater()));
// Use a direct connection to insure that this is called immediately when
// the sender is destroyed. This will run on the signal thread, so TearDown
// must be thread safe.
QObject::connect(receiver_, SIGNAL(destroyed()), helper_, SLOT(TearDown()),
Qt::DirectConnection);
}
virtual void Invoke() { function_(); }