Skip to content

Conversation

Junius00
Copy link
Contributor

@Junius00 Junius00 commented Jul 21, 2025

Description

I've noticed a subtle race condition in the returned message IDs when using esp_mqtt_client_subscribe_multiple() and esp_mqtt_client_unsubscribe():

  • Both return the message ID to the caller via return client->mqtt_state.pending_msg_id, i.e., a pointer
  • This return occurs after the API is unlocked via MQTT_API_UNLOCK(client)
  • If multiple threads are using the client, then this return value could possibly be altered by another API call in the following manner:
    1. Return value is intended to be client->mqtt_state.pending_msg_id = 4 (for example), and call unlocks.
    2. Context switch occurs before return happens.
    3. Another API call modifies client->mqtt_state.pending_msg_id = 5. (e.g., in the incremental case)
    4. Context switches back to original call, which now returns the wrong value of 5, even though the MQTT message was sent with message ID 4.

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

  1. Set the MQTT_MSG_ID_INCREMENTAL config.
  2. Create a FreeRTOS task function that uses esp_mqtt_client_subscribe() / esp_mqtt_client_unsubscribe(), and logs the message ID received.
  3. Use xTaskCreate() to create multiple instances of the same task function.
  4. Observe any message ID duplicates.

If an event handler is also registered using esp_mqtt_client_register_event(), then the 'lost' message IDs can be compared by printing event_data->msg_id for MQTT_EVENT_SUBSCRIBED / MQTT_EVENT_UNSUBSCRIBED events, i.e., seeing something like:

esp_mqtt_client_subscribe() message ID: 1
esp_mqtt_client_subscribe() message ID: 2
MQTT_EVENT_SUBSCRIBED message ID: 1
esp_mqtt_client_subscribe() message ID: 4 // this was supposed to be '3', but was overwritten
esp_mqtt_client_subscribe() message ID: 4
MQTT_EVENT_SUBSCRIBED message ID: 2
MQTT_EVENT_SUBSCRIBED message ID: 3 // this is the 'lost' message ID
MQTT_EVENT_SUBSCRIBED message ID: 4

@github-actions github-actions bot changed the title fix: subscribe/unsubscribe message ID race condition fix: subscribe/unsubscribe message ID race condition (IDFGH-16024) Jul 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants