1 /* Test of simple and straight-forward malloc implementation.
2 Copyright (C) 2020-2024 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2020. */
24 #if defined _WIN32 && !defined __CYGWIN__
26 /* Declare VirtualAlloc(), GetSystemInfo. */
27 # define WIN32_LEAN_AND_MEAN
28 # define WIN32_EXTRA_LEAN
33 /* Declare getpagesize(). */
35 /* On HP-UX, getpagesize exists, but it is not declared in <unistd.h> even if
36 the compiler options -D_HPUX_SOURCE -D_XOPEN_SOURCE=600 are used. */
42 int getpagesize (void);
46 # include <sys/types.h>
47 # include <sys/mman.h>
49 /* Some old mmap() implementations require the flag MAP_VARIABLE whenever you
50 pass an addr == NULL. */
52 # define MAP_VARIABLE 0
57 /* ================= Back end of the malloc implementation ================= */
59 /* The memory page size.
60 Once it is initialized, a power of 2. Typically 4096 or 8192. */
61 static uintptr_t pagesize
;
63 /* Initializes pagesize. */
67 #if defined _WIN32 && !defined __CYGWIN__
69 <https://msdn.microsoft.com/en-us/library/ms724381.aspx>
70 <https://msdn.microsoft.com/en-us/library/ms724958.aspx> */
72 GetSystemInfo (&info
);
73 pagesize
= info
.dwPageSize
;
75 pagesize
= getpagesize ();
79 /* Allocates a contiguous set of pages of memory.
80 size > 0, must be a multiple of pagesize.
81 Returns a multiple of PAGESIZE, or 0 upon failure. */
83 alloc_pages (size_t size
)
85 #if defined _WIN32 && !defined __CYGWIN__
87 <https://msdn.microsoft.com/en-us/library/aa366887.aspx>
88 <https://msdn.microsoft.com/en-us/library/aa366786.aspx> */
89 void *mem
= VirtualAlloc (NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
92 return (uintptr_t) mem
;
94 /* Use mmap with the MAP_ANONYMOUS or MAP_ANON flag. */
95 void *mem
= mmap (NULL
, size
, PROT_READ
| PROT_WRITE
,
96 MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_VARIABLE
, -1, 0);
97 if (mem
== (void *)(-1))
99 return (uintptr_t) mem
;
103 /* Frees a contiguous set of pages of memory, returned by alloc_pages.
104 size > 0, must be a multiple of pagesize. */
106 free_pages (uintptr_t pages
, size_t size
)
108 #if defined _WIN32 && !defined __CYGWIN__
110 <https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualfree> */
111 if (!VirtualFree ((void *) pages
, 0, MEM_RELEASE
))
114 if ((pages
& (pagesize
- 1)) != 0)
116 if (munmap ((void *) pages
, size
) < 0)
121 /* Cygwin defines PAGESIZE in <limits.h>. */
124 /* ======================= Instantiate the front end ======================= */
126 #define PAGESIZE pagesize
127 /* On Cygwin and Linux/PowerPC, PAGESIZE is 65536. On macOS 11, it is 16384.
128 On all other platforms, it is either 4096 or 8192. */
129 #if defined __CYGWIN__ || (defined __linux__ && defined __powerpc__)
130 # define PAGESIZE_MAX 65536
132 # define PAGESIZE_MAX 16384
135 #define ALLOC_PAGES alloc_pages
136 #define FREE_PAGES free_pages
137 #define ALIGNMENT (sizeof (void *)) /* or 8 or 16 or 32 */
138 #define PAGE_RESERVED_HEADER_SIZE (3 * UINTPTR_WIDTH / 8) /* = 3 * sizeof (void *) */
140 #include "ssfmalloc.h"
142 /* ================================= Tests ================================= */
149 /* Fills a block of a given size with some contents. */
151 fill_block (uintptr_t block
, size_t size
)
153 unsigned char code
= (size
% (UCHAR_MAX
- 1)) + 1;
154 memset ((char *) block
, code
, size
);
157 /* Verifies that the contents of a block is still present
158 (i.e. has not accidentally been overwritten by other operations). */
160 verify_block (uintptr_t block
, size_t size
)
162 unsigned char code
= (size
% (UCHAR_MAX
- 1)) + 1;
163 char *p
= (char *) block
;
164 for (; size
> 0; p
++, size
--)
165 if ((unsigned char) *p
!= code
)
169 static size_t block_sizes
[] =
280 #define RANDOM(n) (rand () % (n))
281 #define RANDOM_BLOCK_SIZE() block_sizes[RANDOM (SIZEOF (block_sizes))]
284 main (int argc
, char *argv
[])
286 /* Allow the user to provide a non-default random seed on the command line. */
288 srand (atoi (argv
[1]));
292 /* Randomly allocate and deallocate blocks.
293 Also verify that there are no unexpected modifications to the contents of
297 char *blocks
[SIZEOF (block_sizes
)];
302 for (i
= 0; i
< SIZEOF (block_sizes
); i
++)
306 for (repeat
= 0; repeat
< 100000; repeat
++)
308 unsigned int operation
= RANDOM (2);
313 { /* Allocate a block. */
314 size_t i
= RANDOM (SIZEOF (block_sizes
));
315 size_t size
= block_sizes
[i
];
316 if (blocks
[i
] == NULL
)
318 uintptr_t block
= allocate_block (size
);
321 fill_block (block
, size
);
322 blocks
[i
] = (char *) block
;
327 { /* Free a block. */
328 size_t i
= RANDOM (SIZEOF (block_sizes
));
329 size_t size
= block_sizes
[i
];
330 if (blocks
[i
] != NULL
)
332 uintptr_t block
= (uintptr_t) blocks
[i
];
333 verify_block (block
, size
);
342 /* Free the remaining blocks. */
346 for (i
= 0; i
< SIZEOF (block_sizes
); i
++)
347 if (blocks
[i
] != NULL
)
349 uintptr_t block
= (uintptr_t) blocks
[i
];
350 size_t size
= block_sizes
[i
];
351 verify_block (block
, size
);
357 return test_exit_status
;