Source: dbus-python
Version: 1.2.8-1
Severity: serious
Justification: fails to build from source (but built successfully in the past)
Build-time tests for dbus-python 1.2.8-1 failed on the armhf buildd. I
re-ran the tests 100 times in a loop on the armhf porterbox 'harris'
and they failed 6 times (2 for Python 2 and 4 for Python 3).
>From the log, we can see that there is a race condition: the client exits
before the server sent the expected response to its actions:
INFO:cross-test-client:Binding signal handler for Triggered
INFO:cross-test-client:method/signal: Triggering signal
INFO:cross-test-server:method/signal: client wants me to emit
Triggered(dbus.UInt64(42L)) from dbus.UTF8String('/Where/Ever')
INFO:cross-test-client:method/signal: Trigger() returned
INFO:cross-test-client:signal/callback: Emitting signal to trigger callback
INFO:cross-test-server:signal/callback: Triggered by client (:1.3:/Test):
(dbus.UInt16(42),dbus.Double(23.0))
INFO:cross-test-client:signal/callback: Emitting signal returned
INFO:cross-test-client:signal/callback: Response received
(dbus.UInt16(42),dbus.Double(23.0))
ERROR:cross-test-client:report 1: reply to
org.freedesktop.DBus.Binding.Tests.Trigger didn't arrive
INFO:cross-test-client:asking server to Exit
INFO:cross-test-server:signal/callback: Sent Response
INFO:cross-test-server:client wants me to Exit
INFO:cross-test-server:will quit when idle
INFO:cross-test-client:server says it will exit
INFO:cross-test-client:main loop exited.
INFO:cross-test-server:method/signal: Emitting Triggered(dbus.UInt64(42L)) from
dbus.UTF8String('/Where/Ever')
INFO:cross-test-server:method/signal: Emitted Triggered
INFO:cross-test-server:main loop exited.
dbus-daemon[16779]: [session uid=2912 pid=16779] Reloaded configuration
dbus-daemon[16779]: [session uid=2912 pid=16779] Reloaded configuration
org.freedesktop.DBus.Binding.Tests.Trigger fail 1
The failing test is part of an interface intended to be an
interoperability test between D-Bus language bindings (I think only
dbus-python and dbus-java ever actually implemented it), so the confusing
names unfortunately can't be changed.
* client logs "method/signal: Triggering signal"
* record that a response to Tests.Trigger is expected
* client calls Tests.Trigger() method on server, asynchronously
* server implements Tests.Trigger() as follows:
- log "method/signal: client wants me to emit Triggered(%r) from %r"
- record that Tests.Trigger() was tested
- send back a successful reply to the client, which causes this:
+ client logs "method/signal: Trigger() returned
+ client logs "signal/callback: Emitting signal to trigger callback"
+ client emits signal SignalTests.Trigger(42, 23)
+ client logs "signal/callback: Emitting signal returned"
- next time the server returns to its main loop:
+ log "method/signal: Emitting Triggered(%r) from %r"
+ create an object at the given object path
+ emit SignalTests.Triggered signal from it
+ log "method/signal: Emitted Triggered"
* client responds to SignalTests.Triggered as follows:
- log "method/signal: Triggered(%r) by %r"
- record that a response to Tests.Trigger was received
- do some checks on the parameters
- log "Tests.Trigger pass"
* server responds to SignalTests.Trigger as follows:
- log "signal/callback: Triggered by client (%s:%s): (%r,%r)"
- record that SignalTests.Trigger was tested
- call CallbackTests.Response() method on the client, blocking for a
reply
- log "signal/callback: Sent Response"
* client implements CallbackTests.Response() as follows:
- log "signal/callback: Response received (%r,%r)"
- record that a response to SignalTests.Trigger was received
- check the parameters
- log "SignalTests.Trigger pass"
- check that every expected reply has arrived
- call Tests.Exit() on the server, asynchronously
+ on success, log "server says it will exit" and quit the main loop
+ 1 second later, quit the main loop anyway
There is a race condition here between these chains of events, which as
far as I can tell has existed for at least 10 years:
* server receives Tests.Trigger() and schedules SignalTests.Triggered
* server returns to main loop
* server emits SignalTests.Triggered
* client receives SignalTests.Triggered
and
* server receives Tests.Trigger() and replies with success
* client receives success and emits SignalTests.Trigger
* server receives SignalTests.Trigger and calls CallbackTests.Response()
* client receives CallbackTests.Response() and calls Tests.Exit()
* server receives Tests.Exit() and replies with success
* client quits its main loop
Solution: don't reply to Tests.Trigger() until after the
SignalTests.Triggered signal has been sent. Because the client called
Tests.Trigger() asynchronously, messages are not re-ordered and the reply
arrives after the signal, so the whole chain of events leading up to
"client receives SignalTests.Triggered" happens before
"client receives success and emits SignalTests.Trigger".
smcv