Symptom
HIL DUT 01d7f344 (Ethernet primary, W5500 over SPI, IDF 5.5.4): LoadProhibited in w5500_tsk ~150 s after boot, reproducible every boot, on any image where one extra ~4.3 KB internal-DRAM allocation is made at tether start (a FreeRTOS TCB + 4 KB stack). Same code with that allocation moved to PSRAM: no crash in 360 s+. main alone: no crash. Bisected in #135 (three builds); details in that PR body.
Coredump (decoded against the crashing ELF, v1.2-21-gb467f85)
exccause 0x1c LoadProhibited, excvaddr 0x0
#1 uninstall_priv_desc (spi_master.c:1176) memcpy(orig_rx_buffer, trans_buf->buffer_to_rcv, ...)
#5 w5500_spi_read (value=0x3fcccbbc, len=1494)
#6 w5500_read (emac=0x5d6 ...) <- emac pointer garbage
#7 w5500_read_buffer (buffer=0x3fcccbbc, len=1494) <- emac->rx_buffer is a w5500_tsk STACK address
#8 emac_w5500_receive (mac=0x3fccb388, buf=0x3fcf74d0)
#9 emac_w5500_task
emac->rx_buffer should be the heap_caps_malloc(ETH_MAX_PACKET_SIZE, MALLOC_CAP_DMA) block from emac_w5500_new; here it reads as a stack address, and trans_buf->buffer_to_rcv is NULL. The emac_w5500_t struct is being overwritten by a neighbour in internal DRAM. The FreeRTOS stack canary never fired on any task, so it is not a task-stack overflow; the write comes from whoever owns the block adjacent to emac, and which block that is depends on allocation order (hence "only with one more allocation").
Raw coredump: ops/coredumps/2026-09-17-dut-w5500-rx-v1.2-21-gb467f85.bin (ESP coredump format, 24-byte header). Decode with esp_coredump info_corefile -t raw against the ELF in ops/elf-archive/ (build is not bit-reproducible, so strip the header and load in gdb, or rebuild b467f85).
Not yet known
- Which allocation writes past its end. Candidates by proximity at tether start:
esp_netif_new internals, TinyUSB task/queues (tinyusb_driver_install), the W5500 alloc_recv_buf (1522 B per frame, freed per frame — heap churn right at the crash site).
- Whether
heap_caps_check_integrity_all() at 1 Hz on a bench build catches the first corrupt block (cheap next step).
Why it matters
#135 sidesteps it (PSRAM stack), but the corruption is main's and will surface again with the next unrelated internal-DRAM allocation. Also motivated #145 (the crash loop never tripped the rollback ladder).
Symptom
HIL DUT
01d7f344(Ethernet primary, W5500 over SPI, IDF 5.5.4):LoadProhibitedinw5500_tsk~150 s after boot, reproducible every boot, on any image where one extra ~4.3 KB internal-DRAM allocation is made at tether start (a FreeRTOS TCB + 4 KB stack). Same code with that allocation moved to PSRAM: no crash in 360 s+.mainalone: no crash. Bisected in #135 (three builds); details in that PR body.Coredump (decoded against the crashing ELF,
v1.2-21-gb467f85)emac->rx_buffershould be theheap_caps_malloc(ETH_MAX_PACKET_SIZE, MALLOC_CAP_DMA)block fromemac_w5500_new; here it reads as a stack address, andtrans_buf->buffer_to_rcvis NULL. Theemac_w5500_tstruct is being overwritten by a neighbour in internal DRAM. The FreeRTOS stack canary never fired on any task, so it is not a task-stack overflow; the write comes from whoever owns the block adjacent toemac, and which block that is depends on allocation order (hence "only with one more allocation").Raw coredump:
ops/coredumps/2026-09-17-dut-w5500-rx-v1.2-21-gb467f85.bin(ESP coredump format, 24-byte header). Decode withesp_coredump info_corefile -t rawagainst the ELF inops/elf-archive/(build is not bit-reproducible, so strip the header and load in gdb, or rebuildb467f85).Not yet known
esp_netif_newinternals, TinyUSB task/queues (tinyusb_driver_install), the W5500alloc_recv_buf(1522 B per frame, freed per frame — heap churn right at the crash site).heap_caps_check_integrity_all()at 1 Hz on a bench build catches the first corrupt block (cheap next step).Why it matters
#135 sidesteps it (PSRAM stack), but the corruption is
main's and will surface again with the next unrelated internal-DRAM allocation. Also motivated #145 (the crash loop never tripped the rollback ladder).