fixed bug #35305: pcb may be freed too early on shutdown(WR)

This commit is contained in:
goldsimon 2012-01-22 11:18:36 +01:00
parent 593f75fc3b
commit 4d71f7270b
3 changed files with 27 additions and 12 deletions

View File

@ -62,6 +62,9 @@ HISTORY
++ Bugfixes: ++ Bugfixes:
2012-01-22: Simon Goldschmidt
* tcp.c, tcp_in.c: fixed bug #35305: pcb may be freed too early on shutdown(WR)
2012-01-21: Simon Goldschmidt 2012-01-21: Simon Goldschmidt
* tcp.c: fixed bug #34636: FIN_WAIT_2 - Incorrect shutdown of TCP pcb * tcp.c: fixed bug #34636: FIN_WAIT_2 - Incorrect shutdown of TCP pcb

View File

@ -298,7 +298,9 @@ tcp_close(struct tcp_pcb *pcb)
/** /**
* Causes all or part of a full-duplex connection of this PCB to be shut down. * Causes all or part of a full-duplex connection of this PCB to be shut down.
* This doesn't deallocate the PCB! * This doesn't deallocate the PCB unless shutting down both sides!
* Shutting down both sides is the same as calling tcp_close, so if it succeds,
* the PCB should not be referenced any more.
* *
* @param pcb PCB to shutdown * @param pcb PCB to shutdown
* @param shut_rx shut down receive side if this is != 0 * @param shut_rx shut down receive side if this is != 0
@ -313,28 +315,32 @@ tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)
return ERR_CONN; return ERR_CONN;
} }
if (shut_rx) { if (shut_rx) {
/* shut down the receive side: free buffered data... */ /* shut down the receive side: set a flag not to receive any more data... */
pcb->flags |= TF_RXCLOSED;
if (shut_tx) {
/* shutting down the tx AND rx side is the same as closing for the raw API */
return tcp_close_shutdown(pcb, 1);
}
/* ... and free buffered data */
if (pcb->refused_data != NULL) { if (pcb->refused_data != NULL) {
pbuf_free(pcb->refused_data); pbuf_free(pcb->refused_data);
pcb->refused_data = NULL; pcb->refused_data = NULL;
} }
/* ... and set a flag not to receive any more data */
pcb->flags |= TF_RXCLOSED;
} }
if (shut_tx) { if (shut_tx) {
/* This can't happen twice since if it succeeds, the pcb's state is changed. /* This can't happen twice since if it succeeds, the pcb's state is changed.
Only close in these states as the others directly deallocate the PCB */ Only close in these states as the others directly deallocate the PCB */
switch (pcb->state) { switch (pcb->state) {
case SYN_RCVD: case SYN_RCVD:
case ESTABLISHED: case ESTABLISHED:
case CLOSE_WAIT: case CLOSE_WAIT:
return tcp_close_shutdown(pcb, 0); return tcp_close_shutdown(pcb, shut_rx);
default: default:
/* don't shut down other states */ /* Not (yet?) connected, cannot shutdown the TX side as that would bring us
break; into CLOSED state, where the PCB is deallocated. */
return ERR_CONN;
} }
} }
/* @todo: return another err_t if not in correct state or already shut? */
return ERR_OK; return ERR_OK;
} }

View File

@ -316,6 +316,12 @@ tcp_input(struct pbuf *p, struct netif *inp)
} else if (recv_flags & TF_CLOSED) { } else if (recv_flags & TF_CLOSED) {
/* The connection has been closed and we will deallocate the /* The connection has been closed and we will deallocate the
PCB. */ PCB. */
if (!(pcb->flags & TF_RXCLOSED)) {
/* Connection closed although the application has only shut down the
tx side: call the PCB's err callback and indicate the closure to
ensure the application doesn't continue using the PCB. */
TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_CLSD);
}
tcp_pcb_remove(&tcp_active_pcbs, pcb); tcp_pcb_remove(&tcp_active_pcbs, pcb);
memp_free(MEMP_TCP_PCB, pcb); memp_free(MEMP_TCP_PCB, pcb);
} else { } else {