fix: subscribe/unsubscribe message ID race condition (IDFGH-16024) #305
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
I've noticed a subtle race condition in the returned message IDs when using
esp_mqtt_client_subscribe_multiple()
andesp_mqtt_client_unsubscribe()
:return client->mqtt_state.pending_msg_id
, i.e., a pointerMQTT_API_UNLOCK(client)
client->mqtt_state.pending_msg_id = 4
(for example), and call unlocks.client->mqtt_state.pending_msg_id = 5
. (e.g., in the incremental case)This makes it possible for two API calls to return the same message ID when called at approximately the same time, with one API call losing access to its actual message ID, which can disrupt use cases where the message ID is required to be unique (at least for messages in close temporal proximity), or for use cases where future actions are dependent on the message ID (e.g., callbacks).
Testing
MQTT_MSG_ID_INCREMENTAL
config.esp_mqtt_client_subscribe()
/esp_mqtt_client_unsubscribe()
, and logs the message ID received.xTaskCreate()
to create multiple instances of the same task function.If an event handler is also registered using
esp_mqtt_client_register_event()
, then the 'lost' message IDs can be compared by printingevent_data->msg_id
forMQTT_EVENT_SUBSCRIBED
/MQTT_EVENT_UNSUBSCRIBED
events, i.e., seeing something like: