diff options
Diffstat (limited to 'src/util/support/t_k5buf.c')
| -rw-r--r-- | src/util/support/t_k5buf.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/src/util/support/t_k5buf.c b/src/util/support/t_k5buf.c new file mode 100644 index 000000000000..ba86851dc47b --- /dev/null +++ b/src/util/support/t_k5buf.c @@ -0,0 +1,260 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* util/support/t_k5buf.c - Test the k5buf string buffer module */ +/* + * Copyright 2008 Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#include "k5-platform.h" +#include "k5-buf.h" +#include <stdio.h> +#include <stdlib.h> + +static void +fail_if(int condition, const char *name) +{ + if (condition) { + fprintf(stderr, "%s failed\n", name); + exit(1); + } +} + +/* Test the invariants of a buffer. */ +static void +check_buf(struct k5buf *buf, const char *name) +{ + fail_if(buf->buftype != K5BUF_FIXED && buf->buftype != K5BUF_DYNAMIC && + buf->buftype != K5BUF_ERROR, name); + if (buf->buftype == K5BUF_ERROR) { + fail_if(buf->data != NULL, name); + fail_if(buf->space != 0 || buf->len != 0, name); + } else { + fail_if(buf->space == 0, name); + fail_if(buf->len >= buf->space, name); + fail_if(((char *)buf->data)[buf->len] != 0, name); + } +} + +static void +test_basic() +{ + struct k5buf buf; + char storage[1024]; + + k5_buf_init_fixed(&buf, storage, sizeof(storage)); + k5_buf_add(&buf, "Hello "); + k5_buf_add_len(&buf, "world", 5); + check_buf(&buf, "basic fixed"); + fail_if(buf.data == NULL || buf.len != 11, "basic fixed"); + fail_if(strcmp(buf.data, "Hello world") != 0, "basic fixed"); + + k5_buf_init_dynamic(&buf); + k5_buf_add_len(&buf, "Hello", 5); + k5_buf_add(&buf, " world"); + check_buf(&buf, "basic dynamic"); + fail_if(buf.data == NULL || buf.len != 11, "basic dynamic"); + fail_if(strcmp(buf.data, "Hello world") != 0, "basic dynamic"); + k5_buf_free(&buf); +} + +static void +test_realloc() +{ + struct k5buf buf; + char data[1024]; + size_t i; + + for (i = 0; i < sizeof(data); i++) + data[i] = 'a'; + + /* Cause the buffer size to double from 128 to 256 bytes. */ + k5_buf_init_dynamic(&buf); + k5_buf_add_len(&buf, data, 10); + k5_buf_add_len(&buf, data, 128); + fail_if(buf.space != 256, "realloc 1"); + check_buf(&buf, "realloc 1"); + fail_if(buf.data == NULL || buf.len != 138, "realloc 1"); + fail_if(memcmp(buf.data, data, buf.len) != 0, "realloc 1"); + + /* Cause the same buffer to double in size to 512 bytes. */ + k5_buf_add_len(&buf, data, 128); + fail_if(buf.space != 512, "realloc 2"); + check_buf(&buf, "realloc 2"); + fail_if(buf.data == NULL || buf.len != 266, "realloc 2"); + fail_if(memcmp(buf.data, data, buf.len) != 0, "realloc 2"); + k5_buf_free(&buf); + + /* Cause a buffer to increase from 128 to 512 bytes directly. */ + k5_buf_init_dynamic(&buf); + k5_buf_add_len(&buf, data, 10); + k5_buf_add_len(&buf, data, 256); + fail_if(buf.space != 512, "realloc 3"); + check_buf(&buf, "realloc 3"); + fail_if(buf.data == NULL || buf.len != 266, "realloc 3"); + fail_if(memcmp(buf.data, data, buf.len) != 0, "realloc 3"); + k5_buf_free(&buf); + + /* Cause a buffer to increase from 128 to 1024 bytes directly. */ + k5_buf_init_dynamic(&buf); + k5_buf_add_len(&buf, data, 10); + k5_buf_add_len(&buf, data, 512); + fail_if(buf.space != 1024, "realloc 4"); + check_buf(&buf, "realloc 4"); + fail_if(buf.data == NULL || buf.len != 522, "realloc 4"); + fail_if(memcmp(buf.data, data, buf.len) != 0, "realloc 4"); + k5_buf_free(&buf); + + /* Cause a reallocation to fail by integer overflow. */ + k5_buf_init_dynamic(&buf); + k5_buf_add_len(&buf, data, 100); + k5_buf_add_len(&buf, NULL, SIZE_MAX); + check_buf(&buf, "realloc 5"); + fail_if(buf.buftype != K5BUF_ERROR, "realloc 5"); + k5_buf_free(&buf); +} + +static void +test_overflow() +{ + struct k5buf buf; + char storage[10]; + + /* Cause a fixed-sized buffer overflow. */ + k5_buf_init_fixed(&buf, storage, sizeof(storage)); + k5_buf_add(&buf, "12345"); + k5_buf_add(&buf, "12345"); + check_buf(&buf, "overflow 1"); + fail_if(buf.buftype != K5BUF_ERROR, "overflow 1"); + + /* Cause a fixed-sized buffer overflow with integer overflow. */ + k5_buf_init_fixed(&buf, storage, sizeof(storage)); + k5_buf_add(&buf, "12345"); + k5_buf_add_len(&buf, NULL, SIZE_MAX); + check_buf(&buf, "overflow 2"); + fail_if(buf.buftype != K5BUF_ERROR, "overflow 2"); +} + +static void +test_error() +{ + struct k5buf buf; + char storage[1]; + + /* Cause an overflow and then perform actions afterwards. */ + k5_buf_init_fixed(&buf, storage, sizeof(storage)); + k5_buf_add(&buf, "1"); + fail_if(buf.buftype != K5BUF_ERROR, "error"); + check_buf(&buf, "error"); + k5_buf_add(&buf, "test"); + check_buf(&buf, "error"); + k5_buf_add_len(&buf, "test", 4); + check_buf(&buf, "error"); + k5_buf_truncate(&buf, 3); + check_buf(&buf, "error"); + fail_if(buf.buftype != K5BUF_ERROR, "error"); +} + +static void +test_truncate() +{ + struct k5buf buf; + + k5_buf_init_dynamic(&buf); + k5_buf_add(&buf, "abcde"); + k5_buf_add(&buf, "fghij"); + k5_buf_truncate(&buf, 7); + check_buf(&buf, "truncate"); + fail_if(buf.data == NULL || buf.len != 7, "truncate"); + fail_if(strcmp(buf.data, "abcdefg") != 0, "truncate"); + k5_buf_free(&buf); +} + +static void +test_binary() +{ + struct k5buf buf; + char data[] = { 'a', 0, 'b' }, *s; + + k5_buf_init_dynamic(&buf); + k5_buf_add_len(&buf, data, 3); + k5_buf_add_len(&buf, data, 3); + check_buf(&buf, "binary"); + fail_if(buf.data == NULL || buf.len != 6, "binary"); + s = buf.data; + fail_if(s[0] != 'a' || s[1] != 0 || s[2] != 'b', "binary"); + fail_if(s[3] != 'a' || s[4] != 0 || s[5] != 'b', "binary"); + k5_buf_free(&buf); +} + +static void +test_fmt() +{ + struct k5buf buf; + char storage[10], data[1024]; + size_t i; + + for (i = 0; i < sizeof(data) - 1; i++) + data[i] = 'a'; + data[i] = '\0'; + + /* Format some text into a non-empty fixed buffer. */ + k5_buf_init_fixed(&buf, storage, sizeof(storage)); + k5_buf_add(&buf, "foo"); + k5_buf_add_fmt(&buf, " %d ", 3); + check_buf(&buf, "fmt 1"); + fail_if(buf.data == NULL || buf.len != 6, "fmt 1"); + fail_if(strcmp(buf.data, "foo 3 ") != 0, "fmt 1"); + + /* Overflow the same buffer with formatted text. */ + k5_buf_add_fmt(&buf, "%d%d%d%d", 1, 2, 3, 4); + check_buf(&buf, "fmt 2"); + fail_if(buf.buftype != K5BUF_ERROR, "fmt 2"); + + /* Format some text into a non-empty dynamic buffer. */ + k5_buf_init_dynamic(&buf); + k5_buf_add(&buf, "foo"); + k5_buf_add_fmt(&buf, " %d ", 3); + check_buf(&buf, "fmt 3"); + fail_if(buf.data == NULL || buf.len != 6, "fmt 3"); + fail_if(strcmp(buf.data, "foo 3 ") != 0, "fmt 3"); + + /* Format more text into the same buffer, causing a big resize. */ + k5_buf_add_fmt(&buf, "%s", data); + check_buf(&buf, "fmt 4"); + fail_if(buf.space != 2048, "fmt 4"); + fail_if(buf.data == NULL || buf.len != 1029, "fmt 4"); + fail_if(strcmp((char *)buf.data + 6, data) != 0, "fmt 4"); + k5_buf_free(&buf); +} + +int +main() +{ + test_basic(); + test_realloc(); + test_overflow(); + test_error(); + test_truncate(); + test_binary(); + test_fmt(); + return 0; +} |
