]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ncbmbuf: add tests as standalone mode
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 16 Oct 2025 14:41:42 +0000 (16:41 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 22 Oct 2025 13:04:24 +0000 (15:04 +0200)
Write some tests for ncbmbuf buf. These tests should be run each time
ncbmbuf implementation is adjusted. Use the following command :

$ gcc -g -DSTANDALONE -I./include -o ncbmbuf src/ncbmbuf.c && ./ncbmbuf

As the previous patch, this commit must be backported prior to the fix
to come on QUIC CRYPTO frames parsing.

src/ncbmbuf.c

index 252219b1bd6234ca2b357a84e5d2afe23c2ffa63..6f66e9cae076d3d63b917821210602490b8c4ab2 100644 (file)
@@ -2,6 +2,10 @@
 
 #include <string.h>
 
+#ifdef STANDALONE
+#include <stdio.h>
+#endif /* STANDALONE */
+
 #ifdef DEBUG_STRICT
 # include <haproxy/bug.h>
 #else
@@ -333,3 +337,272 @@ enum ncb_ret ncbmb_advance(struct ncbmbuf *buf, ncb_sz_t adv)
 
        return NCB_RET_OK;
 }
+
+#ifdef STANDALONE
+
+static void ncbmbuf_print_buf(struct ncbmbuf *b, int line)
+{
+       ncb_sz_t data;
+       int i;
+
+       fprintf(stderr, "[%03d] ", line);
+
+       for (i = 0; i < b->size; ++i) {
+               if (i && !(i % 8)) fprintf(stderr, " ");
+               else if (i && !(i % 4)) fprintf(stderr, ".");
+               fprintf(stderr, "%02x", (unsigned char)b->area[i]);
+       }
+
+       fprintf(stderr, " [");
+       for (i = 0; i < b->size_bm; ++i)
+               fprintf(stderr, "%02x", (unsigned char)b->bitmap[i]);
+       fprintf(stderr, "]\n");
+}
+
+#define NCBMB_DATA_EQ(buf, off, data) \
+  BUG_ON(ncbmb_data((buf), (off)) != (data))
+
+void test_ncbmb(void)
+{
+       char *area = calloc(16384, 1);
+       char *data = calloc(16384, 1);
+       struct ncbmbuf buf;
+
+       memset(data, 0x11, 16384);
+
+       /* 7 bytes data // 1 byte bitmap (0xfe) */
+       buf = ncbmb_make(area, 8, 0);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 0, 0);
+
+       ncbmb_add(&buf, 1, data, 3, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 1, 3);
+       ncbmb_advance(&buf, 2);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 0, 2);
+       ncbmb_advance(&buf, 7);
+       ncbmb_add(&buf, 0, data, 7, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 0, 7);
+
+       /* 7 bytes data // 1 byte bitmap (0xfe) */
+       buf = ncbmb_make(area, 8, 0);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 0, 0);
+       ncbmb_add(&buf, 0, data, 2, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 0, 2);
+       ncbmb_add(&buf, 4, data, 2, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__);
+       NCBMB_DATA_EQ(&buf, 0, 2); NCBMB_DATA_EQ(&buf, 4, 2);
+       ncbmb_add(&buf, 2, data, 2, NCB_ADD_OVERWRT);
+       ncbmb_add(&buf, 6, data, 1, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 0, 7);
+       fprintf(stderr, "\n");
+
+       /* 8 bytes data // 1 byte bitmap (no unused) */
+       buf = ncbmb_make(area, 9, 4); ncbmbuf_print_buf(&buf, __LINE__);
+
+       ncbmb_add(&buf, 1, data, 6, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 1, 6);
+       ncbmb_add(&buf, 7, data, 1, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 1, 7);
+       fprintf(stderr, "\n");
+
+       /* 8 bytes data // 2 bytes bitmap (0x00) */
+       buf = ncbmb_make(area, 10, 0);
+       ncbmbuf_print_buf(&buf, __LINE__);
+
+       ncbmb_add(&buf, 0, data, 5, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 0, 5);
+       ncbmb_add(&buf, 7, data, 1, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 7, 1);
+       ncbmb_add(&buf, 5, data, 3, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 0, 8);
+       fprintf(stderr, "\n");
+
+       /* 26 bytes data // 4 bytes bitmap (0xc0) */
+       buf = ncbmb_make(area, 30, 15); ncbmbuf_print_buf(&buf, __LINE__);
+
+       ncbmb_add(&buf, 0, data, 12, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 0, 12);
+       ncbmb_add(&buf, 19, data, 1, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 19, 1);
+       ncbmb_add(&buf, 20, data, 6, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__); NCBMB_DATA_EQ(&buf, 19, 7);
+       ncbmb_add(&buf, 12, data, 10, NCB_ADD_OVERWRT);
+       ncbmbuf_print_buf(&buf, __LINE__);
+       NCBMB_DATA_EQ(&buf, 0, 26); NCBMB_DATA_EQ(&buf, 1, 25);
+       ncbmb_advance(&buf, 15);
+       NCBMB_DATA_EQ(&buf, 0, 11); ncbmbuf_print_buf(&buf, __LINE__);
+       fprintf(stderr, "\n");
+
+       free(area); free(data);
+}
+
+#define ITBMAP_CHECK(it, m, b) \
+  BUG_ON((it).mask != (m) || (it).bits != (b))
+
+void test_itbmap(void)
+{
+       struct itbmap it;
+       char *area = calloc(16384, 1);
+       struct ncbmbuf buf;
+
+       /* 7 bytes data // 1 byte bitmap (0xfe) */
+       buf = ncbmb_make(area, 8, 0); ncbmbuf_print_buf(&buf, __LINE__);
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0xfe, 7);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       it = itbmap_get(&buf, 1); ITBMAP_CHECK(it, 0x7e, 6);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       /* 8 bytes data // 1 byte bitmap (no unused) */
+       buf = ncbmb_make(area, 9, 0); ncbmbuf_print_buf(&buf, __LINE__);
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+       it = itbmap_get(&buf, 6); ITBMAP_CHECK(it, 0x03, 2);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+       it = itbmap_get(&buf, 7); ITBMAP_CHECK(it, 0x01, 1);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       /* 10 bytes data // 2 bytes bitmap (0xc0) */
+       buf = ncbmb_make(area, 12, 0); ncbmbuf_print_buf(&buf, __LINE__);
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xc0, 2);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       buf.head = 3;
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0x1f, 5);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xc0, 2);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xe0, 3);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       buf.head = 4;
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0x0f, 4);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xc0, 2);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xf0, 4);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       buf.head = 7;
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0x01, 1);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xc0, 2);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xfe, 7);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       buf.head = 8;
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0xc0, 2);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       /* 8 bytes data // 2 bytes bitmap (0x00) */
+       buf = ncbmb_make(area, 10, 0); ncbmbuf_print_buf(&buf, __LINE__);
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       it = itbmap_get(&buf, 4); ITBMAP_CHECK(it, 0x0f, 4);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       it = itbmap_get(&buf, 6); ITBMAP_CHECK(it, 0x03, 2);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       buf.head = 7;
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0x01, 1);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xfe, 7);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       /* 26 bytes data // 4 bytes bitmap (0xc0) */
+       buf = ncbmb_make(area, 30, 0); ncbmbuf_print_buf(&buf, __LINE__);
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xc0, 2);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       it = itbmap_get(&buf, 15); ITBMAP_CHECK(it, 0x01, 1);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xc0, 2);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       buf.head = 15;
+       it = itbmap_get(&buf, 0); ITBMAP_CHECK(it, 0x01, 1);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xc0, 2);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xff, 8);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xfe, 7);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       it = itbmap_get(&buf, 15); ITBMAP_CHECK(it, 0x0f, 4);
+       it = itbmap_next(&buf, &it); ITBMAP_CHECK(it, 0xfe, 7);
+       it = itbmap_next(&buf, &it); BUG_ON(it.b);
+
+       free(area);
+}
+
+/* Real example of QUIC CRYPTO frames received from ngtcp2 client. */
+void test_ngtcp2_crypto(void)
+{
+       char *area = calloc(16384, 1);
+       char *data = calloc(16384, 1);
+       struct ncbmbuf buf;
+
+       memset(data, 0x11, 16384);
+
+       buf = ncbmb_make(area, 16384, 0);
+       ncbmb_add(&buf, 371, data, 14, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 371, 14);
+       ncbmb_add(&buf, 430, data, 59, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 430, 59);
+       ncbmb_add(&buf, 607, data, 472, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 607, 472);
+       ncbmb_add(&buf, 489, data, 118, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 489, 590);
+       ncbmb_add(&buf, 66, data, 67, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 66, 67);
+       ncbmb_add(&buf, 385, data, 15, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 385, 15);
+       ncbmb_add(&buf, 135, data, 118, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 135, 118);
+       ncbmb_add(&buf, 0, data, 66, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 0, 133);
+       ncbmb_add(&buf, 400, data, 15, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 400, 15);
+       ncbmb_add(&buf, 253, data, 118, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 253, 162);
+       ncbmb_add(&buf, 415, data, 15, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 400, 679);
+       ncbmb_add(&buf, 133, data, 1, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 0, 134);
+       ncbmb_add(&buf, 134, data, 1, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 0, 1079);
+
+       ncbmb_add(&buf, 1265, data, 187, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 1265, 187);
+       ncbmb_add(&buf, 1218, data, 47, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 1218, 234);
+       ncbmb_add(&buf, 1192, data, 3, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 1192, 3);
+       ncbmb_add(&buf, 1177, data, 3, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 1177, 3);
+       ncbmb_add(&buf, 1125, data, 47, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 1125, 47);
+       ncbmb_add(&buf, 1172, data, 5, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 1125, 55);
+       ncbmb_add(&buf, 1079, data, 46, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 0, 1180);
+       ncbmb_add(&buf, 1195, data, 23, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 1192, 260);
+       ncbmb_add(&buf, 1183, data, 6, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 1183, 6);
+       ncbmb_add(&buf, 1180, data, 3, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 0, 1189);
+       ncbmb_add(&buf, 1189, data, 3, NCB_ADD_OVERWRT);
+       NCBMB_DATA_EQ(&buf, 0, 1452);
+
+       free(area); free(data);
+}
+
+int main(int argc, char **argv)
+{
+       test_ncbmb();
+       test_itbmap();
+       test_ngtcp2_crypto();
+       return 0;
+}
+
+#endif /* STANDALONE */