1
0
mirror of https://git.savannah.gnu.org/git/gnulib.git synced 2025-08-08 17:22:05 +03:00

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.
This commit is contained in:
Paul Eggert
2022-01-23 16:30:17 -08:00
parent 71f29a9f46
commit a319a3a16e
9 changed files with 396 additions and 0 deletions

View File

@@ -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> 2022-01-17 Paul Eggert <eggert@cs.ucla.edu>
extern-inline: improve macOS port extern-inline: improve macOS port

121
lib/alignalloc.c Normal file
View File

@@ -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 */

98
lib/alignalloc.h Normal file
View File

@@ -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_ */

33
lib/xalignalloc.c Normal file
View File

@@ -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;
}

10
m4/alignalloc.m4 Normal file
View File

@@ -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])
])

32
modules/alignalloc Normal file
View File

@@ -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

14
modules/alignalloc-tests Normal file
View File

@@ -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

23
modules/xalignalloc Normal file
View File

@@ -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

57
tests/test-alignalloc.c Normal file
View File

@@ -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;
}