From fb4cf009e5a7638dfbaf671e56d0cf1bc1595485 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AD=99=E6=98=A5=E9=98=B3?= Date: Tue, 30 Dec 2025 16:50:28 +0800 Subject: [PATCH] =?utf8?q?lwip=E5=A2=9E=E5=8A=A0=E5=AE=89=E5=85=A8?= =?utf8?q?=E9=98=B2=E6=8A=A4=EF=BC=8C=E9=98=B2=E6=AD=A2=E6=96=AD=E7=BD=91?= =?utf8?q?=E6=81=A2=E5=A4=8D=E5=BC=82=E5=B8=B8=E6=AD=BB=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../lwip/lwip_v2.1.3/src/api/api_msg.c | 125 +++++++++++++----- 1 file changed, 95 insertions(+), 30 deletions(-) diff --git a/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/api/api_msg.c b/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/api/api_msg.c index ab47f0da4..fe1d4a3ca 100644 --- a/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/api/api_msg.c +++ b/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/api/api_msg.c @@ -361,8 +361,20 @@ poll_tcp(void *arg, struct tcp_pcb *pcb) LWIP_UNUSED_ARG(pcb); LWIP_ASSERT("conn != NULL", (conn != NULL)); + /* 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) { + /* Connection was closed by err_tcp. Nothing to do. */ + return ERR_OK; + } + if (conn->state == NETCONN_WRITE) { - lwip_netconn_do_writemore(conn WRITE_DELAYED); + /* 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) { + lwip_netconn_do_writemore(conn WRITE_DELAYED); + } } else if (conn->state == NETCONN_CLOSE) { #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER if (conn->current_msg && conn->current_msg->msg.sd.polls_left) { @@ -403,8 +415,20 @@ sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) LWIP_ASSERT("conn != NULL", (conn != NULL)); if (conn) { + /* 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 sent_tcp was scheduled before err_tcp but executed after. */ + if (conn->pcb.tcp == NULL) { + /* Connection was closed by err_tcp. Nothing to do. */ + return ERR_OK; + } + if (conn->state == NETCONN_WRITE) { - lwip_netconn_do_writemore(conn WRITE_DELAYED); + /* 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) { + lwip_netconn_do_writemore(conn WRITE_DELAYED); + } } else if (conn->state == NETCONN_CLOSE) { lwip_netconn_do_close_internal(conn WRITE_DELAYED); } @@ -1706,6 +1730,16 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) #endif /* LWIP_SO_SNDTIMEO */ { do { + /* Runtime checks: verify pcb and vector are still valid before accessing them. + * These can become invalid if the connection was closed by another thread. */ + if (conn->pcb.tcp == NULL || conn->current_msg == NULL || + conn->current_msg->msg.w.vector == NULL) { + /* Connection was closed or message invalidated, abort write */ + err = ERR_CONN; + write_finished = 1; + break; + } + dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off; diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off; if (diff > 0xffffUL) { /* max_u16_t */ @@ -1714,6 +1748,13 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) } else { len = (u16_t)diff; } + + /* Re-check pcb validity before calling tcp_sndbuf */ + if (conn->pcb.tcp == NULL) { + err = ERR_CONN; + write_finished = 1; + break; + } available = tcp_sndbuf(conn->pcb.tcp); if (available < len) { /* don't try to write more than sendbuf */ @@ -1741,6 +1782,12 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) } else { write_more = 0; } + /* Re-check pcb validity before calling tcp_write */ + if (conn->pcb.tcp == NULL) { + err = ERR_CONN; + write_finished = 1; + break; + } err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); if (err == ERR_OK) { conn->current_msg->msg.w.offset += len; @@ -1759,16 +1806,19 @@ lwip_netconn_do_writemore(struct netconn *conn WRITE_DELAYED_PARAM) /* if OK or memory error, check available space */ if ((err == ERR_OK) || (err == ERR_MEM)) { err_mem: - 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); - conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; - } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || - (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { - /* The queued byte- or pbuf-count exceeds the configured low-water limit, - let select mark this pcb as non-writable. */ - API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); + /* 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)) { + /* 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); + conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; + } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || + (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { + /* The queued byte- or pbuf-count exceeds the configured low-water limit, + let select mark this pcb as non-writable. */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0); + } } } @@ -1778,13 +1828,19 @@ err_mem: /* return sent length (caller reads length from msg.w.offset) */ write_finished = 1; } - out_err = tcp_output(conn->pcb.tcp); - if (out_err == ERR_RTE) { - /* If tcp_output fails because no route is found, - don't try writing any more but return the error - to the application thread. */ - err = out_err; + /* Re-check pcb validity before calling tcp_output */ + if (conn->pcb.tcp == NULL) { + err = ERR_CONN; write_finished = 1; + } else { + out_err = tcp_output(conn->pcb.tcp); + if (out_err == ERR_RTE) { + /* If tcp_output fails because no route is found, + don't try writing any more but return the error + to the application thread. */ + err = out_err; + write_finished = 1; + } } } else if (err == ERR_MEM) { /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called. @@ -1793,18 +1849,24 @@ err_mem: will remain non-writable until sent_tcp/poll_tcp is called */ /* tcp_write returned ERR_MEM, try tcp_output anyway */ - err_t out_err = tcp_output(conn->pcb.tcp); - if (out_err == ERR_RTE) { - /* If tcp_output fails because no route is found, - don't try writing any more but return the error - to the application thread. */ - err = out_err; - write_finished = 1; - } else if (dontblock) { - /* non-blocking write is done on ERR_MEM, set error according - to partial write or not */ - err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; + /* Re-check pcb validity before calling tcp_output */ + if (conn->pcb.tcp == NULL) { + err = ERR_CONN; write_finished = 1; + } else { + err_t out_err = tcp_output(conn->pcb.tcp); + if (out_err == ERR_RTE) { + /* If tcp_output fails because no route is found, + don't try writing any more but return the error + to the application thread. */ + err = out_err; + write_finished = 1; + } else if (dontblock) { + /* non-blocking write is done on ERR_MEM, set error according + to partial write or not */ + err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK; + write_finished = 1; + } } } else { /* On errors != ERR_MEM, we don't try writing any more but return @@ -1817,8 +1879,11 @@ err_mem: and back to application task */ sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg); conn->current_msg->err = err; - conn->current_msg = NULL; + /* Reset state BEFORE clearing current_msg to avoid race condition: + * If poll_tcp/sent_tcp is called between these two assignments, + * we want state to be NETCONN_NONE (not NETCONN_WRITE) when current_msg is NULL */ conn->state = NETCONN_NONE; + conn->current_msg = NULL; #if LWIP_TCPIP_CORE_LOCKING if (delayed) #endif -- 2.17.1