diff --git a/doc/tasks.md b/doc/tasks.md index c015280d..15c5d2f7 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -220,6 +220,11 @@ в нескольких прогонах. В `test_dm_e2e` при teardown остаётся timer-leak (~68 узлов, `router_no_route`), не влияет на результат — стоит разобрать отдельно. +[ ] **lwip/proxy: утечка pcb в FIN_WAIT_2** — `tcp_shutdown(pcb,0,1)` (half-close по FIN от + exit) не ставит `TF_RXCLOSED`, поэтому таймаут FIN_WAIT_2 в `tcp_slowtmr` не срабатывает: + если браузер никогда не пришлёт FIN, pcb навсегда остаётся в FIN_WAIT_2 (утечка, не crash). + Двойной free по TIME_WAIT уже закрыт (detach по локальному закрытию + guard abort). + ## Открытые флаки [+] **test_chat_join_e2e** — сделано. Причина: ложный критерий успеха джойнера J. `wait_group_started()` проверял `senders_list` непуст в предположении «senders_list diff --git a/src/proxy/tcp_proxy_client.c b/src/proxy/tcp_proxy_client.c index 367f01bb..24582161 100644 --- a/src/proxy/tcp_proxy_client.c +++ b/src/proxy/tcp_proxy_client.c @@ -547,7 +547,7 @@ static void tcp_proxy_client_conn_detach(struct tcp_proxy_client_conn *pc) { // Проверка, что pc->pcb ещё не освобождён пулом (защита от висячего указателя: // таймер TIME_WAIT мог освободить pcb без err_cb). Возвращает 0 и сбрасывает // pc->pcb, если pcb освобождён; иначе 1 (pcb валиден). -static int tcp_proxy_client_pcb_valid(struct tcp_proxy_client_conn *pc, const char* why) { +static int tcp_proxy_client_pcb_guard(struct tcp_proxy_client_conn *pc, const char* why) { struct tcp_pcb* pcb = pc->pcb; struct lwip_tcp_ctx* ctx = pc->proxy ? pc->proxy->lwip : NULL; if (ctx && memory_pool_is_freed(ctx->pcb_pool, pcb)) { @@ -564,16 +564,11 @@ static int tcp_proxy_client_pcb_valid(struct tcp_proxy_client_conn *pc, const ch static void tcp_proxy_client_abort_pcb(struct tcp_proxy_client_conn *pc, const char* why) { if (!pc || !pc->pcb) return; struct tcp_pcb* pcb = pc->pcb; - if (!tcp_proxy_client_pcb_valid(pc, why)) return; + if (!tcp_proxy_client_pcb_guard(pc, why)) return; DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "PROXY %s pcb=%p state=%s sid=%08x", why, (void*)pcb, tcp_debug_state_str(pcb->state), pc->stream_id); - tcp_arg(pcb, NULL); - tcp_recv(pcb, NULL); - tcp_sent(pcb, NULL); - tcp_err(pcb, NULL); - tcp_poll(pcb, NULL, 0); + tcp_proxy_client_conn_detach(pc); tcp_abort(pcb); - pc->pcb = NULL; } // ==================================================================== @@ -615,7 +610,7 @@ static void tcp_proxy_client_handle_close(struct tcp_proxy_client* p, uint32_t s if (!pc) { DEBUG_WARN(DEBUG_CATEGORY_PROXY, "PROXY CLOSE sid=%08x — no conn, dropping", stream_id); return; } DEBUG_INFO(DEBUG_CATEGORY_PROXY, "PROXY REM_CLOSED sid=%08x fin_local=%d pcb=%p", stream_id, pc->fin_local, (void*)pc->pcb); pc->rem_closed = 1; - if (pc->pcb && tcp_proxy_client_pcb_valid(pc, "CLOSE")) { + if (pc->pcb && tcp_proxy_client_pcb_guard(pc, "CLOSE")) { DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "PROXY CLOSE pcb=%p state=%s sid=%08x", (void*)pc->pcb, tcp_debug_state_str(pc->pcb->state), stream_id); tcp_arg(pc->pcb, NULL);