services/pipewire: destroy qml ifaces early to avoid user callbacks

Consumers of defaultAudio*Changed signals can run code between
safeDestroy being called and PwObjectIface destruction due to
signal connection order. This change destroys ifaces earlier so they
are nulled by the time a changed signal is fired from destruction,
preventing access between ~PwNode() and ~QObject() completion.

Fixes #116 #122 #124
This commit is contained in:
outfoxxed 2025-07-17 00:06:32 -07:00
parent 201c559dcd
commit 91dcb41d22
Signed by untrusted user: outfoxxed
GPG key ID: 4C88A185FB89301E
2 changed files with 14 additions and 1 deletions

View file

@ -18,6 +18,16 @@
namespace qs::service::pipewire {
PwObjectIface::PwObjectIface(PwBindableObject* object): QObject(object), object(object) {
// We want to destroy the interface before QObject::destroyed is fired, as handlers
// connected before PwObjectIface will run first and emit signals that hit user code,
// which can then try to reference the iface again after ~PwNode() has been called but
// before ~QObject() has finished.
QObject::connect(object, &PwBindableObject::destroying, this, &PwObjectIface::onObjectDestroying);
}
void PwObjectIface::onObjectDestroying() { delete this; }
void PwObjectIface::ref() {
this->refcount++;

View file

@ -36,7 +36,7 @@ class PwObjectIface
Q_OBJECT;
public:
explicit PwObjectIface(PwBindableObject* object): QObject(object), object(object) {};
explicit PwObjectIface(PwBindableObject* object);
// destructor should ONLY be called by the pw object destructor, making an unref unnecessary
~PwObjectIface() override = default;
Q_DISABLE_COPY_MOVE(PwObjectIface);
@ -44,6 +44,9 @@ public:
void ref() override;
void unref() override;
private slots:
void onObjectDestroying();
private:
quint32 refcount = 0;
PwBindableObject* object;