Нашелся корень проблемы: void TCP_Client_Error_Callback(void *arg, err_t err)
{
...
if(tcp_client.pcb){
tcp_close(tcp_client.pcb); // <-- проблема
tcp_client.pcb = NULL;
}
...
}
Но по документации lwIP (tcp.h:113, коммент к tcp_err_fn):
The corresponding pcb is already freed when this callback is called!
Т.е. на момент вызова tcp_err callback-а lwIP уже освободил PCB обратно в пул memp (tcp_pcb_remove уже отработал, PCB убран из tcp_active_pcbs/tcp_tw_pcbs и возвращён в свободный список memp). Вызов tcp_close() на уже освобождённый указатель — это use-after-free: вы трогаете память, которая, возможно, уже переиспользована под другой PCB (например, под входящее серверное соединение в bridge.c, которое активно создаётся через tcp_new()/Bridge_Accept_Callback). Это портит связные списки (pcb->next), там образуется цикл, и следующий проход tcp_input() по tcp_active_pcbs циклится в for-цикле, который вы приводили — ровно там, где list corruption и проявляется.
Но проект я переделал под отдельную задачу FreeRTOS.