Commit 436edc8f97 for openssl.org
commit 436edc8f97b807b8909dd006cbd72bf290b3553c
Author: Alexandr Nedvedicky <sashan@openssl.org>
Date: Mon Sep 21 17:15:33 2026 +0200
test: cover sc_data_trim_right() function
sc_data_trim_right() function shrinks heap buffer with
stream data by trimming the buffer from its end.
In order to reclaim unused memory the function uses realloc().
To reach code in the sc_data_trim_right() the test queues the fill
frames first so packet buffer overhead tresshold is reached,
The fill frames are intentionally placed beyond the gap so
they don't interfer with testing done later.
The test creates 3 dis-joint ranges. Each range is 64B long.
The offsets are: 0, 128, 256. Then partial read of 16 bytes happens.
After that the test inserts yet another stream frame that carries
160 bytes of data and lands to offset 63. The frame joins the
first two ranges. The join operation calls to sc_data_trim_right().
Finally to verify things do work as expected The test reads
all available data from stream and verifies those data match
the expected content.
The test is based on code submitted by Mounir IDRASSI
Co-authored-by: Mounir IDRASSI <mounir.idrassi@amcrypto.jp>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
Merge-date: Sat Sep 26 11:35:38 2026
Merged-from: https://github.com/openssl/openssl/pull/32038
diff --git a/test/quic_stream_test.c b/test/quic_stream_test.c
index da156f2b72..6844c74e75 100644
--- a/test/quic_stream_test.c
+++ b/test/quic_stream_test.c
@@ -2673,6 +2673,197 @@ err:
return ok;
}
+#define FILLERS 56
+
+static int test_trim_right(void)
+{
+ unsigned char data[4096];
+ unsigned char read_buf[4096];
+ size_t readbytes;
+ TEST_STREAM_CHUNK_T tsc_buf[4];
+ OSSL_QRX_PKT *pkt[FILLERS + OSSL_NELEM(tsc_buf)] = { 0 };
+ unsigned char fill = 0xFF;
+ QUIC_RSTREAM_QPARM *rsqp = NULL;
+ TEST_STREAM_CHUNK_T *tsc;
+ QUIC_RSTREAM *rstream = NULL;
+ QUIC_CHANNEL *ch = NULL;
+ int fin;
+ unsigned int i, pktnum;
+ int ok = 0;
+
+ if (!TEST_ptr(ch = OPENSSL_zalloc(sizeof(QUIC_CHANNEL))))
+ return 0;
+
+ if (!TEST_ptr(rsqp = ossl_quic_rstream_qparm_new(ch)))
+ goto err;
+
+ rstream = ossl_quic_rstream_new(NULL, NULL, rsqp);
+ if (!TEST_ptr(rstream))
+ goto err;
+
+ for (i = 0; i < sizeof(data); i++)
+ data[i] = FILL_PATTERN[i % (sizeof(FILL_PATTERN) - 1)];
+
+ memset(tsc_buf, 0, sizeof(tsc_buf));
+ memset(read_buf, 0, sizeof(read_buf));
+
+ pktnum = 0;
+ for (i = 0; i < FILLERS; i++) {
+ pkt[pktnum] = pkt_test_new(1200);
+ if (!TEST_ptr(pkt[pktnum]))
+ goto err;
+
+ if (!TEST_true(ossl_quic_rstream_queue_data(rstream, pkt[pktnum],
+ 1024 + 2 * i, &fill, 1, 0)))
+ goto err;
+
+ pktnum++;
+ }
+
+ /*
+ * send three chunks. each 64 bytes long,
+ * chunks create three ranges.
+ */
+ tsc = &tsc_buf[0];
+ tsc->tsc_data = &data[0];
+ tsc->tsc_off = 0;
+ tsc->tsc_len = 64;
+ tsc->tsc_fin = 0;
+ tsc->tsc_ranges_exp = FILLERS + 1;
+ tsc->tsc_chunks_exp = FILLERS + 1;
+
+ tsc = &tsc_buf[1];
+ tsc->tsc_data = &data[128];
+ tsc->tsc_off = 128;
+ tsc->tsc_len = 64;
+ tsc->tsc_fin = 0;
+ tsc->tsc_ranges_exp = FILLERS + 2;
+ tsc->tsc_chunks_exp = FILLERS + 2;
+
+ tsc = &tsc_buf[2];
+ tsc->tsc_data = &data[256];
+ tsc->tsc_off = 256;
+ tsc->tsc_len = 64;
+ tsc->tsc_fin = 0;
+ tsc->tsc_ranges_exp = FILLERS + 3;
+ tsc->tsc_chunks_exp = FILLERS + 3;
+
+ for (i = 0; i < OSSL_NELEM(tsc_buf) - 1; i++) {
+ pkt[pktnum] = pkt_test_new(1200);
+ if (!TEST_ptr(pkt[pktnum]))
+ goto err;
+ tsc = &tsc_buf[i];
+ if (!TEST_true(ossl_quic_rstream_queue_data(rstream, pkt[pktnum],
+ tsc->tsc_off, tsc->tsc_data, tsc->tsc_len, tsc->tsc_fin)))
+ goto err;
+
+ /*
+ * check our assumptions about about reassemble process internals.
+ */
+ if (!TEST_size_t_eq(ossl_quic_rstream_get_range_count(rstream),
+ tsc->tsc_ranges_exp)) {
+ TEST_info("%s failing iteration %u", OPENSSL_FUNC, i);
+ goto err;
+ }
+
+ if (!TEST_size_t_eq(ossl_quic_rstream_get_chunk_count(rstream),
+ tsc->tsc_chunks_exp)) {
+ TEST_info("%s failing iteration %u", OPENSSL_FUNC, i);
+ goto err;
+ }
+
+ /*
+ * the packet reference should stay at 1, because _rstream_queue_data()
+ * copies data to stream buffer instead of grabbing a reference to
+ * packet (advancing the packet's ref counter)
+ */
+ if (!TEST_size_t_eq(pkt_test_refcount(pkt[pktnum]), 1))
+ goto err;
+ pktnum++;
+ }
+
+ /*
+ * do a partial read of 16 bytes.
+ */
+ if (!TEST_true(ossl_quic_rstream_read(rstream, read_buf,
+ 16, &readbytes, &fin)))
+ goto err;
+
+ if (!TEST_uint64_t_eq(readbytes, 16))
+ goto err;
+
+ if (!TEST_false(fin))
+ goto err;
+
+ if (!TEST_mem_eq(read_buf, readbytes, data, readbytes))
+ goto err;
+
+ /*
+ * send chunk that glues three ranges together.
+ */
+ tsc = &tsc_buf[3];
+ tsc->tsc_data = &data[63];
+ tsc->tsc_off = 63;
+ tsc->tsc_len = 160;
+ tsc->tsc_fin = 0;
+ tsc->tsc_ranges_exp = FILLERS + 2;
+ tsc->tsc_chunks_exp = FILLERS + 3;
+
+ pkt[pktnum] = pkt_test_new(1200);
+ if (!TEST_ptr(pkt[pktnum]))
+ goto err;
+ if (!TEST_true(ossl_quic_rstream_queue_data(rstream, pkt[pktnum],
+ tsc->tsc_off, tsc->tsc_data, tsc->tsc_len, tsc->tsc_fin)))
+ goto err;
+
+ /*
+ * check our assumptions about about reassemble process internals.
+ */
+ if (!TEST_size_t_eq(ossl_quic_rstream_get_range_count(rstream),
+ tsc->tsc_ranges_exp)) {
+ TEST_info("%s failing iteration %u", OPENSSL_FUNC, i);
+ goto err;
+ }
+
+ if (!TEST_size_t_eq(ossl_quic_rstream_get_chunk_count(rstream),
+ tsc->tsc_chunks_exp)) {
+ TEST_info("%s failing iteration %u", OPENSSL_FUNC, i);
+ goto err;
+ }
+
+ if (!TEST_size_t_eq(pkt_test_refcount(pkt[pktnum]), 1))
+ goto err;
+ pktnum++;
+
+ if (!TEST_true(ossl_quic_rstream_read(rstream, read_buf,
+ 4096, &readbytes, &fin)))
+ goto err;
+
+ /*
+ * the ranges are still dis-joint, only 207 bytes can be read
+ */
+ if (!TEST_uint64_t_eq(readbytes, 207))
+ goto err;
+
+ if (!TEST_false(fin))
+ goto err;
+
+ if (!TEST_mem_eq(read_buf, readbytes, &data[16], readbytes))
+ goto err;
+
+ ok = 1;
+err:
+ ossl_quic_rstream_free(rstream);
+
+ for (i = 0; i < OSSL_NELEM(pkt); i++)
+ pkt_test_free(pkt[i]);
+
+ ossl_quic_rstream_qparm_destroy(rsqp);
+ ossl_quic_channel_free(ch);
+
+ return ok;
+}
+
int setup_tests(void)
{
ADD_TEST(test_sstream_simple);
@@ -2694,6 +2885,7 @@ int setup_tests(void)
ADD_TEST(test_rstream_mix_chunks);
ADD_TEST(test_final_size_violation_fin_first);
ADD_TEST(test_final_size_violation_data_first);
+ ADD_TEST(test_trim_right);
return 1;
}