2 * Test suite for xmalloc and family.
4 * The canonical version of this file is maintained in the rra-c-util package,
5 * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
7 * Copyright 2000-2001, 2006, 2017, 2020 Russ Allbery <eagle@eyrie.org>
8 * Copyright 2008, 2012-2014
9 * The Board of Trustees of the Leland Stanford Junior University
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
29 * SPDX-License-Identifier: MIT
35 #include <portable/system.h>
40 #ifdef HAVE_SYS_TIME_H
41 # include <sys/time.h>
45 /* Linux requires sys/time.h be included before sys/resource.h. */
46 #include <sys/resource.h>
48 #include <util/messages.h>
49 #include <util/xmalloc.h>
53 * A customized error handler for checking xmalloc's support of them. Prints
54 * out the error message and exits with status 1.
56 static void __attribute__((__noreturn__))
57 test_handler(const char *function, size_t size, const char *file, int line)
59 die("%s %lu %s %d", function, (unsigned long) size, file, line);
64 * Allocate the amount of memory given and write to all of it to make sure we
65 * can, returning true if that succeeded and false on any sort of detectable
69 test_malloc(size_t size)
74 buffer = xmalloc(size);
78 memset(buffer, 1, size);
79 for (i = 0; i < size; i++)
88 * Allocate 10 bytes of memory given, write to it, then reallocate to the
89 * desired size, writing to the rest and then checking it all. Returns true
90 * on success, false on any failure.
93 test_realloc(size_t size)
102 memset(buffer, 1, 10);
103 buffer = xrealloc(buffer, size);
106 memset(buffer + 10, 2, size - 10);
107 for (i = 0; i < 10; i++)
110 for (i = 10; i < size; i++)
119 * Like test_realloc, but test allocating an array instead. Returns true on
120 * success, false on any failure.
123 test_reallocarray(size_t n, size_t size)
128 buffer = xmalloc(10);
131 memset(buffer, 1, 10);
132 buffer = xreallocarray(buffer, n, size);
135 if (n > 0 && size > 0)
136 memset(buffer + 10, 2, (n * size) - 10);
137 for (i = 0; i < 10; i++)
140 for (i = 10; i < n * size; i++)
149 * Generate a string of the size indicated, call xstrdup on it, and then
150 * ensure the result matches. Returns true on success, false on any failure.
153 test_strdup(size_t size)
158 string = xmalloc(size);
161 memset(string, 1, size - 1);
162 string[size - 1] = '\0';
163 copy = xstrdup(string);
166 match = strcmp(string, copy);
174 * Generate a string of the size indicated plus some, call xstrndup on it, and
175 * then ensure the result matches. Also test xstrdup on a string that's
176 * shorter than the specified size and ensure that we don't copy too much, and
177 * on a string that's not nul-terminated. Returns true on success, false on
181 test_strndup(size_t size)
184 int shortmatch, nonulmatch, match, toomuch;
186 /* Copy a short string. */
188 memcpy(string, "test", 5);
189 copy = xstrndup(string, size);
190 shortmatch = strcmp(string, copy);
194 /* Copy a string that's not nul-terminated. */
196 memcpy(string, "test", 4);
197 copy = xstrndup(string, 4);
198 nonulmatch = strcmp(copy, "test");
202 /* Now the test of running out of memory. */
203 string = xmalloc(size + 1);
206 memset(string, 1, size - 1);
207 string[size - 1] = 2;
209 copy = xstrndup(string, size - 1);
212 match = strncmp(string, copy, size - 1);
213 toomuch = strcmp(string, copy);
216 return (shortmatch == 0 && nonulmatch == 0 && match == 0 && toomuch != 0);
221 * Allocate the amount of memory given and check that it's all zeroed,
222 * returning true if that succeeded and false on any sort of detectable error.
225 test_calloc(size_t size)
231 if (nelems * 4 != size)
233 buffer = xcalloc(nelems, 4);
236 for (i = 0; i < size; i++)
245 * Test asprintf with a large string (essentially using it as strdup).
246 * Returns true if successful, false otherwise.
249 test_asprintf(size_t size)
254 string = xmalloc(size);
255 memset(string, 42, size - 1);
256 string[size - 1] = '\0';
257 xasprintf(©, "%s", string);
259 for (i = 0; i < size - 1; i++)
262 if (copy[size - 1] != '\0')
269 /* Wrapper around vasprintf to do the va_list stuff. */
270 static void __attribute__((__format__(printf, 2, 3)))
271 xvasprintf_wrapper(char **strp, const char *format, ...)
275 va_start(args, format);
276 xvasprintf(strp, format, args);
282 * Test vasprintf with a large string (essentially using it as strdup).
283 * Returns true if successful, false otherwise.
286 test_vasprintf(size_t size)
291 string = xmalloc(size);
292 memset(string, 42, size - 1);
293 string[size - 1] = '\0';
294 xvasprintf_wrapper(©, "%s", string);
296 for (i = 0; i < size - 1; i++)
299 if (copy[size - 1] != '\0')
307 * Take the amount of memory to allocate in bytes as a command-line argument
308 * and call test_malloc with that amount of memory.
311 main(int argc, char *argv[])
319 die("Usage error. Type, size, and limit must be given.");
321 size = strtol(argv[2], 0, 10);
322 if (size == 0 && errno != 0)
323 sysdie("Invalid size");
325 limit = strtol(argv[3], 0, 10);
326 if (limit == 0 && errno != 0)
327 sysdie("Invalid limit");
329 /* If the code is capitalized, install our customized error handler. */
332 xmalloc_error_handler = test_handler;
333 code = (unsigned char) tolower(code);
337 * Decide if the allocation should fail. If it should, set willfail to 2,
338 * so that if it unexpectedly succeeds, we exit with a status indicating
339 * that the test should be skipped.
342 if (code == 's' || code == 'n' || code == 'a' || code == 'v') {
347 if (limit > 0 && max > limit)
351 * If a memory limit was given and we can set memory limits, set it.
352 * Otherwise, exit 2, signalling to the driver that the test should be
353 * skipped. We do this here rather than in the driver due to some
354 * pathological problems with Linux (setting ulimit in the shell caused
358 #if HAVE_SETRLIMIT && defined(RLIMIT_AS)
365 if (setrlimit(RLIMIT_AS, &rl) < 0) {
366 syswarn("Can't set data limit to %lu", (unsigned long) limit);
369 if (size < limit || code == 'r' || code == 'y') {
370 test_size = (code == 'r' || code == 'y') ? 10 : size;
373 tmp = malloc(test_size);
375 syswarn("Can't allocate initial memory of %lu (limit %lu)",
376 (unsigned long) test_size, (unsigned long) limit);
382 warn("Data limits aren't supported.");
387 /* clang-format off */
389 case 'c': exit(test_calloc(size) ? willfail : 1);
390 case 'm': exit(test_malloc(size) ? willfail : 1);
391 case 'r': exit(test_realloc(size) ? willfail : 1);
392 case 'y': exit(test_reallocarray(4, size / 4) ? willfail : 1);
393 case 's': exit(test_strdup(size) ? willfail : 1);
394 case 'n': exit(test_strndup(size) ? willfail : 1);
395 case 'a': exit(test_asprintf(size) ? willfail : 1);
396 case 'v': exit(test_vasprintf(size) ? willfail : 1);
397 default: die("Unknown mode %c", argv[1][0]);
399 /* clang-format on */