+2024-11-04 Paul Eggert <eggert@cs.ucla.edu>
+
+ malloc etc. tests: use volatile more consistently
+ Typically it’s ineffective to use ‘void *volatile p’
+ when testing malloc and similar functions, as the compiler
+ can optimize the call to malloc before assigning the result
+ to the volatile pointer variable. Instead, be more systematic
+ about calling malloc through a volatile function pointer
+ so that the compiler cannot infer that it is a malloc call.
+ This fix can’t be done for alloca-like functions which may not
+ have a function address, so continue to trust to luck there.
+ * tests/test-aligned-malloc.c (aligned4_malloc, aligned4_free)
+ (aligned8_malloc, aligned8_free, aligned16_malloc)
+ (aligned16_free, aligned32_malloc, aligned32_free):
+ * tests/test-aligned_alloc.c (aligned_alloc):
+ * tests/test-calloc-gnu.c (calloc):
+ * tests/test-free.c (free):
+ * tests/test-malloc-gnu.c (malloc):
+ * tests/test-reallocarray.c (reallocarray):
+ Test indirectly, by calling through a volatile pointer.
+ * tests/test-aligned-malloc.c, tests/test-aligned_alloc.c:
+ * tests/test-calloc-gnu.c, tests/test-calloc-posix.c:
+ * tests/test-free.c, tests/test-malloc-gnu.c:
+ * tests/test-malloc-posix.c, tests/test-realloc-posix.c:
+ * tests/test-reallocarray.c:
+ (main) Don’t bother making data pointers olatile, as it’s ineffective.
+ * tests/test-calloc-gnu.c (identity):
+ * tests/test-free.c (get_errno, get_errno_func):
+ Remove; all uses removed.
+
2024-11-04 Bruno Haible <bruno@clisp.org>
aligned_alloc: Fix test failures on macOS, Solaris (regr. 2024-10-30).
#undef aligned_free
#undef aligned_malloc
#undef ALIGNMENT
+void *(*volatile my_aligned4_malloc) (size_t) = aligned4_malloc;
+#define aligned4_malloc my_aligned4_malloc
+void (*volatile my_aligned4_free) (void *) = aligned4_free;
+#define aligned4_free my_aligned4_free
#define ALIGNMENT 8
#define aligned_malloc aligned8_malloc
#undef aligned_free
#undef aligned_malloc
#undef ALIGNMENT
+void *(*volatile my_aligned8_malloc) (size_t) = aligned8_malloc;
+#define aligned8_malloc my_aligned8_malloc
+void (*volatile my_aligned8_free) (void *) = aligned8_free;
+#define aligned8_free my_aligned8_free
#define ALIGNMENT 16
#define aligned_malloc aligned16_malloc
#undef aligned_free
#undef aligned_malloc
#undef ALIGNMENT
+void *(*volatile my_aligned16_malloc) (size_t) = aligned16_malloc;
+#define aligned16_malloc my_aligned16_malloc
+void (*volatile my_aligned16_free) (void *) = aligned16_free;
+#define aligned16_free my_aligned16_free
#define ALIGNMENT 32
#define aligned_malloc aligned32_malloc
#undef aligned_free
#undef aligned_malloc
#undef ALIGNMENT
+void *(*volatile my_aligned32_malloc) (size_t) = aligned32_malloc;
+#define aligned32_malloc my_aligned32_malloc
+void (*volatile my_aligned32_free) (void *) = aligned32_free;
+#define aligned32_free my_aligned32_free
#include <string.h>
{
static size_t sizes[] =
{ 13, 8, 17, 450, 320, 1, 99, 4, 15, 16, 2, 76, 37, 127, 2406, 641 };
- void *volatile aligned4_blocks[SIZEOF (sizes)];
- void *volatile aligned8_blocks[SIZEOF (sizes)];
- void *volatile aligned16_blocks[SIZEOF (sizes)];
- void *volatile aligned32_blocks[SIZEOF (sizes)];
+ void *aligned4_blocks[SIZEOF (sizes)];
+ void *aligned8_blocks[SIZEOF (sizes)];
+ void *aligned16_blocks[SIZEOF (sizes)];
+ void *aligned32_blocks[SIZEOF (sizes)];
size_t i;
for (i = 0; i < SIZEOF (sizes); i++)
#include "macros.h"
+void *(*volatile my_aligned_alloc) (size_t, size_t) = aligned_alloc;
+#undef aligned_alloc
+#define aligned_alloc my_aligned_alloc
+
#define ROUNDUP(x,y) (((x) + (y) - 1) & - (y))
int
/* Test also a zero size. */
0
};
- void *volatile aligned2_blocks[SIZEOF (sizes)];
- void *volatile aligned4_blocks[SIZEOF (sizes)];
- void *volatile aligned8_blocks[SIZEOF (sizes)];
- void *volatile aligned16_blocks[SIZEOF (sizes)];
- void *volatile aligned32_blocks[SIZEOF (sizes)];
- void *volatile aligned64_blocks[SIZEOF (sizes)];
+ void *aligned2_blocks[SIZEOF (sizes)];
+ void *aligned4_blocks[SIZEOF (sizes)];
+ void *aligned8_blocks[SIZEOF (sizes)];
+ void *aligned16_blocks[SIZEOF (sizes)];
+ void *aligned32_blocks[SIZEOF (sizes)];
+ void *aligned64_blocks[SIZEOF (sizes)];
size_t i;
for (i = 0; i < SIZEOF (sizes); i++)
#include "macros.h"
-/* Return N.
- Usual compilers are not able to infer something about the return value. */
-static size_t
-identity (size_t n)
-{
- unsigned int x = rand ();
- unsigned int y = x * x * x * x;
- x++; y |= x * x * x * x;
- x++; y |= x * x * x * x;
- x++; y |= x * x * x * x;
- y = y >> 1;
- y &= -y;
- y -= 8;
- /* At this point Y is zero but GCC doesn't infer this. */
- return n + y;
-}
+/* Work around clang bug
+ <https://github.com/llvm/llvm-project/issues/114772>. */
+void *(*volatile my_calloc) (size_t, size_t) = calloc;
+#undef calloc
+#define calloc my_calloc
int
main ()
{
/* Check that calloc (0, 0) is not a NULL pointer. */
{
- void * volatile p = calloc (0, 0);
+ void *p = calloc (0, 0);
ASSERT (p != NULL);
free (p);
}
/* Check that calloc fails when requested to allocate a block of memory
- larger than PTRDIFF_MAX or SIZE_MAX bytes.
- Use 'identity' to avoid a compiler warning from GCC 7.
- 'volatile' is needed to defeat an incorrect optimization by clang 10,
- see <https://bugs.llvm.org/show_bug.cgi?id=46055>. */
+ larger than PTRDIFF_MAX or SIZE_MAX bytes. */
{
for (size_t n = 2; n != 0; n <<= 1)
{
- void *volatile p = calloc (PTRDIFF_MAX / n + 1, identity (n));
+ void *p = calloc (PTRDIFF_MAX / n + 1, n);
ASSERT (p == NULL);
ASSERT (errno == ENOMEM);
- p = calloc (SIZE_MAX / n + 1, identity (n));
+ p = calloc (SIZE_MAX / n + 1, n);
ASSERT (p == NULL);
ASSERT (errno == ENOMEM);
}
/* Work around clang bug
<https://github.com/llvm/llvm-project/issues/114772>. */
-void *(* volatile my_calloc) (size_t, size_t) = calloc;
+void *(*volatile my_calloc) (size_t, size_t) = calloc;
+#undef calloc
#define calloc my_calloc
int
nowadays where a 32-bit process can actually allocate 2 GiB of RAM. */
if (sizeof (size_t) >= 8)
{
- void *volatile p;
+ void *p;
errno = 0;
p = calloc (SIZE_MAX / 20, 2);
a GCC optimization. Without it, when optimizing, GCC would "know" that errno
is unchanged by calling free(ptr), when ptr was the result of a malloc(...)
call in the same function. */
-static int
-get_errno (void)
-{
- volatile int err = errno;
- return err;
-}
-
-static int (* volatile get_errno_func) (void) = get_errno;
+void (*volatile my_free) (void *) = free;
+#undef free
+#define free my_free
int
main ()
{
errno = 1789; /* Liberté, égalité, fraternité. */
free (NULL);
- ASSERT_NO_STDIO (get_errno_func () == 1789);
+ ASSERT_NO_STDIO (errno == 1789);
}
{ /* Small memory allocations. */
#define N 10000
- void * volatile ptrs[N];
+ void *ptrs[N];
size_t i;
for (i = 0; i < N; i++)
ptrs[i] = malloc (15);
{
errno = 1789;
free (ptrs[i]);
- ASSERT_NO_STDIO (get_errno_func () == 1789);
+ ASSERT_NO_STDIO (errno == 1789);
}
#undef N
}
{ /* Medium memory allocations. */
#define N 1000
- void * volatile ptrs[N];
+ void *ptrs[N];
size_t i;
for (i = 0; i < N; i++)
ptrs[i] = malloc (729);
{
errno = 1789;
free (ptrs[i]);
- ASSERT_NO_STDIO (get_errno_func () == 1789);
+ ASSERT_NO_STDIO (errno == 1789);
}
#undef N
}
{ /* Large memory allocations. */
#define N 10
- void * volatile ptrs[N];
+ void *ptrs[N];
size_t i;
for (i = 0; i < N; i++)
ptrs[i] = malloc (5318153);
{
errno = 1789;
free (ptrs[i]);
- ASSERT_NO_STDIO (get_errno_func () == 1789);
+ ASSERT_NO_STDIO (errno == 1789);
}
#undef N
}
{
/* Do a large memory allocation. */
size_t big_size = 0x1000000;
- void * volatile ptr = malloc (big_size - 0x100);
+ void *ptr = malloc (big_size - 0x100);
char *ptr_aligned = (char *) ((uintptr_t) ptr & ~(pagesize - 1));
/* This large memory allocation allocated a memory area
from ptr_aligned to ptr_aligned + big_size.
which increases the number of VMAs by 1, which is supposed
to fail. */
free (ptr);
- ASSERT_NO_STDIO (get_errno_func () == 1789);
+ ASSERT_NO_STDIO (errno == 1789);
}
}
}
#include "macros.h"
+/* Work around clang bug
+ <https://github.com/llvm/llvm-project/issues/114772>. */
+void *(*volatile my_malloc) (size_t) = malloc;
+#undef malloc
+#define malloc my_malloc
+
int
main (int argc, _GL_UNUSED char **argv)
{
/* Check that malloc (0) is not a NULL pointer. */
- void *volatile p = malloc (0);
+ void *p = malloc (0);
ASSERT (p != NULL);
free (p);
/* Work around clang bug
<https://github.com/llvm/llvm-project/issues/114772>. */
-void *(* volatile my_malloc) (size_t) = malloc;
+void *(*volatile my_malloc) (size_t) = malloc;
+#undef malloc
#define malloc my_malloc
int
nowadays where a 32-bit process can actually allocate 2 GiB of RAM. */
if (sizeof (size_t) >= 8)
{
- void *volatile p;
+ void *p;
errno = 0;
p = malloc (SIZE_MAX / 10);
/* Work around clang bug
<https://github.com/llvm/llvm-project/issues/114772>. */
-void *(* volatile my_realloc) (void *, size_t) = realloc;
+void *(*volatile my_realloc) (void *, size_t) = realloc;
+#undef realloc
#define realloc my_realloc
int
main (int argc, _GL_UNUSED char **argv)
{
- void *volatile p;
+ void *p;
/* Check that realloc (NULL, 0) is not a NULL pointer. */
p = realloc (NULL, 0);
if (PTRDIFF_MAX < SIZE_MAX)
{
size_t one = argc != 12345;
- void *volatile r = realloc (p, PTRDIFF_MAX + one);
+ void *r = realloc (p, PTRDIFF_MAX + one);
ASSERT (r == NULL);
/* Avoid a test failure due to glibc bug
<https://sourceware.org/bugzilla/show_bug.cgi?id=27870>. */
nowadays where a 32-bit process can actually allocate 2 GiB of RAM. */
if (sizeof (size_t) >= 8)
{
- void *volatile r;
+ void *r;
errno = 0;
r = realloc (p, SIZE_MAX / 10);
#include "macros.h"
+/* Work around clang bug
+ <https://github.com/llvm/llvm-project/issues/114772>. */
+void *(*volatile my_reallocarray) (void *, size_t, size_t) = reallocarray;
+#undef reallocarray
+#define reallocarray my_reallocarray
+
int
main ()
{
of memory larger than PTRDIFF_MAX or SIZE_MAX bytes. */
for (size_t n = 2; n != 0; n <<= 1)
{
- void *volatile p = NULL;
+ void *p = NULL;
if (PTRDIFF_MAX / n + 1 <= SIZE_MAX)
{