Environment
- esp-modbus:
1.0.18 / legacy master (a294764)
- ESP-IDF: 5.5
- Target: ESP32-S3, dual-core non-SMP FreeRTOS
Problem
When internal/DMA-capable RAM is exhausted during serial-master initialization, v1.0.18 does not fail transactionally.
In mbc_serial_master_create(), the interface is allocated with malloc(), the task handle is left indeterminate, and the failure path calls vTaskDelete() after xTaskCreatePinnedToCore() fails. On hardware this turned an ordinary allocation failure into a StoreProhibited write through address 0x8.
The UART startup path has the same class of bug: xMBMasterPortSerialInit() calls vTaskDelete(xMbTaskHandle) after failed task creation. A null task handle means the calling task in FreeRTOS; an uninitialized handle is worse.
The same initialization chain also has partial-allocation leaks:
portevent_m.c returns after individual allocation failures without rolling back earlier event groups/queue/semaphore.
porttimer_m.c leaks the timer context when esp_timer_create() fails.
The observed sequence was:
sdmmc_read_sectors: not enough mem
...
mbc_serial_master_create -> failed controller task allocation
vTaskDelete(invalid handle)
Guru Meditation Error: StoreProhibited, EXCVADDR=0x00000008
The SD error is useful context: even a one-sector DMA bounce allocation was already failing, so the following 4096-byte controller stack allocation was expected to fail. That failure should be recoverable.
Expected behavior
- Return
ESP_ERR_NO_MEM / FALSE without deleting an invalid or unrelated task.
- Roll back only resources whose ownership was successfully acquired.
- Leave close/destroy idempotent after a partially completed start.
- Permit a later initialization retry.
Downstream validation
We tested a repository-owned 1.0.18 fork which:
- zero-initializes task/resource handles;
- never calls
vTaskDelete() after failed task creation;
- transactionally unwinds controller, UART, event, and timer allocations;
- makes partial close/destroy idempotent; and
- synchronizes timer callbacks with close so a retiring context is not freed while a callback is in flight.
After the patch, repeated init -> batch/read -> deinit cycles passed on ESP32-S3 while a persistent WSS connection, HTTPS status sync, SD event writes, and remote console traffic were active. A live Modbus owner session also completed without panic. Allocation failure is now rejected cleanly instead of corrupting FreeRTOS state.
Current v2 main has redesigned/guarded cleanup and no longer contains these exact paths. Would Espressif accept a focused backport PR against legacy master for the v1.0.18 users still distributed through the component registry? I can split it into:
- controller/UART task-creation rollback; and
- event/timer partial-initialization rollback.
A deterministic regression test can fault-inject both task-creation calls and each resource allocation, assert a clean failure, then retry initialization successfully.
Environment
1.0.18/ legacymaster(a294764)Problem
When internal/DMA-capable RAM is exhausted during serial-master initialization, v1.0.18 does not fail transactionally.
In
mbc_serial_master_create(), the interface is allocated withmalloc(), the task handle is left indeterminate, and the failure path callsvTaskDelete()afterxTaskCreatePinnedToCore()fails. On hardware this turned an ordinary allocation failure into aStoreProhibitedwrite through address0x8.The UART startup path has the same class of bug:
xMBMasterPortSerialInit()callsvTaskDelete(xMbTaskHandle)after failed task creation. A null task handle means the calling task in FreeRTOS; an uninitialized handle is worse.The same initialization chain also has partial-allocation leaks:
portevent_m.creturns after individual allocation failures without rolling back earlier event groups/queue/semaphore.porttimer_m.cleaks the timer context whenesp_timer_create()fails.The observed sequence was:
The SD error is useful context: even a one-sector DMA bounce allocation was already failing, so the following 4096-byte controller stack allocation was expected to fail. That failure should be recoverable.
Expected behavior
ESP_ERR_NO_MEM/FALSEwithout deleting an invalid or unrelated task.Downstream validation
We tested a repository-owned 1.0.18 fork which:
vTaskDelete()after failed task creation;After the patch, repeated
init -> batch/read -> deinitcycles passed on ESP32-S3 while a persistent WSS connection, HTTPS status sync, SD event writes, and remote console traffic were active. A live Modbus owner session also completed without panic. Allocation failure is now rejected cleanly instead of corrupting FreeRTOS state.Current v2
mainhas redesigned/guarded cleanup and no longer contains these exact paths. Would Espressif accept a focused backport PR against legacymasterfor the v1.0.18 users still distributed through the component registry? I can split it into:A deterministic regression test can fault-inject both task-creation calls and each resource allocation, assert a clean failure, then retry initialization successfully.