Skip to content

Commit 8391f90

Browse files
wangfuyuwangfuyu
andauthored
m) Fix: packet_in pool memory leak (litespeedtech#426)
[Reproduce] http_client POST large body request to http_server, like: http_client -H quic.test.com -s ${SERVER_ADDR}:${SERVER_PORT} -p /1KB_char.txt -M POST -P /test/quic-data/html/10KB_char.txt -o version=h3 -n 100 -r 50000000 -R 500 -w 10 -K [Notes] [RFC5116 AEAD] Section 5.1 An authentication tag with a length of 16 octets (128bits) is used. [RFC9001 QUIC-TLS] Section 5.3 These cipher suites have a 16-byte authentication tag and produce an output 16 bytes larger than their input. Co-authored-by: wangfuyu <ivanfywang@gmail.com>
1 parent 108c4e7 commit 8391f90

File tree

4 files changed

+118
-10
lines changed

4 files changed

+118
-10
lines changed

src/liblsquic/lsquic_enc_sess_ietf.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2243,7 +2243,16 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
22432243
size_t out_sz;
22442244
enum dec_packin dec_packin;
22452245
int s;
2246-
const size_t dst_sz = packet_in->pi_data_sz;
2246+
/* 16Bytes: AEAD authentication tag
2247+
*
2248+
* [RFC5116 AEAD] Section 5.1
2249+
* An authentication tag with a length of 16 octets (128bits) is used.
2250+
*
2251+
* [RFC9001 QUIC-TLS] Section 5.3
2252+
* These cipher suites have a 16-byte authentication tag and
2253+
* produce an output 16 bytes larger than their input.
2254+
*/
2255+
const size_t dst_sz = packet_in->pi_data_sz - 16;
22472256
unsigned char new_secret[EVP_MAX_KEY_LENGTH];
22482257
struct crypto_ctx crypto_ctx_buf;
22492258
char secret_str[EVP_MAX_KEY_LENGTH * 2 + 1];

src/liblsquic/lsquic_engine.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ struct lsquic_engine
261261
unsigned n_conns;
262262
lsquic_time_t deadline;
263263
lsquic_time_t resume_sending_at;
264+
lsquic_time_t mem_logged_last;
264265
unsigned mini_conns_count;
265266
struct lsquic_purga *purga;
266267
#if LSQUIC_CONN_STATS
@@ -960,6 +961,51 @@ destroy_conn (struct lsquic_engine *engine, struct lsquic_conn *conn,
960961
--engine->n_conns;
961962
conn->cn_flags |= LSCONN_NEVER_TICKABLE;
962963
conn->cn_if->ci_destroy(conn);
964+
965+
if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG) /* log period: 10s */
966+
&& ((engine->mem_logged_last + 10000000 <= now) || (engine->n_conns == 0)))
967+
{
968+
#define MAX_MM_STAT_LOG 4096
969+
unsigned cur = 0;
970+
unsigned ret = 0;
971+
unsigned idx = 0;
972+
char mm_log[MAX_MM_STAT_LOG] = {0};
973+
struct pool_stats *poolst = NULL;
974+
975+
engine->mem_logged_last = now;
976+
977+
ret = snprintf(mm_log + cur, MAX_MM_STAT_LOG - cur,
978+
"%p, conns: %u, mini_conns: %u. mm_stat, used: %zu"
979+
", pool(calls-objs_all-objs_out-max-avg-var), pib",
980+
engine, engine->n_conns, engine->mini_conns_count,
981+
lsquic_mm_mem_used(&engine->pub.enp_mm));
982+
cur += ret;
983+
984+
for (idx = 0; idx < MM_N_IN_BUCKETS && cur < MAX_MM_STAT_LOG; idx++)
985+
{
986+
poolst = &engine->pub.enp_mm.packet_in_bstats[idx];
987+
ret = snprintf(mm_log + cur, MAX_MM_STAT_LOG - cur,
988+
": [%u]%u-%u-%u-%u-%u-%u", idx,
989+
poolst->ps_calls, poolst->ps_objs_all, poolst->ps_objs_out,
990+
poolst->ps_max, poolst->ps_max_avg, poolst->ps_max_var);
991+
cur += ret;
992+
}
993+
994+
ret = snprintf(mm_log + cur, MAX_MM_STAT_LOG - cur, ", pob");
995+
cur += ret;
996+
997+
for (idx = 0; idx < MM_N_OUT_BUCKETS && cur < MAX_MM_STAT_LOG; idx++)
998+
{
999+
poolst = &engine->pub.enp_mm.packet_out_bstats[idx];
1000+
ret = snprintf(mm_log + cur, MAX_MM_STAT_LOG - cur,
1001+
": [%u]%u-%u-%u-%u-%u-%u", idx,
1002+
poolst->ps_calls, poolst->ps_objs_all, poolst->ps_objs_out,
1003+
poolst->ps_max, poolst->ps_max_avg, poolst->ps_max_var);
1004+
cur += ret;
1005+
}
1006+
1007+
LSQ_DEBUG("%s", mm_log);
1008+
}
9631009
}
9641010

9651011

src/liblsquic/lsquic_mm.c

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,21 +192,15 @@ void
192192
lsquic_mm_put_packet_in (struct lsquic_mm *mm,
193193
struct lsquic_packet_in *packet_in)
194194
{
195-
#if LSQUIC_USE_POOLS
196-
unsigned idx;
197-
struct packet_in_buf *pib;
198-
199195
assert(0 == packet_in->pi_refcnt);
200196
if (packet_in->pi_flags & PI_OWN_DATA)
201197
{
202-
pib = (struct packet_in_buf *) packet_in->pi_data;
203-
idx = packet_in_index(packet_in->pi_data_sz);
204-
SLIST_INSERT_HEAD(&mm->packet_in_bufs[idx], pib, next_pib);
198+
lsquic_mm_put_packet_in_buf(mm, packet_in->pi_data, packet_in->pi_data_sz);
205199
}
200+
201+
#if LSQUIC_USE_POOLS
206202
TAILQ_INSERT_HEAD(&mm->free_packets_in, packet_in, pi_next);
207203
#else
208-
if (packet_in->pi_flags & PI_OWN_DATA)
209-
free(packet_in->pi_data);
210204
lsquic_malo_put(packet_in);
211205
#endif
212206
}
@@ -370,6 +364,42 @@ maybe_shrink_packet_out_bufs (struct lsquic_mm *mm, unsigned idx)
370364
#endif
371365

372366

367+
/* If average maximum falls under 1/4 of all objects allocated, release
368+
* half of the objects allocated.
369+
*/
370+
static void
371+
maybe_shrink_packet_in_bufs (struct lsquic_mm *mm, unsigned idx)
372+
{
373+
struct pool_stats *poolst;
374+
struct packet_in_buf *pib;
375+
unsigned n_to_leave;
376+
377+
poolst = &mm->packet_in_bstats[idx];
378+
if (poolst->ps_max_avg * 4 < poolst->ps_objs_all)
379+
{
380+
n_to_leave = poolst->ps_objs_all / 2;
381+
while (poolst->ps_objs_all > n_to_leave
382+
&& (pib = SLIST_FIRST(&mm->packet_in_bufs[idx])))
383+
{
384+
SLIST_REMOVE_HEAD(&mm->packet_in_bufs[idx], next_pib);
385+
free(pib);
386+
--poolst->ps_objs_all;
387+
}
388+
#if LSQUIC_LOG_POOL_STATS
389+
LSQ_DEBUG("pib pool #%u; max avg %u; shrank from %u to %u objs",
390+
idx, poolst->ps_max_avg, n_to_leave * 2, poolst->ps_objs_all);
391+
#endif
392+
}
393+
#if LSQUIC_LOG_POOL_STATS
394+
else
395+
{
396+
LSQ_DEBUG("pib pool #%u; max avg %u; objs: %u; won't shrink",
397+
idx, poolst->ps_max_avg, poolst->ps_objs_all);
398+
}
399+
#endif
400+
}
401+
402+
373403
void
374404
lsquic_mm_put_packet_out (struct lsquic_mm *mm,
375405
struct lsquic_packet_out *packet_out)
@@ -456,9 +486,25 @@ lsquic_mm_get_packet_in_buf (struct lsquic_mm *mm, size_t size)
456486
pib = SLIST_FIRST(&mm->packet_in_bufs[idx]);
457487
fiu_do_on("mm/packet_in_buf", FAIL_NOMEM);
458488
if (pib)
489+
{
459490
SLIST_REMOVE_HEAD(&mm->packet_in_bufs[idx], next_pib);
491+
poolst_allocated(&mm->packet_in_bstats[idx], 0);
492+
}
460493
else
494+
{
461495
pib = malloc(packet_in_sizes[idx]);
496+
if (!pib)
497+
{
498+
return NULL;
499+
}
500+
501+
poolst_allocated(&mm->packet_in_bstats[idx], 1);
502+
}
503+
504+
if (poolst_has_new_sample(&mm->packet_in_bstats[idx]))
505+
{
506+
maybe_shrink_packet_in_bufs(mm, idx);
507+
}
462508
#else
463509
pib = malloc(size);
464510
#endif
@@ -476,6 +522,12 @@ lsquic_mm_put_packet_in_buf (struct lsquic_mm *mm, void *mem, size_t size)
476522
pib = (struct packet_in_buf *) mem;
477523
idx = packet_in_index(size);
478524
SLIST_INSERT_HEAD(&mm->packet_in_bufs[idx], pib, next_pib);
525+
526+
poolst_freed(&mm->packet_in_bstats[idx]);
527+
if (poolst_has_new_sample(&mm->packet_in_bstats[idx]))
528+
{
529+
maybe_shrink_packet_in_bufs(mm, idx);
530+
}
479531
#else
480532
free(mem);
481533
#endif

src/liblsquic/lsquic_mm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct lsquic_mm {
4444
TAILQ_HEAD(, lsquic_packet_in) free_packets_in;
4545
SLIST_HEAD(, packet_out_buf) packet_out_bufs[MM_N_OUT_BUCKETS];
4646
struct pool_stats packet_out_bstats[MM_N_OUT_BUCKETS];
47+
struct pool_stats packet_in_bstats[MM_N_IN_BUCKETS];
4748
SLIST_HEAD(, packet_in_buf) packet_in_bufs[MM_N_IN_BUCKETS];
4849
SLIST_HEAD(, four_k_page) four_k_pages;
4950
SLIST_HEAD(, sixteen_k_page) sixteen_k_pages;

0 commit comments

Comments
 (0)