diff options
author | Florian Weimer <fweimer@redhat.com> | 2017-06-21 22:43:57 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2017-06-21 22:43:57 +0200 |
commit | 4dd8e7c0ce5ecc7f65e33e60ad2f717b31de32ec (patch) | |
tree | bfc9688f34dfc949e8da77d0ec05b684ff64e86f /malloc/tst-alloc_buffer.c | |
parent | 11ffcacb64a939c10cfc713746b8ec88837f5c4a (diff) | |
download | glibc-4dd8e7c0ce5ecc7f65e33e60ad2f717b31de32ec.tar.gz glibc-4dd8e7c0ce5ecc7f65e33e60ad2f717b31de32ec.tar.xz glibc-4dd8e7c0ce5ecc7f65e33e60ad2f717b31de32ec.zip |
Implement allocation buffers for internal use
This commit adds fixed-size allocation buffers. The primary use case is in NSS modules, where dynamically sized data is stored in a fixed-size buffer provided by the caller. Other uses include a replacement of mempcpy cascades (which is safer due to the size checking inherent to allocation buffers).
Diffstat (limited to 'malloc/tst-alloc_buffer.c')
-rw-r--r-- | malloc/tst-alloc_buffer.c | 665 |
1 files changed, 665 insertions, 0 deletions
diff --git a/malloc/tst-alloc_buffer.c b/malloc/tst-alloc_buffer.c new file mode 100644 index 0000000000..1c143999c7 --- /dev/null +++ b/malloc/tst-alloc_buffer.c @@ -0,0 +1,665 @@ +/* Tests for struct alloc_buffer. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <arpa/inet.h> +#include <alloc_buffer.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <support/check.h> +#include <support/support.h> +#include <support/test-driver.h> + +/* Return true if PTR is sufficiently aligned for TYPE. */ +#define IS_ALIGNED(ptr, type) \ + ((((uintptr_t) ptr) & (__alloc_buffer_assert_align (__alignof (type)) - 1)) \ + == 0) + +/* Structure with non-power-of-two size. */ +struct twelve +{ + uint32_t buffer[3] __attribute__ ((aligned (4))); +}; +_Static_assert (sizeof (struct twelve) == 12, "struct twelve"); +_Static_assert (__alignof__ (struct twelve) == 4, "struct twelve"); + +/* Check for success obtaining empty arrays. Does not assume the + buffer is empty. */ +static void +test_empty_array (struct alloc_buffer refbuf) +{ + bool refbuf_failed = alloc_buffer_has_failed (&refbuf); + if (test_verbose) + printf ("info: %s: current=0x%llx end=0x%llx refbuf_failed=%d\n", + __func__, (unsigned long long) refbuf.__alloc_buffer_current, + (unsigned long long) refbuf.__alloc_buffer_end, refbuf_failed); + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY ((alloc_buffer_alloc_bytes (&buf, 0) == NULL) + == refbuf_failed); + TEST_VERIFY (alloc_buffer_has_failed (&buf) == refbuf_failed); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY ((alloc_buffer_alloc_array (&buf, char, 0) == NULL) + == refbuf_failed); + TEST_VERIFY (alloc_buffer_has_failed (&buf) == refbuf_failed); + } + /* The following tests can fail due to the need for aligning the + returned pointer. */ + { + struct alloc_buffer buf = refbuf; + bool expect_failure = refbuf_failed + || !IS_ALIGNED (alloc_buffer_next (&buf, void), double); + double *ptr = alloc_buffer_alloc_array (&buf, double, 0); + TEST_VERIFY (IS_ALIGNED (ptr, double)); + TEST_VERIFY ((ptr == NULL) == expect_failure); + TEST_VERIFY (alloc_buffer_has_failed (&buf) == expect_failure); + } + { + struct alloc_buffer buf = refbuf; + bool expect_failure = refbuf_failed + || !IS_ALIGNED (alloc_buffer_next (&buf, void), struct twelve); + struct twelve *ptr = alloc_buffer_alloc_array (&buf, struct twelve, 0); + TEST_VERIFY (IS_ALIGNED (ptr, struct twelve)); + TEST_VERIFY ((ptr == NULL) == expect_failure); + TEST_VERIFY (alloc_buffer_has_failed (&buf) == expect_failure); + } +} + +/* Test allocation of impossibly large arrays. */ +static void +test_impossible_array (struct alloc_buffer refbuf) +{ + if (test_verbose) + printf ("info: %s: current=0x%llx end=0x%llx\n", + __func__, (unsigned long long) refbuf.__alloc_buffer_current, + (unsigned long long) refbuf.__alloc_buffer_end); + static const size_t counts[] = + { SIZE_MAX, SIZE_MAX - 1, SIZE_MAX - 2, SIZE_MAX - 3, SIZE_MAX - 4, + SIZE_MAX / 2, SIZE_MAX / 2 + 1, SIZE_MAX / 2 - 1, 0}; + + for (int i = 0; counts[i] != 0; ++i) + { + size_t count = counts[i]; + if (test_verbose) + printf ("info: %s: count=%zu\n", __func__, count); + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_bytes (&buf, count) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, char, count) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, short, count) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, double, count) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct twelve, count) + == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + } +} + +/* Check for failure to obtain anything from a failed buffer. */ +static void +test_after_failure (struct alloc_buffer refbuf) +{ + if (test_verbose) + printf ("info: %s: current=0x%llx end=0x%llx\n", + __func__, (unsigned long long) refbuf.__alloc_buffer_current, + (unsigned long long) refbuf.__alloc_buffer_end); + TEST_VERIFY (alloc_buffer_has_failed (&refbuf)); + { + struct alloc_buffer buf = refbuf; + alloc_buffer_add_byte (&buf, 17); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, char) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, double) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, struct twelve) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + + test_impossible_array (refbuf); + for (int count = 0; count <= 4; ++count) + { + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_bytes (&buf, count) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, char, count) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, double, count) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct twelve, count) + == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + } +} + +static void +test_empty (struct alloc_buffer refbuf) +{ + TEST_VERIFY (alloc_buffer_size (&refbuf) == 0); + if (alloc_buffer_next (&refbuf, void) != NULL) + TEST_VERIFY (!alloc_buffer_has_failed (&refbuf)); + test_empty_array (refbuf); + test_impossible_array (refbuf); + + /* Failure to obtain non-empty objects. */ + { + struct alloc_buffer buf = refbuf; + alloc_buffer_add_byte (&buf, 17); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, char) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, double) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, struct twelve) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, char, 1) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, double, 1) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct twelve, 1) == NULL); + test_after_failure (buf); + } +} + +static void +test_size_1 (struct alloc_buffer refbuf) +{ + TEST_VERIFY (!alloc_buffer_has_failed (&refbuf)); + TEST_VERIFY (alloc_buffer_size (&refbuf) == 1); + test_empty_array (refbuf); + test_impossible_array (refbuf); + + /* Success adding a single byte. */ + { + struct alloc_buffer buf = refbuf; + alloc_buffer_add_byte (&buf, 17); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + test_empty (buf); + } + TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\x11", 1) == 0); + { + struct alloc_buffer buf = refbuf; + signed char *ptr = alloc_buffer_alloc (&buf, signed char); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + *ptr = 126; + test_empty (buf); + } + TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\176", 1) == 0); + { + struct alloc_buffer buf = refbuf; + char *ptr = alloc_buffer_alloc_array (&buf, char, 1); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + *ptr = (char) 253; + test_empty (buf); + } + TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\xfd", 1) == 0); + + /* Failure with larger objects. */ + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, short) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, double) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, struct twelve) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, short, 1) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, double, 1) == NULL); + test_after_failure (buf); + } + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct twelve, 1) == NULL); + test_after_failure (buf); + } +} + +static void +test_size_2 (struct alloc_buffer refbuf) +{ + TEST_VERIFY (!alloc_buffer_has_failed (&refbuf)); + TEST_VERIFY (alloc_buffer_size (&refbuf) == 2); + TEST_VERIFY (IS_ALIGNED (alloc_buffer_next (&refbuf, void), short)); + test_empty_array (refbuf); + test_impossible_array (refbuf); + + /* Success adding two bytes. */ + { + struct alloc_buffer buf = refbuf; + alloc_buffer_add_byte (&buf, '@'); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + test_size_1 (buf); + } + TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "@\xfd", 2) == 0); + { + struct alloc_buffer buf = refbuf; + signed char *ptr = alloc_buffer_alloc (&buf, signed char); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + *ptr = 'A'; + test_size_1 (buf); + } + TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "A\xfd", 2) == 0); + { + struct alloc_buffer buf = refbuf; + char *ptr = alloc_buffer_alloc_array (&buf, char, 1); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + *ptr = 'B'; + test_size_1 (buf); + } + TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "B\xfd", 2) == 0); + { + struct alloc_buffer buf = refbuf; + unsigned short *ptr = alloc_buffer_alloc (&buf, unsigned short); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (IS_ALIGNED (ptr, unsigned short)); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + *ptr = htons (0x12f4); + test_empty (buf); + } + TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\x12\xf4", 2) == 0); + { + struct alloc_buffer buf = refbuf; + unsigned short *ptr = alloc_buffer_alloc_array (&buf, unsigned short, 1); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (IS_ALIGNED (ptr, unsigned short)); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + *ptr = htons (0x13f5); + test_empty (buf); + } + TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "\x13\xf5", 2) == 0); + { + struct alloc_buffer buf = refbuf; + char *ptr = alloc_buffer_alloc_array (&buf, char, 2); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + memcpy (ptr, "12", 2); + test_empty (buf); + } + TEST_VERIFY (memcmp (alloc_buffer_next (&refbuf, void), "12", 2) == 0); +} + +static void +test_misaligned (char pad) +{ + enum { SIZE = 23 }; + char *backing = xmalloc (SIZE + 2); + backing[0] = ~pad; + backing[SIZE + 1] = pad; + struct alloc_buffer refbuf = alloc_buffer_create (backing + 1, SIZE); + + { + struct alloc_buffer buf = refbuf; + short *ptr = alloc_buffer_alloc_array (&buf, short, SIZE / sizeof (short)); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (IS_ALIGNED (ptr, short)); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + for (int i = 0; i < SIZE / sizeof (short); ++i) + ptr[i] = htons (0xff01 + i); + TEST_VERIFY (memcmp (ptr, + "\xff\x01\xff\x02\xff\x03\xff\x04" + "\xff\x05\xff\x06\xff\x07\xff\x08" + "\xff\x09\xff\x0a\xff\x0b", 22) == 0); + } + { + struct alloc_buffer buf = refbuf; + uint32_t *ptr = alloc_buffer_alloc_array + (&buf, uint32_t, SIZE / sizeof (uint32_t)); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (IS_ALIGNED (ptr, uint32_t)); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + for (int i = 0; i < SIZE / sizeof (uint32_t); ++i) + ptr[i] = htonl (0xf1e2d301 + i); + TEST_VERIFY (memcmp (ptr, + "\xf1\xe2\xd3\x01\xf1\xe2\xd3\x02" + "\xf1\xe2\xd3\x03\xf1\xe2\xd3\x04" + "\xf1\xe2\xd3\x05", 20) == 0); + } + { + struct alloc_buffer buf = refbuf; + struct twelve *ptr = alloc_buffer_alloc (&buf, struct twelve); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (IS_ALIGNED (ptr, struct twelve)); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + ptr->buffer[0] = htonl (0x11223344); + ptr->buffer[1] = htonl (0x55667788); + ptr->buffer[2] = htonl (0x99aabbcc); + TEST_VERIFY (memcmp (ptr, + "\x11\x22\x33\x44" + "\x55\x66\x77\x88" + "\x99\xaa\xbb\xcc", 12) == 0); + } + { + static const double nums[] = { 1, 2 }; + struct alloc_buffer buf = refbuf; + double *ptr = alloc_buffer_alloc_array (&buf, double, 2); + TEST_VERIFY_EXIT (ptr != NULL); + TEST_VERIFY (IS_ALIGNED (ptr, double)); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + ptr[0] = nums[0]; + ptr[1] = nums[1]; + TEST_VERIFY (memcmp (ptr, nums, sizeof (nums)) == 0); + } + + /* Verify that padding was not overwritten. */ + TEST_VERIFY (backing[0] == ~pad); + TEST_VERIFY (backing[SIZE + 1] == pad); + free (backing); +} + +/* Check that overflow during alignment is handled properly. */ +static void +test_large_misaligned (void) +{ + uintptr_t minus1 = -1; + uintptr_t start = minus1 & ~0xfe; + struct alloc_buffer refbuf = alloc_buffer_create ((void *) start, 16); + TEST_VERIFY (!alloc_buffer_has_failed (&refbuf)); + + struct __attribute__ ((aligned (256))) align256 + { + int dymmy; + }; + + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc (&buf, struct align256) == NULL); + test_after_failure (buf); + } + for (int count = 0; count < 3; ++count) + { + struct alloc_buffer buf = refbuf; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, struct align256, count) + == NULL); + test_after_failure (buf); + } +} + +/* Check behavior of large allocations. */ +static void +test_large (void) +{ + { + /* Allocation which wraps around. */ + struct alloc_buffer buf = { 1, SIZE_MAX }; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, char, SIZE_MAX) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + + { + /* Successful very large allocation. */ + struct alloc_buffer buf = { 1, SIZE_MAX }; + uintptr_t val = (uintptr_t) alloc_buffer_alloc_array + (&buf, char, SIZE_MAX - 1); + TEST_VERIFY (val == 1); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + test_empty (buf); + } + + { + typedef char __attribute__ ((aligned (2))) char2; + + /* Overflow in array size computation. */ + struct alloc_buffer buf = { 1, SIZE_MAX }; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, char2, SIZE_MAX - 1) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + + /* Successful allocation after alignment. */ + buf = (struct alloc_buffer) { 1, SIZE_MAX }; + uintptr_t val = (uintptr_t) alloc_buffer_alloc_array + (&buf, char2, SIZE_MAX - 2); + TEST_VERIFY (val == 2); + test_empty (buf); + + /* Alignment behavior near the top of the address space. */ + buf = (struct alloc_buffer) { SIZE_MAX, SIZE_MAX }; + TEST_VERIFY (alloc_buffer_next (&buf, char2) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + buf = (struct alloc_buffer) { SIZE_MAX, SIZE_MAX }; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, char2, 0) == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + } + + { + typedef short __attribute__ ((aligned (2))) short2; + + /* Test overflow in size computation. */ + struct alloc_buffer buf = { 1, SIZE_MAX }; + TEST_VERIFY (alloc_buffer_alloc_array (&buf, short2, SIZE_MAX / 2) + == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + + /* A slightly smaller array fits within the allocation. */ + buf = (struct alloc_buffer) { 2, SIZE_MAX - 1 }; + uintptr_t val = (uintptr_t) alloc_buffer_alloc_array + (&buf, short2, SIZE_MAX / 2 - 1); + TEST_VERIFY (val == 2); + test_empty (buf); + } +} + +static void +test_copy_bytes (void) +{ + char backing[4]; + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + alloc_buffer_copy_bytes (&buf, "1", 1); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + TEST_VERIFY (alloc_buffer_size (&buf) == 3); + TEST_VERIFY (memcmp (backing, "1@@@", 4) == 0); + } + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + alloc_buffer_copy_bytes (&buf, "12", 3); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + TEST_VERIFY (alloc_buffer_size (&buf) == 1); + TEST_VERIFY (memcmp (backing, "12\0@", 4) == 0); + } + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + alloc_buffer_copy_bytes (&buf, "1234", 4); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + TEST_VERIFY (alloc_buffer_size (&buf) == 0); + TEST_VERIFY (memcmp (backing, "1234", 4) == 0); + } + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + alloc_buffer_copy_bytes (&buf, "1234", 5); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + TEST_VERIFY (memcmp (backing, "@@@@", 4) == 0); + } + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + alloc_buffer_copy_bytes (&buf, "1234", -1); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + TEST_VERIFY (memcmp (backing, "@@@@", 4) == 0); + } +} + +static void +test_copy_string (void) +{ + char backing[4]; + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + const char *p = alloc_buffer_copy_string (&buf, ""); + TEST_VERIFY (p == backing); + TEST_VERIFY (strcmp (p, "") == 0); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + TEST_VERIFY (alloc_buffer_size (&buf) == 3); + TEST_VERIFY (memcmp (backing, "\0@@@", 4) == 0); + } + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + const char *p = alloc_buffer_copy_string (&buf, "1"); + TEST_VERIFY (p == backing); + TEST_VERIFY (strcmp (p, "1") == 0); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + TEST_VERIFY (alloc_buffer_size (&buf) == 2); + TEST_VERIFY (memcmp (backing, "1\0@@", 4) == 0); + } + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + const char *p = alloc_buffer_copy_string (&buf, "12"); + TEST_VERIFY (p == backing); + TEST_VERIFY (strcmp (p, "12") == 0); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + TEST_VERIFY (alloc_buffer_size (&buf) == 1); + TEST_VERIFY (memcmp (backing, "12\0@", 4) == 0); + } + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + const char *p = alloc_buffer_copy_string (&buf, "123"); + TEST_VERIFY (p == backing); + TEST_VERIFY (strcmp (p, "123") == 0); + TEST_VERIFY (!alloc_buffer_has_failed (&buf)); + TEST_VERIFY (alloc_buffer_size (&buf) == 0); + TEST_VERIFY (memcmp (backing, "123", 4) == 0); + } + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + TEST_VERIFY (alloc_buffer_copy_string (&buf, "1234") == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + TEST_VERIFY (memcmp (backing, "@@@@", 4) == 0); + } + { + memset (backing, '@', sizeof (backing)); + struct alloc_buffer buf = alloc_buffer_create (backing, sizeof (backing)); + TEST_VERIFY (alloc_buffer_copy_string (&buf, "12345") == NULL); + TEST_VERIFY (alloc_buffer_has_failed (&buf)); + TEST_VERIFY (memcmp (backing, "@@@@", 4) == 0); + } +} + +static int +do_test (void) +{ + test_empty (alloc_buffer_create (NULL, 0)); + test_empty (alloc_buffer_create ((char *) "", 0)); + test_empty (alloc_buffer_create ((void *) 1, 0)); + + { + void *ptr = (void *) ""; /* Cannot be freed. */ + struct alloc_buffer buf = alloc_buffer_allocate (1, &ptr); + test_size_1 (buf); + free (ptr); /* Should have been overwritten. */ + } + + { + void *ptr= (void *) ""; /* Cannot be freed. */ + struct alloc_buffer buf = alloc_buffer_allocate (2, &ptr); + test_size_2 (buf); + free (ptr); /* Should have been overwritten. */ + } + + test_misaligned (0); + test_misaligned (0xc7); + test_misaligned (0xff); + + test_large_misaligned (); + test_large (); + test_copy_bytes (); + test_copy_string (); + + return 0; +} + +#include <support/test-driver.c> |