Skip to content

Commit bae8204

Browse files
committed
qtvcp: close dbus bus when sys_notify init fails
If `init()` constructs `dbus.SessionBus(mainloop)` with the PyQt5/PyQt6 mainloop integration and the subsequent `bus.get_object(org.freedesktop.Notifications, ...)` call raises (e.g. `org.freedesktop.DBus.Error.ServiceUnknown` when no notification daemon owns the name), the Python reference to `bus` is dropped on the exception, but dbus-python's mainloop layer has already attached a `QSocketNotifier` to the connection fd. That notifier keeps the C-level connection alive in a half-initialized state. On the next Qt event-loop tick, the queued reply is dispatched via `dbus_connection_dispatch()` and segfaults inside `_dbus_list_unlink` because the connection's internal queue is no longer in a consistent state. Close the bus explicitly on the failure path so the socket notifier detaches and the connection is released cleanly. The `Desktop Notify not available` warning continues to be the only user-visible side effect. Reproduced on Ubuntu 24.04 CI under xvfb + offscreen Qt where no session-bus notification daemon is present; gdb -batch captured a Thread 1 backtrace ending in `dbus_connection_dispatch` -> `_dbus_list_pop_first_link` -> `_dbus_list_unlink` (segv).
1 parent 937ade5 commit bae8204

1 file changed

Lines changed: 18 additions & 0 deletions

File tree

lib/python/qtvcp/lib/sys_notify.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def init(app_name):
6262
interface = "org.freedesktop.Notifications"
6363

6464
mainloop = None
65+
bus = None
6566
try:
6667
if DBusQtMainLoop is not None:
6768
mainloop = DBusQtMainLoop(set_as_default=True)
@@ -76,6 +77,23 @@ def init(app_name):
7677
DBUS_IFACE.connect_to_signal('NotificationClosed', _onNotificationClosed)
7778
except Exception as e:
7879
LOG.warning('Desktop Notify not available:: {}'.format(e))
80+
# When the SessionBus is constructed with a PyQt5/PyQt6 mainloop
81+
# integration, dbus-python installs a QSocketNotifier on the
82+
# connection fd. If the subsequent get_object/Interface setup
83+
# raises (e.g. ServiceUnknown when no notification daemon owns
84+
# org.freedesktop.Notifications), the Python-side bus reference
85+
# is dropped on exception but the QSocketNotifier keeps the
86+
# underlying C connection alive in a half-initialized state.
87+
# The next QEventLoop tick dispatches a queued message via
88+
# dbus_connection_dispatch() and segfaults inside
89+
# _dbus_list_unlink. Close the bus explicitly so the notifier
90+
# detaches and the connection is fully released.
91+
DBUS_IFACE = None
92+
if bus is not None:
93+
try:
94+
bus.close()
95+
except Exception:
96+
pass
7997

8098

8199
def _onActionInvoked(nid, action):

0 commit comments

Comments
 (0)