* lib/xwalloc-die.c, lib/xwalloc.c, lib/xwalloc.h, lib/xwallocator.c: * modules/xwalloc, modules/xwalloc-die, modules/xwalloc-tests: * modules/xwallocator, tests/test-xwalloc.c: New files. --- ChangeLog | 6 ++ lib/xwalloc-die.c | 46 +++++++++++++++ lib/xwalloc.c | 81 +++++++++++++++++++++++++ lib/xwalloc.h | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/xwallocator.c | 5 ++ modules/xwalloc | 29 +++++++++ modules/xwalloc-die | 26 ++++++++ modules/xwalloc-tests | 8 +++ modules/xwallocator | 23 ++++++++ tests/test-xwalloc.c | 98 +++++++++++++++++++++++++++++++ 10 files changed, 482 insertions(+) create mode 100644 lib/xwalloc-die.c create mode 100644 lib/xwalloc.c create mode 100644 lib/xwalloc.h create mode 100644 lib/xwallocator.c create mode 100644 modules/xwalloc create mode 100644 modules/xwalloc-die create mode 100644 modules/xwalloc-tests create mode 100644 modules/xwallocator create mode 100644 tests/test-xwalloc.c
diff --git a/ChangeLog b/ChangeLog index 7818861..2f99ccc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2017-06-04 Paul Eggert <[email protected]> + xwalloc, xwalloc-die, xwallocator: new modules + * lib/xwalloc-die.c, lib/xwalloc.c, lib/xwalloc.h, lib/xwallocator.c: + * modules/xwalloc, modules/xwalloc-die, modules/xwalloc-tests: + * modules/xwallocator, tests/test-xwalloc.c: + New files. + walloc: new module * lib/walloc.c, lib/walloc.h, modules/walloc: * modules/walloc-tests, tests/test-walloc.c: New files. diff --git a/lib/xwalloc-die.c b/lib/xwalloc-die.c new file mode 100644 index 0000000..e2f632a --- /dev/null +++ b/lib/xwalloc-die.c @@ -0,0 +1,46 @@ +/* Report a memory allocation failure and exit + + Copyright (C) 1997-2000, 2002-2004, 2006, 2009-2017 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "xwalloc.h" + +#include <stdint.h> +#include <stdlib.h> + +#include "error.h" +#include "exitfail.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) + +void +xwalloc_die (size_t nbytes) +{ + if (nbytes == SIZE_MAX) + error (exit_failure, 0, "%s", _("memory exhausted")); + else + error (exit_failure, 0, _("memory exhausted; %zu bytes requested"), + nbytes); + + /* _Noreturn cannot be given to error, since it may return if + its first argument is 0. To help compilers understand that + xwalloc_die does not return, call abort. Also, the abort is a + safety feature if exit_failure is 0 (which shouldn't happen). */ + abort (); +} diff --git a/lib/xwalloc.c b/lib/xwalloc.c new file mode 100644 index 0000000..bb0c96c --- /dev/null +++ b/lib/xwalloc.c @@ -0,0 +1,81 @@ +/* Checked wary memory allocation with signed integer counts + + Copyright 2017 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + Written by Paul Eggert. */ + +#include <config.h> + +#include "xwalloc.h" + +#include "walloc.h" +#include <string.h> + +void * +xwgrowalloc (void *a, ptrdiff_t *pn, ptrdiff_t incr, ptrdiff_t nmax, + ptrdiff_t itemsize) +{ + return wallocmore (a, pn, incr, nmax, itemsize, &xwalloc_allocator); +} + +void * +xwreallocarray (void *a, ptrdiff_t n, ptrdiff_t s) +{ + ptrdiff_t n0 = 0; + return xwgrowalloc (a, &n0, n, n, s); +} + +void * +xwrealloc (void *a, ptrdiff_t n) +{ + return xwreallocarray (a, n, 1); +} + +void * +xwnmalloc (ptrdiff_t n, ptrdiff_t s) +{ + return xwreallocarray (NULL, n, s); +} + +void * +xwmalloc (ptrdiff_t n) +{ + return xwnmalloc (n, 1); +} + +void * +xwcalloc (ptrdiff_t n, ptrdiff_t s) +{ + return memset (xwreallocarray (NULL, n, s), 0, n * s); +} + +void * +xwzalloc (ptrdiff_t n) +{ + return xwcalloc (n, 1); +} + +void * +xwmemdup (void const *a, ptrdiff_t n) +{ + return memcpy (xwmalloc (n), a, n); +} + +char * +xwstrdup (char const *str) +{ + return xwmemdup (str, strlen (str) + 1); +} diff --git a/lib/xwalloc.h b/lib/xwalloc.h new file mode 100644 index 0000000..e8332b8 --- /dev/null +++ b/lib/xwalloc.h @@ -0,0 +1,160 @@ +/* Checked and wary memory allocation with signed integer counts + + Copyright 2017 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + Written by Paul Eggert. */ + + +/* The memory allocators in this module always succeed, and so have a + leading 'x' in their name because they have checked that the result + is nonnull. The allocators are designed for applications that have + a single _Noreturn routine xwalloc_die that is called when memory + allocation fails. They are not suitable for libraries designed to + work in other applications. + + These allocators operate warily in the sense of walloc.h, so they + use ptrdiff_t rather than size_t for byte and object counts. */ + +#ifndef XWALLOC_H_ +#define XWALLOC_H_ + +#include <stddef.h> + +#ifndef _GL_INLINE_HEADER_BEGIN + #error "Please include config.h first." +#endif +_GL_INLINE_HEADER_BEGIN +#ifndef WALLOC_INLINE +# define WALLOC_INLINE _GL_INLINE +#endif + +#if 3 <= __GNUC__ +# define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +#else +# define _GL_ATTRIBUTE_MALLOC +#endif + +#if 4 < __GNUC__ + (3 <= __GNUC_MINOR__) && !defined __clang__ +# define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args)) +#else +# define _GL_ATTRIBUTE_ALLOC_SIZE(args) +#endif + +#if 4 < __GNUC__ + (9 <= __GNUC_MINOR__) +# define _GL_ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__)) +#else +# define _GL_ATTRIBUTE_RETURNS_NONNULL +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Report a memory allocation error and exit. This is suitable for + the DIE member of struct allocator. */ +extern _Noreturn void xwalloc_die (size_t); + +/* An allocator using the stdlib functions and xwalloc_die as a DIE + function. */ +extern struct allocator const xwalloc_allocator; + +/* Here is an example that allocates at most 1000 items; it dies if + this limit is exceeded or if storage is otherwise exhauted. + + float *a; + ptrdiff_t used; + ptrdiff_t allocated; + + void + append_val (float value) + { + if (used == allocated) + a = xwgrowalloc (a, &allocated, 1, 1000, sizeof *a); + a[used++] = value; + } + + */ + +/* These are like the similarly-named functions without the leading 'x', + except that on allocation failure they call xwalloc_die instead + of returning a null pointer. */ +extern void *xwgrowalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t) + _GL_ATTRIBUTE_RETURNS_NONNULL; +extern void *xwreallocarray (void *, ptrdiff_t, ptrdiff_t) + _GL_ATTRIBUTE_ALLOC_SIZE ((2, 3)) _GL_ATTRIBUTE_RETURNS_NONNULL; +extern void *xwmemdup (void const *, ptrdiff_t) _GL_ATTRIBUTE_ALLOC_SIZE ((2)); +extern char *xwstrdup (char const *) _GL_ATTRIBUTE_MALLOC; + +/* These are like the similarly named functions without the leading 'xw', + except they take ptrdiff_t instead of size_t arguments, and on + allocation failure they call xwalloc_die instead of returning a + null pointer. */ +extern void *xwmalloc (ptrdiff_t) + _GL_ATTRIBUTE_ALLOC_SIZE ((1)) _GL_ATTRIBUTE_MALLOC + _GL_ATTRIBUTE_RETURNS_NONNULL; +extern void *xwrealloc (void *, ptrdiff_t) + _GL_ATTRIBUTE_ALLOC_SIZE ((2)) + _GL_ATTRIBUTE_RETURNS_NONNULL; +extern void *xwcalloc (ptrdiff_t, ptrdiff_t) + _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)) _GL_ATTRIBUTE_MALLOC + _GL_ATTRIBUTE_RETURNS_NONNULL; + +/* Allocate a block of N*S bytes, calling xwalloc_die on failure. + N must be nonnegative and S must be positive. */ +extern void *xwnmalloc (ptrdiff_t, ptrdiff_t) + _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2)) _GL_ATTRIBUTE_MALLOC + _GL_ATTRIBUTE_RETURNS_NONNULL; + +/* Allocate a zero-initialied block containing N bytes, calling + xwalloc_die on failure. This is like xwcalloc (N, 1). */ +extern void *xwzalloc (ptrdiff_t) + _GL_ATTRIBUTE_ALLOC_SIZE ((1)) _GL_ATTRIBUTE_MALLOC + _GL_ATTRIBUTE_RETURNS_NONNULL; + +#ifdef __cplusplus +} + +/* C++ does not allow conversions from void * to other pointer types + without a cast. Use templates to work around the problem when + possible. */ + +template <typename T> inline T * +xwgrowalloc (T *a, ptrdiff_t *pn, ptrdiff_t incr, ptrdiff_t nmax, + ptrdiff_t itemsize) +{ + return (T *) xwgrowalloc (a, pn, incr, nmax, itemsize); +} +template <typename T> inline T * +xwmemdup (T *a, ptrdiff_t n) +{ + return (T *) xwmemdup ((void *) a, n); +} +template <typename T> inline T * +void *xwrealloc (T *a, ptrdiff_t n) +{ + return (T *) xwrealloc (a, n); +} +template <typename T> inline T * +xwreallocarray (T *a, ptrdiff_t n, ptrdiff_t s) +{ + return (T *) xwreallocarray ((void *) a, n, s); +} + +#endif + +_GL_INLINE_HEADER_END + +#endif /* !WALLOC_H_ */ diff --git a/lib/xwallocator.c b/lib/xwallocator.c new file mode 100644 index 0000000..e5b09a2 --- /dev/null +++ b/lib/xwallocator.c @@ -0,0 +1,5 @@ +#include <config.h> +#include "allocator.h" +#include "xwalloc.h" +#include <stdlib.h> +struct allocator const xwalloc_allocator = {malloc, realloc, free, xwalloc_die}; diff --git a/modules/xwalloc b/modules/xwalloc new file mode 100644 index 0000000..677679f --- /dev/null +++ b/modules/xwalloc @@ -0,0 +1,29 @@ +Description: +Checked wary memory allocation with signed integer counts + +This module depends on xwalloc-die and xwallocator, modules that +are designed to be overridden by the application as needed. + +Files: +lib/allocator.h +lib/xwalloc.c +lib/xwalloc.h + +Depends-on: +walloc +xwalloc-die +xwallocator + +configure.ac: + +Makefile.am: +lib_SOURCES += xwalloc.c + +Include: +"xwalloc.h" + +License: +GPL + +Maintainer: +all diff --git a/modules/xwalloc-die b/modules/xwalloc-die new file mode 100644 index 0000000..5a90e83 --- /dev/null +++ b/modules/xwalloc-die @@ -0,0 +1,26 @@ +Description: +Report a wary memory allocation failure and exit + +Files: +lib/xwalloc.h +lib/xwalloc-die.c + +Depends-on: +error +gettext-h +exitfail +stdint + +configure.ac: + +Makefile.am: +lib_SOURCES += xwalloc-die.c + +Include: +"walloc.h" + +License: +GPL + +Maintainer: +all diff --git a/modules/xwalloc-tests b/modules/xwalloc-tests new file mode 100644 index 0000000..fbef154 --- /dev/null +++ b/modules/xwalloc-tests @@ -0,0 +1,8 @@ +Files: +tests/test-xwalloc.c + +Depends-on: + +Makefile.am: +TESTS += test-xwalloc +check_PROGRAMS += test-xwalloc diff --git a/modules/xwallocator b/modules/xwallocator new file mode 100644 index 0000000..161565b --- /dev/null +++ b/modules/xwallocator @@ -0,0 +1,23 @@ +Description: +Report a wary memory allocation failure and exit + +Files: +lib/allocator.h +lib/xwalloc.h +lib/xwallocator.c + +Depends-on: + +configure.ac: + +Makefile.am: +lib_SOURCES += xwallocator.c + +Include: +"xwalloc.h" + +License: +GPL + +Maintainer: +all diff --git a/tests/test-xwalloc.c b/tests/test-xwalloc.c new file mode 100644 index 0000000..d368e5d --- /dev/null +++ b/tests/test-xwalloc.c @@ -0,0 +1,98 @@ +/* Test xwalloc module + Copyright 2017 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <xwalloc.h> + +#include <allocator.h> +#include <stdlib.h> +#include <string.h> + +typedef ptrdiff_t item; + +static ptrdiff_t +test (item *p, ptrdiff_t oldn, ptrdiff_t n) +{ + if (!p) + return 0; + for (ptrdiff_t i = 0; i < oldn; i++) + if (p[i] != ~i) + abort (); + for (ptrdiff_t i = oldn; i < n; i++) + p[i] = ~i; + return n; +} + +int died; + +static void +test_died (size_t n) +{ + died++; +} + +static struct allocator const test_allocator + = {malloc, realloc, free, test_died}; + +int +main (void) +{ + ptrdiff_t oldn = 0; + ptrdiff_t n = 1; + item *p = xwreallocarray (0, n, sizeof *p); + for (int j = 0; j < 10; j++) + { + oldn = test (p, oldn, n); + p = xwgrowalloc (p, &n, 1, n + 2, sizeof *p); + oldn = test (p, oldn, n); + + item *q = xwmemdup (p, n * sizeof *p); + test (q, n, n); + free (q); + + char *s = xwstrdup ("hello"); + if (!strcmp (s, "Hello")) + abort (); + free (s); + + q = xwmalloc (n * sizeof *q); + test (q, 0, n); + q = xwrealloc (q, (n + 1) * sizeof *q); + test (q, n, n + 1); + free (q); + + q = xwnmalloc (n, sizeof *q); + test (q, 0, n); + q = xwreallocarray (q, n + 1, sizeof *q); + test (q, n, n + 1); + free (q); + + q = xwcalloc (n, sizeof *q); + for (ptrdiff_t i = 0; i < n; i++) + if (q[i]) + abort (); + free (q); + + q = xwzalloc (n * sizeof *q); + for (ptrdiff_t i = 0; i < n; i++) + if (q[i]) + abort (); + free (q); + } + free (p); + return 0; +} -- 2.9.4
