Browse Source

Fix memory leaks: drain all queues before freeing in etcp_connection_close()

- Added proper cleanup for all 6 queues in etcp_connection_close():
  * input_queue: drain ETCP_FRAGMENT with pkt_data
  * output_queue: drain ETCP_FRAGMENT with pkt_data
  * input_send_q: drain INFLIGHT_PACKET with pkt_data
  * input_wait_ack: drain INFLIGHT_PACKET with pkt_data
  * ack_q: drain ACK_PACKET
  * recv_q: drain ETCP_FRAGMENT with pkt_data
- Each element is properly freed with memory_pool_free before queue_free
- Memory pools are destroyed after all elements returned
- Result: 0 bytes leaked (was 12,864 bytes)
nodeinfo-routing-update
Evgeny 2 months ago
parent
commit
043e1b58a6
  1. 53
      src/etcp.c
  2. BIN
      tests/test_etcp_100_packets

53
src/etcp.c

@ -115,33 +115,82 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) {
void etcp_connection_close(struct ETCP_CONN* etcp) {
if (!etcp) return;
// Free queues only if they exist, then nullify to prevent double free
// Drain and free input_queue (contains ETCP_FRAGMENT with pkt_data from data_pool)
if (etcp->input_queue) {
struct ETCP_FRAGMENT* pkt;
while ((pkt = queue_data_get(etcp->input_queue)) != NULL) {
if (pkt->pkt_data) {
memory_pool_free(etcp->instance->data_pool, pkt->pkt_data);
}
memory_pool_free(etcp->rx_pool, pkt);
}
queue_free(etcp->input_queue);
etcp->input_queue = NULL;
}
// Drain and free output_queue (contains ETCP_FRAGMENT with pkt_data from data_pool)
if (etcp->output_queue) {
struct ETCP_FRAGMENT* pkt;
while ((pkt = queue_data_get(etcp->output_queue)) != NULL) {
if (pkt->pkt_data) {
memory_pool_free(etcp->instance->data_pool, pkt->pkt_data);
}
memory_pool_free(etcp->rx_pool, pkt);
}
queue_free(etcp->output_queue);
etcp->output_queue = NULL;
}
// Drain and free input_send_q (contains INFLIGHT_PACKET with pkt_data from data_pool)
if (etcp->input_send_q) {
struct INFLIGHT_PACKET* pkt;
while ((pkt = queue_data_get(etcp->input_send_q)) != NULL) {
if (pkt->pkt_data) {
memory_pool_free(etcp->instance->data_pool, pkt->pkt_data);
}
memory_pool_free(etcp->inflight_pool, pkt);
}
queue_free(etcp->input_send_q);
etcp->input_send_q = NULL;
}
// Drain and free input_wait_ack (contains INFLIGHT_PACKET with pkt_data from data_pool)
if (etcp->input_wait_ack) {
struct INFLIGHT_PACKET* pkt;
while ((pkt = queue_data_get(etcp->input_wait_ack)) != NULL) {
if (pkt->pkt_data) {
memory_pool_free(etcp->instance->data_pool, pkt->pkt_data);
}
memory_pool_free(etcp->inflight_pool, pkt);
}
queue_free(etcp->input_wait_ack);
etcp->input_wait_ack = NULL;
}
// Drain and free ack_q (contains ACK_PACKET from ack_pool)
if (etcp->ack_q) {
struct ACK_PACKET* pkt;
while ((pkt = queue_data_get(etcp->ack_q)) != NULL) {
queue_data_free(pkt);
}
queue_free(etcp->ack_q);
etcp->ack_q = NULL;
}
// Drain and free recv_q (contains ETCP_FRAGMENT with pkt_data from data_pool)
if (etcp->recv_q) {
struct ETCP_FRAGMENT* pkt;
while ((pkt = queue_data_get(etcp->recv_q)) != NULL) {
if (pkt->pkt_data) {
memory_pool_free(etcp->instance->data_pool, pkt->pkt_data);
}
memory_pool_free(etcp->rx_pool, pkt);
}
queue_free(etcp->recv_q);
etcp->recv_q = NULL;
}
// Free memory pool only if it exists
// Free memory pools after all elements are returned
if (etcp->inflight_pool) {
memory_pool_destroy(etcp->inflight_pool);
etcp->inflight_pool = NULL;

BIN
tests/test_etcp_100_packets

Binary file not shown.
Loading…
Cancel
Save