Defensively free pb when err != ERR_OK but pb != nullptr in both
recv_fn and s_queued_recv_fn. In practice lwip never sends data
with an error code, but this prevents a leak if it ever does.
Also add comment noting tcp_recved is deferred to read().
Consolidate the dequeue + shift + tcp_arg update into a single while
loop that skips null entries (freed by lwip while queued) and returns
the first valid PCB. Eliminates the duplicated shift/update logic.
Consolidate the dequeue + shift + tcp_arg update into a single while
loop that skips null entries (freed by lwip while queued) and returns
the first valid PCB. Eliminates the duplicated shift/update logic.
When LWIPRawImpl creation was deferred to the main-loop accept(),
the queued PCB had no recv callback registered. lwip's default
tcp_recv_null handler ACKs incoming data but drops it silently.
On ESP8266, lwip processes TCP segments in batches — if the SYN
completion and first data packet arrive in the same batch, the
API handshake data is lost, causing SocketClosedAPIError (EOF).
Fix: register temporary recv/err callbacks on queued PCBs that
buffer any data received before accept() creates the LWIPRawImpl.
The buffered data is transferred to the new socket via init().
The LWIPRawImpl object is only 20 bytes — no reason to heap-allocate it
in the callback on ESP8266 either. Store raw tcp_pcb pointers on both
platforms, removing the #ifdef branches and simplifying the code.
The LWIPRawImpl object is only 20 bytes — no reason to heap-allocate it
in the callback on ESP8266 either. Store raw tcp_pcb pointers on both
platforms, removing the #ifdef branches and simplifying the code.
- Check xPSR bit 9 to detect hardware alignment padding word in the
exception frame, fixing pre-fault SP and stack scan start offset
- Replace C-style pointer casts with reinterpret_cast<uintptr_t>
- Use idedata.firmware_elf_path instead of hardcoded path in decoder
Between accept_fn_ storing a raw PCB and accept() picking it up, the
connection could error (RST, timeout). Without an error callback, lwip
frees the PCB silently, leaving a dangling pointer. When accept() later
creates LWIPRawImpl with it, the use-after-free corrupts the heap.
Fix: register a lightweight error callback (no allocation) in accept_fn_
that nulls the array slot when the PCB is freed. accept() checks for
null and skips freed PCBs. After shifting the array, tcp_arg pointers
are updated for remaining entries.
Between accept_fn_ storing a raw PCB and accept() picking it up, the
connection could error (RST, timeout). Without an error callback, lwip
frees the PCB silently, leaving a dangling pointer. When accept() later
creates LWIPRawImpl with it, the use-after-free corrupts the heap.
Fix: register a lightweight error callback (no allocation) in accept_fn_
that nulls the array slot when the PCB is freed. accept() checks for
null and skips freed PCBs. After shifting the array, tcp_arg pointers
are updated for remaining entries.
- Add #if defined(PICO_RP2350) for SRAM end (520KB vs 264KB) so
stack scanning works on both RP2040 and RP2350
- Widen flash range check to 4MB for RP2350
- Add __attribute__((noreturn)) to hard_fault_handler_c
- Mark exc_return parameter as unused via /*exc_return*/
- Build addr2line hint line with all addresses (PC, LR, and BT*)
so users can copy-paste a single command for full decode
Add a crash handler for RP2040 that captures register state and stack
backtrace when a HardFault occurs, stores it in watchdog scratch
registers (which survive reboot), and logs it on the next boot.
- Override weak isr_hardfault with Cortex-M0+ compatible handler
- Save PC, LR, SP to watchdog scratch registers
- Scan stack for return addresses to provide deeper backtrace
- Log crash data immediately after logger initialization
- Add addr2line auto-decoding in CLI serial log viewer