bug-gnulib
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]