When the MQTT WebSocket handshake fails before a connection is fully
established (e.g. "Sec-WebSocket-Accept not found"), the IDF v4
transport teardown path writes only 3 of the 4 bytes of the heap block
tail canary (expected 0xbaad5678, actual 0xbaad5600). The subsequent
esp_mqtt_client_destroy() call frees that block, causing multi_heap_free
to detect the broken canary and abort:
CORRUPT HEAP: Bad tail at 0x3fcb42a4. Expected 0xbaad5678 got 0xbaad5600
assert failed: multi_heap_free multi_heap_poisoning.c:259 (head != NULL)
The fix is to check heap integrity with heap_caps_check_integrity_all(false)
between esp_mqtt_client_stop() and esp_mqtt_client_destroy(). If corruption
is detected, scan internal SRAM (0x3FC00000–0x3FD00000) for the truncated
canary pattern and restore it to the correct value before
destroy() runs.
The scan is a no-op when the heap is clean and is compiled out entirely
on IDF v5+, where the underlying bug does not exist.
This fixes crash-on-reconnect observed with ESP32-S3 + IDF v4 + WSS transport.