/* Fundamental fix: Check if connection is still valid before processing any state.
* If pcb is NULL, it means err_tcp was called and the connection is closed.
* This can happen if poll_tcp was scheduled before err_tcp but executed after. */
- if (conn->pcb.tcp == NULL) {
+ if (conn->pcb.tcp == NULL || conn->state == NETCONN_NONE) {
/* Connection was closed by err_tcp. Nothing to do. */
return ERR_OK;
}
if (conn->state == NETCONN_WRITE) {
/* Only proceed if current_msg is valid. If it's NULL, the write operation
* was already completed or aborted, but state wasn't reset yet. */
- if (conn->current_msg != NULL) {
+ /* Re-check state and current_msg before calling lwip_netconn_do_writemore */
+ if (conn->current_msg != NULL && conn->state == NETCONN_WRITE && conn->pcb.tcp != NULL) {
lwip_netconn_do_writemore(conn WRITE_DELAYED);
}
} else if (conn->state == NETCONN_CLOSE) {
if (conn->state == NETCONN_WRITE) {
/* Only proceed if current_msg is valid. If it's NULL, the write operation
* was already completed or aborted, but state wasn't reset yet. */
- if (conn->current_msg != NULL) {
+ /* Re-check state and current_msg before calling lwip_netconn_do_writemore */
+ if (conn->current_msg != NULL && conn->state == NETCONN_WRITE && conn->pcb.tcp != NULL) {
lwip_netconn_do_writemore(conn WRITE_DELAYED);
}
} else if (conn->state == NETCONN_CLOSE) {
return ERR_CONN;
}
+ /* Re-check before accessing current_msg members (err_tcp may have cleared it) */
+ if (conn->current_msg == NULL || conn->state != NETCONN_WRITE) {
+ return ERR_CONN;
+ }
+
LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len",
conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len);
LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0);
+ /* Save apiflags immediately after check to minimize race window */
+ if (conn->current_msg == NULL || conn->state != NETCONN_WRITE) {
+ return ERR_CONN;
+ }
apiflags = conn->current_msg->msg.w.apiflags;
dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
#if LWIP_SO_SNDTIMEO
/* Re-check current_msg validity before accessing timeout fields */
- if (conn->current_msg != NULL && (conn->send_timeout != 0) &&
- ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
- write_finished = 1;
- if (conn->current_msg->msg.w.offset == 0) {
- /* nothing has been written */
- err = ERR_WOULDBLOCK;
- } else {
- /* partial write */
- err = ERR_OK;
+ if (conn->current_msg != NULL && conn->state == NETCONN_WRITE && (conn->send_timeout != 0)) {
+ /* Re-check again before accessing time_started (err_tcp may have cleared current_msg) */
+ if (conn->current_msg != NULL && conn->state == NETCONN_WRITE &&
+ ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
+ write_finished = 1;
+ /* Re-check before accessing offset */
+ if (conn->current_msg != NULL && conn->state == NETCONN_WRITE) {
+ if (conn->current_msg->msg.w.offset == 0) {
+ /* nothing has been written */
+ err = ERR_WOULDBLOCK;
+ } else {
+ /* partial write */
+ err = ERR_OK;
+ }
+ } else {
+ err = ERR_CONN;
+ write_finished = 1;
+ }
}
- } else
+ }
+ if (!write_finished)
#endif /* LWIP_SO_SNDTIMEO */
{
do {
}
}
/* Re-check current_msg and vector validity before accessing them */
- if (conn->current_msg == NULL || conn->current_msg->msg.w.vector == NULL) {
+ if (conn->current_msg == NULL || conn->current_msg->msg.w.vector == NULL || conn->state != NETCONN_WRITE) {
err = ERR_CONN;
write_finished = 1;
break;
1) We couldn't finish the current vector because of 16-bit size limitations.
tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes
2) We are sending the remainder of the current vector and have more */
+ /* Re-check before accessing vector_cnt */
+ if (conn->current_msg == NULL || conn->state != NETCONN_WRITE) {
+ err = ERR_CONN;
+ write_finished = 1;
+ break;
+ }
if ((len == 0xffff && diff > 0xffffUL) ||
(len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) {
write_more = 1;
err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
if (err == ERR_OK) {
/* Re-check current_msg validity after tcp_write (err_tcp may have been called) */
- if (conn->current_msg == NULL) {
+ if (conn->current_msg == NULL || conn->state != NETCONN_WRITE) {
err = ERR_CONN;
write_finished = 1;
break;
conn->current_msg->msg.w.vector_off += len;
/* check if current vector is finished */
/* Re-check current_msg and vector validity before accessing vector->len */
- if (conn->current_msg == NULL || conn->current_msg->msg.w.vector == NULL) {
+ if (conn->current_msg == NULL || conn->current_msg->msg.w.vector == NULL || conn->state != NETCONN_WRITE) {
err = ERR_CONN;
write_finished = 1;
break;
}
if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) {
+ /* Re-check before modifying vector_cnt (err_tcp may have cleared current_msg) */
+ if (conn->current_msg == NULL || conn->state != NETCONN_WRITE) {
+ err = ERR_CONN;
+ write_finished = 1;
+ break;
+ }
conn->current_msg->msg.w.vector_cnt--;
/* if we have additional vectors, move on to them */
if (conn->current_msg->msg.w.vector_cnt > 0) {
+ /* Re-check before modifying vector pointer (err_tcp may have cleared current_msg) */
+ if (conn->current_msg == NULL || conn->state != NETCONN_WRITE) {
+ err = ERR_CONN;
+ write_finished = 1;
+ break;
+ }
conn->current_msg->msg.w.vector++;
conn->current_msg->msg.w.vector_off = 0;
}
if ((err == ERR_OK) || (err == ERR_MEM)) {
err_mem:
/* Re-check validity before accessing current_msg and pcb */
- if (conn->current_msg != NULL && conn->pcb.tcp != NULL) {
- if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) {
+ if (conn->current_msg != NULL && conn->pcb.tcp != NULL && conn->state == NETCONN_WRITE) {
+ /* Re-check again before accessing current_msg members */
+ if (conn->current_msg == NULL || conn->state != NETCONN_WRITE) {
+ /* Skip this block if current_msg was cleared */
+ } else if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) {
/* non-blocking write did not write everything: mark the pcb non-writable
and let poll_tcp check writable space to mark the pcb writable again */
API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);