paho.mqtt.python icon indicating copy to clipboard operation
paho.mqtt.python copied to clipboard

Client.loop_stop contains a race-condition

Open PromyLOPh opened this issue 1 year ago • 0 comments

Bug Description

Client.loop_stop expects that self._thread stays valid, but _thread_main unsets self._thread after exiting, causing a race-condition:

$ python3 test.py
Traceback (most recent call last):
  File "test.py", line 14, in <module>
    client.loop_stop()
  File "src/paho/mqtt/client.py", line 2365, in loop_stop
    self._thread.join()
    ^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'join'

Reproduction

Trigger it by applying this patch to paho-mqtt, which simply adds a wait, so _thread_main always wins the race:

diff --git a/src/paho/mqtt/client.py b/src/paho/mqtt/client.py
index 4ccc869..dc01f5e 100644
--- a/src/paho/mqtt/client.py
+++ b/src/paho/mqtt/client.py
@@ -2360,6 +2360,7 @@ class Client:
             return MQTTErrorCode.MQTT_ERR_INVAL

         self._thread_terminate = True
+        time.sleep (2)
         if threading.current_thread() != self._thread:
             self._thread.join()

Then run this minimal MQTT client:

import time

from paho.mqtt.client import Client
from paho.mqtt.enums import CallbackAPIVersion, MQTTProtocolVersion

client = Client(CallbackAPIVersion.VERSION2, 'testclient', protocol=MQTTProtocolVersion.MQTTv5)

client.loop_start()
client.connect(host='localhost')

time.sleep (2)

client.disconnect()
client.loop_stop()

Environment

  • Python version: Python 3.11.2
  • Library version: Commit d45de3737879cfe7a6acc361631fa5cb1ef584bb
  • Operating system (including version): Debian 12
  • MQTT server (name, version, configuration, hosting details): mosquitto 2.0.15 without any configuration.

PromyLOPh avatar Nov 27 '24 10:11 PromyLOPh