mirror of
https://https.git.savannah.gnu.org/git/gnulib.git
synced 2026-04-28 06:33:36 +00:00
Done through sed -e 's/SIZEOF \([(][^()]*[)]\)/countof \1/g' * lib/boot-time.c: Include <stdcountof.h>. * lib/readutmp.c: Include <stdcountof.h>. * lib/boot-time-aux.h (get_linux_boot_time_fallback, get_openbsd_boot_time, get_windows_boot_time): Use countof. * lib/duplocale.c: Include <stdcountof.h>. (SIZEOF): Remove macro. (duplocale): Use countof instead. * lib/fatal-signal.c: Include <stdcountof.h>. (SIZEOF): Remove macro. (num_fatal_signals, actions_allocated): Use countof instead. * lib/iconv_open.c: Include <stdcountof.h>. (SIZEOF): Remove macro. (rpl_iconv_open): Use countof instead. * lib/term-style-control.c: Include <stdcountof.h>. (SIZEOF): Remove macro. (num_job_control_signals): Use countof instead. * lib/uniconv/u16-conv-to-enc.c: Include <stdcountof.h>. (SIZEOF): Remove macro. * lib/uniconv/u32-conv-to-enc.c: Include <stdcountof.h>. (SIZEOF): Remove macro. * lib/uniconv/u-conv-to-enc.h (FUNC): Use countof instead. * lib/uniconv/u16-strconv-to-enc.c: Include <stdcountof.h>. (SIZEOF): Remove macro. * lib/uniconv/u32-strconv-to-enc.c: Include <stdcountof.h>. (SIZEOF): Remove macro. * lib/uniconv/u-strconv-to-enc.h (FUNC): Use countof instead. * lib/uniname/uniname.c: Include <stdcountof.h>. (SIZEOF): Remove macro. (unicode_name_word, unicode_name_word_lookup, unicode_code_to_index, unicode_index_to_code, unicode_character_name, unicode_name_character): Use countof instead. * lib/uniwidth/width.c: Include <stdcountof.h>. (SIZEOF): Remove macro. (uc_width): Use countof instead. * lib/wait-process.c: Include <stdcountof.h>. (SIZEOF): Remove macro. (slaves_allocated): Use countof instead. * lib/gen-uni-tables.c (countof): Renamed from SIZEOF. * modules/boot-time (Depends-on): Add stdcountof-h. * modules/readutmp (Depends-on): Likewise. * modules/duplocale (Depends-on): Likewise. * modules/fatal-signal (Depends-on): Likewise. * modules/iconv_open (Depends-on): Likewise. * modules/term-style-control (Depends-on): Likewise. * modules/uniconv/u16-conv-to-enc (Depends-on): Likewise. * modules/uniconv/u32-conv-to-enc (Depends-on): Likewise. * modules/uniconv/u16-strconv-to-enc (Depends-on): Likewise. * modules/uniconv/u32-strconv-to-enc (Depends-on): Likewise. * modules/uniname/uniname (Depends-on): Likewise. * modules/uniwidth/width (Depends-on): Likewise. * modules/wait-process (Depends-on): Likewise. * tests/macros.h (SIZEOF): Remove macro. * tests/**/*.[hc]: Use countof instead of SIZEOF. Include <stdcountof.h> as needed. * modules/**/*-tests (Depends-on): Add stdcountof-h if needed.
342 lines
7.5 KiB
C
342 lines
7.5 KiB
C
/* Test of simple and straight-forward malloc implementation.
|
|
Copyright (C) 2020-2026 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 Bruno Haible <bruno@clisp.org>, 2020. */
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdcountof.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
#if defined _WIN32 && !defined __CYGWIN__
|
|
|
|
/* Declare VirtualAlloc(), GetSystemInfo. */
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# define WIN32_EXTRA_LEAN
|
|
# include <windows.h>
|
|
|
|
#else
|
|
|
|
/* Declare sysconf(). */
|
|
# include <unistd.h>
|
|
|
|
/* Declare mmap(). */
|
|
# include <sys/types.h>
|
|
# include <sys/mman.h>
|
|
|
|
/* Some old mmap() implementations require the flag MAP_VARIABLE whenever you
|
|
pass an addr == NULL. */
|
|
# ifndef MAP_VARIABLE
|
|
# define MAP_VARIABLE 0
|
|
# endif
|
|
|
|
#endif
|
|
|
|
/* ================= Back end of the malloc implementation ================= */
|
|
|
|
/* The memory page size.
|
|
Once it is initialized, a power of 2. Typically 4096 or 8192. */
|
|
static uintptr_t pagesize;
|
|
|
|
/* Initializes pagesize. */
|
|
static void
|
|
init_pagesize (void)
|
|
{
|
|
#if defined _WIN32 && !defined __CYGWIN__
|
|
/* GetSystemInfo
|
|
<https://msdn.microsoft.com/en-us/library/ms724381.aspx>
|
|
<https://msdn.microsoft.com/en-us/library/ms724958.aspx> */
|
|
SYSTEM_INFO info;
|
|
GetSystemInfo (&info);
|
|
pagesize = info.dwPageSize;
|
|
#else
|
|
pagesize = sysconf (_SC_PAGESIZE);
|
|
#endif
|
|
}
|
|
|
|
/* Allocates a contiguous set of pages of memory.
|
|
size > 0, must be a multiple of pagesize.
|
|
Returns a multiple of PAGESIZE, or 0 upon failure. */
|
|
static uintptr_t
|
|
alloc_pages (size_t size)
|
|
{
|
|
#if defined _WIN32 && !defined __CYGWIN__
|
|
/* VirtualAlloc
|
|
<https://msdn.microsoft.com/en-us/library/aa366887.aspx>
|
|
<https://msdn.microsoft.com/en-us/library/aa366786.aspx> */
|
|
void *mem = VirtualAlloc (NULL, size, MEM_COMMIT, PAGE_READWRITE);
|
|
if (mem == NULL)
|
|
return 0;
|
|
return (uintptr_t) mem;
|
|
#else
|
|
/* Use mmap with the MAP_ANONYMOUS or MAP_ANON flag. */
|
|
void *mem = mmap (NULL, size, PROT_READ | PROT_WRITE,
|
|
MAP_PRIVATE | MAP_ANONYMOUS | MAP_VARIABLE, -1, 0);
|
|
if (mem == (void *)(-1))
|
|
return 0;
|
|
return (uintptr_t) mem;
|
|
#endif
|
|
}
|
|
|
|
/* Frees a contiguous set of pages of memory, returned by alloc_pages.
|
|
size > 0, must be a multiple of pagesize. */
|
|
static void
|
|
free_pages (uintptr_t pages, size_t size)
|
|
{
|
|
#if defined _WIN32 && !defined __CYGWIN__
|
|
/* VirtualFree
|
|
<https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualfree> */
|
|
if (!VirtualFree ((void *) pages, 0, MEM_RELEASE))
|
|
abort ();
|
|
#else
|
|
if ((pages & (pagesize - 1)) != 0)
|
|
abort ();
|
|
if (munmap ((void *) pages, size) < 0)
|
|
abort ();
|
|
#endif
|
|
}
|
|
|
|
/* Cygwin defines PAGESIZE in <limits.h>. */
|
|
#undef PAGESIZE
|
|
|
|
/* ======================= Instantiate the front end ======================= */
|
|
|
|
#define PAGESIZE pagesize
|
|
/* On Cygwin and Linux/PowerPC, PAGESIZE is 65536. On macOS 11, it is 16384.
|
|
On all other platforms, it is either 4096 or 8192. */
|
|
#if defined __CYGWIN__ || (defined __linux__ && defined _ARCH_PPC)
|
|
# define PAGESIZE_MAX 65536
|
|
#else
|
|
# define PAGESIZE_MAX 16384
|
|
#endif
|
|
|
|
#define ALLOC_PAGES alloc_pages
|
|
#define FREE_PAGES free_pages
|
|
#define ALIGNMENT (sizeof (void *)) /* or 8 or 16 or 32 */
|
|
#define PAGE_RESERVED_HEADER_SIZE (3 * UINTPTR_WIDTH / 8) /* = 3 * sizeof (void *) */
|
|
|
|
#include "ssfmalloc.h"
|
|
|
|
/* ================================= Tests ================================= */
|
|
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
|
|
#include "macros.h"
|
|
|
|
/* Fills a block of a given size with some contents. */
|
|
static void
|
|
fill_block (uintptr_t block, size_t size)
|
|
{
|
|
unsigned char code = (size % (UCHAR_MAX - 1)) + 1;
|
|
memset ((char *) block, code, size);
|
|
}
|
|
|
|
/* Verifies that the contents of a block is still present
|
|
(i.e. has not accidentally been overwritten by other operations). */
|
|
static void
|
|
verify_block (uintptr_t block, size_t size)
|
|
{
|
|
unsigned char code = (size % (UCHAR_MAX - 1)) + 1;
|
|
char *p = (char *) block;
|
|
for (; size > 0; p++, size--)
|
|
if ((unsigned char) *p != code)
|
|
abort ();
|
|
}
|
|
|
|
static size_t block_sizes[] =
|
|
{
|
|
/* Small blocks. */
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7,
|
|
8,
|
|
9,
|
|
12,
|
|
15,
|
|
16,
|
|
17,
|
|
24,
|
|
31,
|
|
32,
|
|
37,
|
|
42,
|
|
49,
|
|
57,
|
|
63,
|
|
64,
|
|
65,
|
|
71,
|
|
77,
|
|
83,
|
|
96,
|
|
99,
|
|
110,
|
|
119,
|
|
127,
|
|
128,
|
|
130,
|
|
144,
|
|
150,
|
|
157,
|
|
161,
|
|
169,
|
|
180,
|
|
192,
|
|
199,
|
|
204,
|
|
210,
|
|
224,
|
|
225,
|
|
236,
|
|
241,
|
|
249,
|
|
255,
|
|
256,
|
|
/* Medium blocks. */
|
|
257,
|
|
281,
|
|
284,
|
|
294,
|
|
301,
|
|
308,
|
|
341,
|
|
447,
|
|
525,
|
|
659,
|
|
771,
|
|
842,
|
|
729,
|
|
999,
|
|
1000,
|
|
1020,
|
|
1023,
|
|
1024,
|
|
1025,
|
|
1280,
|
|
1414,
|
|
2047,
|
|
2048,
|
|
2049,
|
|
2096,
|
|
2401,
|
|
2613,
|
|
2843,
|
|
3010,
|
|
3213,
|
|
3512,
|
|
3678,
|
|
3801,
|
|
3900,
|
|
/* Large blocks. */
|
|
4000,
|
|
4060,
|
|
4080,
|
|
4090,
|
|
4095,
|
|
4096,
|
|
4097,
|
|
4121,
|
|
5381,
|
|
7814,
|
|
8191,
|
|
8192,
|
|
8193,
|
|
11238,
|
|
16383,
|
|
16384,
|
|
16385,
|
|
20184,
|
|
51202,
|
|
135010
|
|
};
|
|
|
|
#define RANDOM(n) (rand () % (n))
|
|
#define RANDOM_BLOCK_SIZE() block_sizes[RANDOM (countof (block_sizes))]
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
/* Allow the user to provide a non-default random seed on the command line. */
|
|
if (argc > 1)
|
|
srand (atoi (argv[1]));
|
|
|
|
init_pagesize ();
|
|
|
|
/* Randomly allocate and deallocate blocks.
|
|
Also verify that there are no unexpected modifications to the contents of
|
|
these blocks. */
|
|
{
|
|
char *blocks[countof (block_sizes)];
|
|
|
|
for (size_t i = 0; i < countof (block_sizes); i++)
|
|
blocks[i] = NULL;
|
|
|
|
for (unsigned int repeat = 0; repeat < 100000; repeat++)
|
|
{
|
|
unsigned int operation = RANDOM (2);
|
|
|
|
switch (operation)
|
|
{
|
|
case 0:
|
|
{ /* Allocate a block. */
|
|
size_t i = RANDOM (countof (block_sizes));
|
|
size_t size = block_sizes[i];
|
|
if (blocks[i] == NULL)
|
|
{
|
|
uintptr_t block = allocate_block (size);
|
|
if (block == 0)
|
|
abort ();
|
|
fill_block (block, size);
|
|
blocks[i] = (char *) block;
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
{ /* Free a block. */
|
|
size_t i = RANDOM (countof (block_sizes));
|
|
size_t size = block_sizes[i];
|
|
if (blocks[i] != NULL)
|
|
{
|
|
uintptr_t block = (uintptr_t) blocks[i];
|
|
verify_block (block, size);
|
|
free_block (block);
|
|
blocks[i] = NULL;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Free the remaining blocks. */
|
|
for (size_t i = 0; i < countof (block_sizes); i++)
|
|
if (blocks[i] != NULL)
|
|
{
|
|
uintptr_t block = (uintptr_t) blocks[i];
|
|
size_t size = block_sizes[i];
|
|
verify_block (block, size);
|
|
free_block (block);
|
|
}
|
|
}
|
|
|
|
return test_exit_status;
|
|
}
|