Commit 4ffef64919 for openssl.org
commit 4ffef6491996fc4aab919ea8a6bc05f7aaa15b33
Author: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Date: Wed Aug 26 16:36:28 2026 +0200
test: cover a long lagging read of packet backed stream data
Queue many small contiguous frames that each pin their own packet while
the reader stays behind, so a large number of packets are held at once and
then released as the data is finally consumed. This exercises the packet
reference lifecycle at a scale the other tests do not reach, and gives a
reassembly that copies data out of packets under memory pressure something
to run against.
Assisted-by: Claude:claude-opus-4-8
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
MergeDate: Fri Aug 28 14:03:47 2026
(Merged from https://github.com/openssl/openssl/pull/32515)
diff --git a/test/quic_stream_test.c b/test/quic_stream_test.c
index 2493d3ff13..2e6cadda35 100644
--- a/test/quic_stream_test.c
+++ b/test/quic_stream_test.c
@@ -783,6 +783,81 @@ err:
return ret;
}
+/*
+ * Many small contiguous frames, each pinning its own packet while the reader
+ * lags behind, so a large number of packets are held at once and released only
+ * as the data is finally consumed. Every byte must still read back in order and
+ * every packet reference must end up released.
+ */
+static int test_rstream_pkt_overhead(void)
+{
+ QUIC_RSTREAM *rstream = NULL;
+ OSSL_QRX_PKT **pkt = NULL;
+ unsigned char *data = NULL, *buf = NULL;
+ const size_t framesz = 8;
+ const size_t nframes = 4096; /* far past a 64 KiB overhead limit */
+ const size_t total = framesz * nframes;
+ const size_t read_lag = 200; /* read only after this many arrive */
+ size_t i, got = 0, readbytes = 0;
+ int fin = 0, ret = 0;
+
+ if (!TEST_ptr(data = OPENSSL_malloc(total))
+ || !TEST_ptr(buf = OPENSSL_malloc(total))
+ || !TEST_ptr(pkt = OPENSSL_zalloc(nframes * sizeof(*pkt)))
+ || !TEST_ptr(rstream = ossl_quic_rstream_new(NULL, NULL, 0)))
+ goto err;
+
+ for (i = 0; i < total; ++i)
+ data[i] = (unsigned char)(i & 0xff);
+
+ for (i = 0; i < nframes; ++i) {
+ if (!TEST_ptr(pkt[i] = pkt_test_new(1200)))
+ goto err;
+
+ if (!TEST_true(ossl_quic_rstream_queue_data(rstream, pkt[i],
+ i * framesz, data + i * framesz, framesz,
+ i == nframes - 1)))
+ goto err;
+
+ /* let the reader fall behind, then drain what has become available */
+ if (i % read_lag == read_lag - 1)
+ while (got < total
+ && TEST_true(ossl_quic_rstream_read(rstream, buf + got,
+ total - got, &readbytes, &fin))
+ && readbytes > 0)
+ got += readbytes;
+ }
+
+ /* drain whatever is left and check every byte survived in order */
+ while (got < total
+ && TEST_true(ossl_quic_rstream_read(rstream, buf + got, total - got,
+ &readbytes, &fin))
+ && readbytes > 0)
+ got += readbytes;
+
+ if (!TEST_size_t_eq(got, total)
+ || !TEST_true(fin)
+ || !TEST_mem_eq(buf, got, data, total))
+ goto err;
+
+ /* every consumed frame has released the reference it held on its packet */
+ for (i = 0; i < nframes; ++i)
+ if (!TEST_size_t_eq(pkt_test_refcount(pkt[i]), 1))
+ goto err;
+
+ ret = 1;
+
+err:
+ ossl_quic_rstream_free(rstream);
+ if (pkt != NULL)
+ for (i = 0; i < nframes; ++i)
+ pkt_test_free(pkt[i]);
+ OPENSSL_free(pkt);
+ OPENSSL_free(data);
+ OPENSSL_free(buf);
+ return ret;
+}
+
int setup_tests(void)
{
ADD_TEST(test_sstream_simple);
@@ -790,5 +865,6 @@ int setup_tests(void)
ADD_ALL_TESTS(test_rstream_simple, 4);
ADD_ALL_TESTS(test_rstream_random, 100);
ADD_TEST(test_rstream_pkt);
+ ADD_TEST(test_rstream_pkt_overhead);
return 1;
}