fix(mqtt): never hand back a half-initialized client or transport

esp_mqtt_client_init() succeeded without a registered event sink when
registration failed, and the WebSocket wrap returned a transport with
the unpadded SDK buffer when the padded allocation failed. Both paths
now fail cleanly instead, the IDF 4 WebSocket layout is pinned to the
validated patch level, and the connection flags esp-mqtt tasks write
become atomic.
This commit is contained in:
agessaman committed 2026-09-21 16:05:39 -07:00
1 parent 6124f3c139
commit 665ece1e12
6 files changed
+135 -27

No files matched your search

+13 -15
View File
@@ -62,7 +62,12 @@
#if ESP_IDF_VERSION_MAJOR == 4
#if ESP_IDF_VERSION_MINOR != 4 || ESP_IDF_VERSION_PATCH != 7
#error "Revalidate the private WebSocket layout before using another IDF 4 SDK"
#endif
#include <stdlib.h>
#include "RequiredTransportBuffer.h"
#include "sdkconfig.h"
#include "esp_transport.h"
#include "esp_transport_ws.h"
@@ -97,22 +102,15 @@ extern "C" {
esp_transport_handle_t __real_esp_transport_ws_init(esp_transport_handle_t parent_handle);
esp_transport_handle_t __wrap_esp_transport_ws_init(esp_transport_handle_t parent_handle) {
esp_transport_handle_t t = __real_esp_transport_ws_init(parent_handle);
if (t != nullptr) {
transport_ws_t* ws = (transport_ws_t*)esp_transport_get_context_data(t);
if (ws != nullptr && ws->buffer != nullptr) {
// The buffer is untouched at this point (allocated moments ago inside
// __real_esp_transport_ws_init), so a swap is safe.
char* padded = (char*)malloc(CONFIG_WS_BUFFER_SIZE + 1);
if (padded != nullptr) {
return initWithRequiredTransportBuffer<esp_transport_handle_t>(
CONFIG_WS_BUFFER_SIZE + 1, malloc,
[&]() { return __real_esp_transport_ws_init(parent_handle); },
[](esp_transport_handle_t transport, void* buffer) {
// Successful init in the pinned SDK guarantees this context and buffer.
transport_ws_t* ws = (transport_ws_t*)esp_transport_get_context_data(transport);
free(ws->buffer);
ws->buffer = padded;
}
// On alloc failure keep the original buffer: same behavior as before
// this fix, which is still strictly better than failing init here.
}
}
return t;
ws->buffer = static_cast<char*>(buffer);
}, free);
}
} // extern "C"