[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] alignalloc, xalignalloc: new modules
From: |
Paul Eggert |
Subject: |
[PATCH] alignalloc, xalignalloc: new modules |
Date: |
Sun, 23 Jan 2022 16:33:38 -0800 |
* lib/alignalloc.c, lib/alignalloc.h, lib/xalignalloc.c:
* m4/alignalloc.m4, modules/alignalloc, modules/alignalloc-tests:
* modules/xalignalloc, tests/test-alignalloc.c:
New files.
---
ChangeLog | 8 +++
lib/alignalloc.c | 121 +++++++++++++++++++++++++++++++++++++++
lib/alignalloc.h | 98 +++++++++++++++++++++++++++++++
lib/xalignalloc.c | 33 +++++++++++
m4/alignalloc.m4 | 10 ++++
modules/alignalloc | 32 +++++++++++
modules/alignalloc-tests | 14 +++++
modules/xalignalloc | 23 ++++++++
tests/test-alignalloc.c | 57 ++++++++++++++++++
9 files changed, 396 insertions(+)
create mode 100644 lib/alignalloc.c
create mode 100644 lib/alignalloc.h
create mode 100644 lib/xalignalloc.c
create mode 100644 m4/alignalloc.m4
create mode 100644 modules/alignalloc
create mode 100644 modules/alignalloc-tests
create mode 100644 modules/xalignalloc
create mode 100644 tests/test-alignalloc.c
diff --git a/ChangeLog b/ChangeLog
index c5eebe4872..980d214b8b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2022-01-23 Paul Eggert <eggert@cs.ucla.edu>
+
+ alignalloc, xalignalloc: new modules
+ * lib/alignalloc.c, lib/alignalloc.h, lib/xalignalloc.c:
+ * m4/alignalloc.m4, modules/alignalloc, modules/alignalloc-tests:
+ * modules/xalignalloc, tests/test-alignalloc.c:
+ New files.
+
2022-01-17 Paul Eggert <eggert@cs.ucla.edu>
extern-inline: improve macOS port
diff --git a/lib/alignalloc.c b/lib/alignalloc.c
new file mode 100644
index 0000000000..03988f11a4
--- /dev/null
+++ b/lib/alignalloc.c
@@ -0,0 +1,121 @@
+/* aligned memory allocation
+
+ Copyright 2022 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 <https://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#include <config.h>
+
+#define ALIGNALLOC_INLINE _GL_EXTERN_INLINE
+#include "alignalloc.h"
+
+#include <limits.h>
+#include <stdalign.h>
+#include <stdint.h>
+#include "intprops.h"
+#include "verify.h"
+
+#if !ALIGNALLOC_VIA_ALIGNED_ALLOC
+# if HAVE_POSIX_MEMALIGN
+
+/* posix_memalign requires the alignment to be a power-of-two multiple of
+ sizeof (void *), whereas alignalloc requires it to be a power of two.
+ To make it OK for the latter to call the former, check that
+ sizeof (void *) is a power of two, which is true on all known platforms.
+ This check is here rather than in alignalloc.h to save the compiler
+ the trouble of checking it each time alignalloc.h is included. */
+verify (! (sizeof (void *) & (sizeof (void *) - 1)));
+
+# else /* !HAVE_POSIX_MEMALIGN */
+
+/* Return P aligned down to ALIGNMENT, which should be a power of two. */
+
+static void *
+align_down (void *p, idx_t alignment)
+{
+ char *c = p;
+ return c - ((uintptr_t) p & (alignment - 1));
+}
+
+/* If alignalloc returned R and the base of the originally-allocated
+ storage is less than R - UCHAR_MAX, return the address of a pointer
+ holding the base of the originally-allocated storage. */
+
+static void **
+address_of_pointer_to_malloced (unsigned char *r)
+{
+ /* The pointer P is located at the highest address A such that A is
+ aligned for pointers, and A + sizeof P < R so that there is room
+ for a 0 byte at R - 1. This approach assumes UCHAR_MAX is large
+ enough so that there is room for P; although true on all
+ plausible platforms, check the assumption to be safe. */
+ verify (sizeof (void *) + alignof (void *) - 1 <= UCHAR_MAX);
+
+ return align_down (r - 1 - sizeof (void *), alignof (void *));
+}
+
+/* Return an ALIGNMENT-aligned pointer to new storage of size SIZE,
+ or a null pointer (setting errno) if memory is exhausted.
+ ALIGNMENT must be a power of two.
+ If SIZE is zero, on success return a unique pointer each time.
+ To free storage later, call alignfree. */
+
+void *
+alignalloc (idx_t alignment, idx_t size)
+{
+ /* malloc (ALIGNMENT + SIZE); if it succeeds, there must be at least
+ one byte available before the returned pointer. It's OK if
+ ALIGNMENT + SIZE fits in size_t but not idx_t. */
+
+ size_t malloc_size;
+ unsigned char *q;
+ if (INT_ADD_WRAPV (size, alignment, &malloc_size)
+ || ! (q = malloc (malloc_size)))
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ unsigned char *r = align_down (q + alignment, alignment);
+ idx_t offset = r - q;
+
+ if (offset <= UCHAR_MAX)
+ r[-1] = offset;
+ else
+ {
+ r[-1] = 0;
+ *address_of_pointer_to_malloced (r) = q;
+ }
+
+ return r;
+}
+
+/* Free storage allocated via alignalloc. Do nothing if PTR is null. */
+
+void
+alignfree (void *ptr)
+{
+ if (ptr)
+ {
+ unsigned char *r = ptr;
+ unsigned char offset = r[-1];
+ void *q = offset ? r - offset : *address_of_pointer_to_malloced (r);
+ free (q);
+ }
+}
+
+# endif /* ! HAVE_POSIX_MEMALIGN */
+#endif /* ! ALIGNALLOC_VIA_ALIGNED_ALLOC */
diff --git a/lib/alignalloc.h b/lib/alignalloc.h
new file mode 100644
index 0000000000..7e4c4743e9
--- /dev/null
+++ b/lib/alignalloc.h
@@ -0,0 +1,98 @@
+/* aligned memory allocation
+
+ Copyright 2022 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 <https://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#ifndef ALIGNALLOC_H_
+#define ALIGNALLOC_H_
+
+#include <errno.h>
+#include <stdlib.h>
+#include "idx.h"
+
+#ifndef _GL_INLINE_HEADER_BEGIN
+ #error "Please include config.h first."
+#endif
+_GL_INLINE_HEADER_BEGIN
+#ifndef ALIGNALLOC_INLINE
+# define ALIGNALLOC_INLINE _GL_INLINE
+#endif
+
+/* Whether aligned_alloc supports any power-of-two alignment,
+ returns a nonnull pointer for size-zero allocations,
+ and sets errno on failure. */
+#if 2 < __GLIBC__ + (15 <= __GLIBC_MINOR__)
+# define ALIGNALLOC_VIA_ALIGNED_ALLOC 1
+#else
+# define ALIGNALLOC_VIA_ALIGNED_ALLOC 0
+#endif
+
+#if ALIGNALLOC_VIA_ALIGNED_ALLOC || HAVE_POSIX_MEMALIGN
+
+/* Free storage allocated via alignalloc. Do nothing if PTR is null. */
+
+ALIGNALLOC_INLINE void
+alignfree (void *ptr)
+{
+ free (ptr);
+}
+
+/* Return an ALIGNMENT-aligned pointer to new storage of size SIZE,
+ or a null pointer (setting errno) if memory is exhausted.
+ ALIGNMENT must be a power of two.
+ If SIZE is zero, on success return a unique pointer each time.
+ To free storage later, call alignfree. */
+
+ALIGNALLOC_INLINE
+_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((2))
+/* _GL_ATTRIBUTE_DEALLOC (alignfree, 1) */
+void *
+alignalloc (idx_t alignment, idx_t size)
+{
+ if ((size_t) -1 < alignment)
+ alignment = (size_t) -1;
+ if ((size_t) -1 < size)
+ size = (size_t) -1;
+
+# if ALIGNALLOC_VIA_ALIGNED_ALLOC
+ return aligned_alloc (alignment, size);
+# else
+ void *ptr = NULL;
+ if (alignment < sizeof (void *))
+ alignment = sizeof (void *);
+ errno = posix_memalign (&ptr, alignment, size | !size);
+ return ptr;
+# endif
+}
+
+#else /* ! (ALIGNALLOC_VIA_ALIGNED_ALLOC || HAVE_POSIX_MEMALIGN) */
+
+void alignfree (void *);
+void *alignalloc (idx_t, idx_t)
+ _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((2))
+ _GL_ATTRIBUTE_DEALLOC (alignfree, 1);
+
+#endif
+
+/* Like alignalloc, but die instead of returning a null pointer. */
+void *xalignalloc (idx_t, idx_t)
+ _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((2))
+ _GL_ATTRIBUTE_RETURNS_NONNULL /* _GL_ATTRIBUTE_DEALLOC (alignfree, 1) */;
+
+_GL_INLINE_HEADER_END
+
+#endif /* !ALIGNALLOC_H_ */
diff --git a/lib/xalignalloc.c b/lib/xalignalloc.c
new file mode 100644
index 0000000000..66b682f26a
--- /dev/null
+++ b/lib/xalignalloc.c
@@ -0,0 +1,33 @@
+/* checked aligned memory allocation
+
+ Copyright 2022 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 <https://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#include <config.h>
+
+#include "alignalloc.h"
+
+#include "xalloc.h"
+
+void *
+xalignalloc (idx_t alignment, idx_t size)
+{
+ void *p = alignalloc (alignment, size);
+ if (!p)
+ xalloc_die ();
+ return p;
+}
diff --git a/m4/alignalloc.m4 b/m4/alignalloc.m4
new file mode 100644
index 0000000000..01627a085a
--- /dev/null
+++ b/m4/alignalloc.m4
@@ -0,0 +1,10 @@
+dnl Copyright 2022 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_ALIGNALLOC],
+[
+ AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+ AC_CHECK_FUNCS_ONCE([posix_memalign])
+])
diff --git a/modules/alignalloc b/modules/alignalloc
new file mode 100644
index 0000000000..68c1b14cd4
--- /dev/null
+++ b/modules/alignalloc
@@ -0,0 +1,32 @@
+Description:
+Aligned memory allocation
+
+Files:
+lib/alignalloc.h
+lib/alignalloc.c
+m4/alignalloc.m4
+
+Depends-on:
+extensions
+extern-inline
+idx
+intprops
+posix_memalign
+stdalign
+stdint
+verify
+
+configure.ac:
+gl_ALIGNALLOC
+
+Makefile.am:
+lib_SOURCES += alignalloc.c
+
+Include:
+"alignalloc.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+bug-gnulib@gnu.org
diff --git a/modules/alignalloc-tests b/modules/alignalloc-tests
new file mode 100644
index 0000000000..359f2975d5
--- /dev/null
+++ b/modules/alignalloc-tests
@@ -0,0 +1,14 @@
+Files:
+tests/test-alignalloc.c
+tests/signature.h
+tests/macros.h
+
+Depends-on:
+intprops
+stdint
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-alignalloc
+check_PROGRAMS += test-alignalloc
diff --git a/modules/xalignalloc b/modules/xalignalloc
new file mode 100644
index 0000000000..d336df0842
--- /dev/null
+++ b/modules/xalignalloc
@@ -0,0 +1,23 @@
+Description:
+Checked aligned memory allocation
+
+Files:
+lib/xalignalloc.c
+
+Depends-on:
+alignalloc
+xalloc-die
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += xalignalloc.c
+
+Include:
+"alignalloc.h"
+
+License:
+GPL
+
+Maintainer:
+bug-gnulib@gnu.org
diff --git a/tests/test-alignalloc.c b/tests/test-alignalloc.c
new file mode 100644
index 0000000000..161ab384db
--- /dev/null
+++ b/tests/test-alignalloc.c
@@ -0,0 +1,57 @@
+/* Test alignalloc and alignfree.
+
+ Copyright 2022 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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <alignalloc.h>
+
+#include <stdint.h>
+#include <string.h>
+#include "intprops.h"
+
+#include "signature.h"
+SIGNATURE_CHECK (alignalloc, void *, (idx_t, idx_t));
+SIGNATURE_CHECK (alignfree, void, (void *));
+
+#include "macros.h"
+
+int
+main ()
+{
+ /* Check that alignalloc returns properly aligned storage,
+ when it succeeds. */
+ for (idx_t alignment = 1; ; )
+ {
+ for (idx_t size = 0; size <= 1024; size = size ? 2 * size : 1)
+ {
+ void *p = alignalloc (alignment, size);
+ if (p)
+ {
+ memset (p, 0, size);
+ ASSERT ((uintptr_t) p % alignment == 0);
+ }
+ alignfree (p);
+ }
+ if (INT_MULTIPLY_WRAPV (alignment, 2, &alignment))
+ break;
+ }
+
+ /* Check that alignfree is a no-op on null pointers. */
+ alignfree (NULL);
+
+ return 0;
+}
--
2.32.0
- [PATCH] alignalloc, xalignalloc: new modules,
Paul Eggert <=