diff options
Diffstat (limited to 'malloc')
| -rw-r--r-- | malloc/Makefile | 6 | ||||
| -rw-r--r-- | malloc/Versions | 8 | ||||
| -rw-r--r-- | malloc/alloc_buffer_alloc_array.c | 47 | ||||
| -rw-r--r-- | malloc/alloc_buffer_allocate.c | 36 | ||||
| -rw-r--r-- | malloc/alloc_buffer_copy_bytes.c | 34 | ||||
| -rw-r--r-- | malloc/alloc_buffer_copy_string.c | 30 | ||||
| -rw-r--r-- | malloc/alloc_buffer_create_failure.c | 31 | ||||
| -rw-r--r-- | malloc/tst-alloc_buffer.c | 665 |
8 files changed, 856 insertions, 1 deletions
diff --git a/malloc/Makefile b/malloc/Makefile index 14c13f17dc..b50de7cd6c 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -33,6 +33,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ tst-mallocfork2 \ tst-interpose-nothread \ tst-interpose-thread \ + tst-alloc_buffer \ tests-static := \ tst-interpose-static-nothread \ @@ -63,6 +64,11 @@ routines = malloc morecore mcheck mtrace obstack reallocarray \ dynarray_finalize \ dynarray_resize \ dynarray_resize_clear \ + alloc_buffer_alloc_array \ + alloc_buffer_allocate \ + alloc_buffer_copy_bytes \ + alloc_buffer_copy_string \ + alloc_buffer_create_failure \ install-lib := libmcheck.a non-lib.a := libmcheck.a diff --git a/malloc/Versions b/malloc/Versions index 5b543069b3..2357cff3da 100644 --- a/malloc/Versions +++ b/malloc/Versions @@ -76,7 +76,6 @@ libc { __libc_scratch_buffer_grow_preserve; __libc_scratch_buffer_set_array_size; - # Internal name for reallocarray __libc_reallocarray; @@ -86,5 +85,12 @@ libc { __libc_dynarray_finalize; __libc_dynarray_resize; __libc_dynarray_resize_clear; + + # struct alloc_buffer support + __libc_alloc_buffer_alloc_array; + __libc_alloc_buffer_allocate; + __libc_alloc_buffer_copy_bytes; + __libc_alloc_buffer_copy_string; + __libc_alloc_buffer_create_failure; } } diff --git a/malloc/alloc_buffer_alloc_array.c b/malloc/alloc_buffer_alloc_array.c new file mode 100644 index 0000000000..68e14da8dd --- /dev/null +++ b/malloc/alloc_buffer_alloc_array.c @@ -0,0 +1,47 @@ +/* Array allocation from a fixed-size 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 <alloc_buffer.h> +#include <malloc-internal.h> +#include <libc-pointer-arith.h> + +void * +__libc_alloc_buffer_alloc_array (struct alloc_buffer *buf, size_t element_size, + size_t align, size_t count) +{ + size_t current = buf->__alloc_buffer_current; + /* The caller asserts that align is a power of two. */ + size_t aligned = ALIGN_UP (current, align); + size_t size; + bool overflow = check_mul_overflow_size_t (element_size, count, &size); + size_t new_current = aligned + size; + if (!overflow /* Multiplication did not overflow. */ + && aligned >= current /* No overflow in align step. */ + && new_current >= size /* No overflow in size computation. */ + && new_current <= buf->__alloc_buffer_end) /* Room in buffer. */ + { + buf->__alloc_buffer_current = new_current; + return (void *) aligned; + } + else + { + alloc_buffer_mark_failed (buf); + return NULL; + } +} +libc_hidden_def (__libc_alloc_buffer_alloc_array) diff --git a/malloc/alloc_buffer_allocate.c b/malloc/alloc_buffer_allocate.c new file mode 100644 index 0000000000..cbde72b842 --- /dev/null +++ b/malloc/alloc_buffer_allocate.c @@ -0,0 +1,36 @@ +/* Allocate a fixed-size allocation buffer using malloc. + 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 <alloc_buffer.h> + +#include <stdlib.h> + +struct alloc_buffer +__libc_alloc_buffer_allocate (size_t size, void **pptr) +{ + *pptr = malloc (size); + if (*pptr == NULL) + return (struct alloc_buffer) + { + .__alloc_buffer_current = __ALLOC_BUFFER_INVALID_POINTER, + .__alloc_buffer_end = __ALLOC_BUFFER_INVALID_POINTER + }; + else + return alloc_buffer_create (*pptr, size); +} +libc_hidden_def (__libc_alloc_buffer_allocate) diff --git a/malloc/alloc_buffer_copy_bytes.c b/malloc/alloc_buffer_copy_bytes.c new file mode 100644 index 0000000000..66196f1520 --- /dev/null +++ b/malloc/alloc_buffer_copy_bytes.c @@ -0,0 +1,34 @@ +/* Copy an array of bytes into the 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 <alloc_buffer.h> + +#include <string.h> + +/* This function works on a copy of the buffer object, so that it can + remain non-addressable in the caller. */ +struct alloc_buffer +__libc_alloc_buffer_copy_bytes (struct alloc_buffer buf, + const void *src, size_t len) +{ + void *ptr = alloc_buffer_alloc_bytes (&buf, len); + if (ptr != NULL) + memcpy (ptr, src, len); + return buf; +} +libc_hidden_def (__libc_alloc_buffer_copy_bytes) diff --git a/malloc/alloc_buffer_copy_string.c b/malloc/alloc_buffer_copy_string.c new file mode 100644 index 0000000000..77c0023d51 --- /dev/null +++ b/malloc/alloc_buffer_copy_string.c @@ -0,0 +1,30 @@ +/* Copy a string into the allocation 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 <alloc_buffer.h> + +#include <string.h> + +/* This function works on a copy of the buffer object, so that it can + remain non-addressable in the caller. */ +struct alloc_buffer +__libc_alloc_buffer_copy_string (struct alloc_buffer buf, const char *src) +{ + return __libc_alloc_buffer_copy_bytes (buf, src, strlen (src) + 1); +} +libc_hidden_def (__libc_alloc_buffer_copy_string) diff --git a/malloc/alloc_buffer_create_failure.c b/malloc/alloc_buffer_create_failure.c new file mode 100644 index 0000000000..5ffba22f7b --- /dev/null +++ b/malloc/alloc_buffer_create_failure.c @@ -0,0 +1,31 @@ +/* Terminate the process as the result of an invalid allocation 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 <alloc_buffer.h> +#include <stdio.h> + +void +__libc_alloc_buffer_create_failure (void *start, size_t size) +{ + char buf[200]; + __snprintf (buf, sizeof (buf), "Fatal glibc error: " + "invalid allocation buffer of size %zu\n", + size); + __libc_fatal (buf); +} +libc_hidden_def (__libc_alloc_buffer_create_failure) 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)); |
