Browse Source

memory_pool_is_freed + стратегические проверки на висячие указатели

memory_pool: memory_pool_is_freed(pool,obj) — поиск obj в free-списке

tw_pcbs (3 места): !ctx→halt и is_freed→halt в начале итерации
  — ловит висячий PCB до re-alloc и после re-alloc

etcp: is_freed→halt перед etcp_conn_input (caller + callee)
  — ловит pkt освобождённый до входа

tcp_alloc: убран старый скан tw_pcbs (заменён на is_freed)
все dangling проверки — halt (while(1)) вместо break/return
etcp-inflight-fix
Evgeny 4 months ago
parent
commit
3217f744f9
  1. 11
      lib/memory_pool.c
  2. 2
      lib/memory_pool.h
  3. 5
      src/etcp.c
  4. 9
      src/etcp_connections.c
  5. 30
      src/lwip_tcp/lwip_tcp.c
  6. 10
      src/lwip_tcp/lwip_tcp_in.c

11
lib/memory_pool.c

@ -141,3 +141,14 @@ void memory_pool_destroy(struct memory_pool* pool) {
pool->free_count = 0;
u_free(pool);
}
int memory_pool_is_freed(struct memory_pool* pool, void* obj)
{
if (!pool || !obj) return 0;
void* cur = pool->free_head;
while (cur) {
if (cur == obj) return 1;
cur = *(void**)cur;
}
return 0;
}

2
lib/memory_pool.h

@ -34,4 +34,6 @@ size_t memory_pool_get_total_free_blocks(void);
#define memory_pool_alloc(pool) memory_pool_alloc_impl(pool, PLOCATION)
#define memory_pool_free(pool, obj) memory_pool_free_impl(pool, obj, PLOCATION)
int memory_pool_is_freed(struct memory_pool* pool, void* obj);
#endif // MEMORY_POOL_H

5
src/etcp.c

@ -16,6 +16,7 @@
#include <math.h> // For bandwidth calcs
#include <limits.h> // For UINT16_MAX
#include "../lib/mem.h"
#include "../lib/memory_pool.h"
// Enable comprehensive debug output for ETCP module
#define DEBUG_CATEGORY_ETCP_DETAILED 1
@ -1277,6 +1278,10 @@ void etcp_ack_recv(struct ETCP_CONN* etcp, uint32_t seq, uint16_t ts, uint16_t d
void etcp_conn_input(struct ETCP_DGRAM* pkt) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
if (!pkt) return;
if (memory_pool_is_freed(pkt->link->etcp->instance->pkt_pool, pkt)) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_conn_input: pkt=%p ALREADY FREED in pkt_pool — HALTING", (void*)pkt);
volatile int _halt = 1; while (_halt) {}
}
if (!pkt->data_len) {
memory_pool_free(pkt->link->etcp->instance->pkt_pool, pkt);
return;

9
src/etcp_connections.c

@ -1730,8 +1730,13 @@ process_decrypted:
// log_dump("RECV decrypted:", pkt->data, pkt->data_len, link);
if (link->link_state == 3) etcp_conn_input(pkt);
else memory_pool_free(e_sock->instance->pkt_pool, pkt);
if (link->link_state == 3) {
if (memory_pool_is_freed(e_sock->instance->pkt_pool, pkt)) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_conn_input: pkt=%p ALREADY FREED in pkt_pool — HALTING", (void*)pkt);
volatile int _halt = 1; while (_halt) {}
}
etcp_conn_input(pkt);
} else memory_pool_free(e_sock->instance->pkt_pool, pkt);
return;
ec_fr:

30
src/lwip_tcp/lwip_tcp.c

@ -790,9 +790,12 @@ void tcp_slowtmr(struct lwip_tcp_ctx *ctx)
pcb = ctx->tw_pcbs;
while (pcb != NULL) {
if (!pcb->ctx) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS DANGLING pcb=%p ctx=NULL in tcp_slowtmr, clearing tw_pcbs", (void*)pcb);
ctx->tw_pcbs = NULL;
break;
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS DANGLING pcb=%p ctx=NULL in tcp_slowtmr — HALTING", (void*)pcb);
volatile int _halt = 1; while (_halt) {}
}
if (memory_pool_is_freed(pcb->ctx->pcb_pool, pcb)) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS DANGLING pcb=%p IS FREED in tcp_slowtmr — HALTING", (void*)pcb);
volatile int _halt = 1; while (_halt) {}
}
pcb_remove = 0;
@ -1033,9 +1036,12 @@ static void tcp_kill_timewait(struct lwip_tcp_ctx *ctx)
inactive = NULL;
for (pcb = ctx->tw_pcbs; pcb != NULL; pcb = pcb->next) {
if (!pcb->ctx) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS DANGLING pcb=%p ctx=NULL in tcp_kill_timewait, clearing tw_pcbs", (void*)pcb);
ctx->tw_pcbs = NULL;
return;
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS DANGLING pcb=%p ctx=NULL in tcp_kill_timewait — HALTING", (void*)pcb);
volatile int _halt = 1; while (_halt) {}
}
if (memory_pool_is_freed(pcb->ctx->pcb_pool, pcb)) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS DANGLING pcb=%p IS FREED in tcp_kill_timewait — HALTING", (void*)pcb);
volatile int _halt = 1; while (_halt) {}
}
if ((uint32_t)(ctx->ticks - pcb->tmr) >= inactivity) {
inactivity = ctx->ticks - pcb->tmr;
@ -1103,18 +1109,6 @@ struct tcp_pcb *tcp_alloc(struct lwip_tcp_ctx *ctx, uint8_t prio)
if (pcb != NULL) {
memset(pcb, 0, sizeof(struct tcp_pcb));
#ifdef DEBUG
{
struct tcp_pcb *_tmp;
for (_tmp = ctx->tw_pcbs; _tmp; _tmp = _tmp->next) {
if (_tmp == pcb) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "tcp_alloc: REUSED PCB %p STILL IN tw_pcbs! halting for debug", (void*)pcb);
volatile int _halt = 1;
while (_halt) {}
}
}
}
#endif
pcb->prio = prio;
pcb->ctx = ctx;
pcb->snd_buf = TCP_SND_BUF;

10
src/lwip_tcp/lwip_tcp_in.c

@ -211,10 +211,14 @@ void lwip_tcp_input(struct lwip_tcp_ctx *ctx, struct pbuf *p,
if (pcb == NULL) {
for (pcb = ctx->tw_pcbs; pcb != NULL; pcb = pcb->next) {
if (!pcb->ctx) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS DANGLING pcb=%p ctx=NULL in lwip_tcp_input, clearing tw_pcbs", (void*)pcb);
ctx->tw_pcbs = NULL;
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS DANGLING pcb=%p ctx=NULL in lwip_tcp_input — HALTING", (void*)pcb);
pbuf_free(p);
return;
volatile int _halt = 1; while (_halt) {}
}
if (memory_pool_is_freed(pcb->ctx->pcb_pool, pcb)) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS DANGLING pcb=%p IS FREED in lwip_tcp_input — HALTING", (void*)pcb);
pbuf_free(p);
volatile int _halt = 1; while (_halt) {}
}
if (pcb->remote_port == sport &&
pcb->local_port == dport &&

Loading…
Cancel
Save