Fri 08 Feb 2013 11:13:29 PM UTC, comment #1:
Correction: For the fast connection case the first tcp_shudown call has only shut_rx set. The section should read:
With a fast connection (XGbE), i see:
tcp_shutdown with pcb->state == CLOSE_WAIT, shut_rx == 1, shut_tx == 0
tcp_shutdown with pcb->state == CLOSE_WAIT, shut_rx == 0, shut_tx == 2
memp_free(..., pcb) from tcp_input with pcb->state == CLOSED
tcp_close with pcb->state == CLOSED
memp_free(..., pcb) from tcp_close_shutdown with pcb->state == CLOSED
|
Fri 08 Feb 2013 10:09:22 PM UTC, original submission:
Symtom:
Can manifest as a silent crash or one of several assertion failures, most commonly:
FATAL: ASSERTION FAILED:
tcp_input: pcb->next != pcb (before cache)
in file ../../externals/lwip/src/core/tcp_in.c, at line 182
Can also be detected through heap instrumentation detecting a double free from tcp_close_shutdown().
To reproduce:
On a slow processor with a fast network connection, shutdown both sides of a socket and then close it.
ex.
// open socket, bind, listen, accept, receive, then
shutdown(fd, SHUT_RD);
// send response, then
shutdown(fd, SHUT_WR);
close(fd);
Further information:
The error only occures with a fast network connection. On a slow network connection I see the following sequence in the tcp layer, and all is well:
tcp_shutdown with pcb->state == CLOSE_WAIT, shut_rx == 1, shut_tx == 0
tcp_shutdown with pcb->state == CLOSE_WAIT, shut_rx == 0, shut_tx == 2
tcp_close with pcb->state == LAST_ACK
memp_free(..., pcb) from tcp_input with pcb->state == CLOSED
With a fast connection (XGbE), i see:
tcp_shutdown with pcb->state == CLOSE_WAIT, shut_rx == 1, shut_tx == 1
tcp_shutdown with pcb->state == CLOSE_WAIT, shut_rx == 0, shut_tx == 2
memp_free(..., pcb) from tcp_input with pcb->state == CLOSED
tcp_close with pcb->state == CLOSED
memp_free(..., pcb) from tcp_close_shutdown with pcb->state == CLOSED
The TCP layer seems to initiate deallocation of the tcp_pcb in response to shutdown of both sides, but the socket layer keeps a reference to the pcb (through netconn) until the file descriptor is deallocated by lwip_close(), at which point the possibly already deallocated pcb is closed by netconn_delete().
|