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 Russ Allbery <eagle@eyrie.org>
8 * Copyright 2008, 2012, 2013, 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.
33 #include <portable/system.h>
37 #ifdef HAVE_SYS_TIME_H
38 # include <sys/time.h>
42 /* Linux requires sys/time.h be included before sys/resource.h. */
43 #include <sys/resource.h>
45 #include <util/messages.h>
46 #include <util/xmalloc.h>
50 * A customized error handler for checking xmalloc's support of them. Prints
51 * out the error message and exits with status 1.
54 test_handler(const char *function, size_t size, const char *file, int line)
56 die("%s %lu %s %d", function, (unsigned long) size, file, line);
61 * Allocate the amount of memory given and write to all of it to make sure we
62 * can, returning true if that succeeded and false on any sort of detectable
66 test_malloc(size_t size)
71 buffer = xmalloc(size);
75 memset(buffer, 1, size);
76 for (i = 0; i < size; i++)
85 * Allocate 10 bytes of memory given, write to it, then reallocate to the
86 * desired size, writing to the rest and then checking it all. Returns true
87 * on success, false on any failure.
90 test_realloc(size_t size)
98 memset(buffer, 1, 10);
99 buffer = xrealloc(buffer, size);
103 memset(buffer + 10, 2, size - 10);
104 for (i = 0; i < 10; i++)
107 for (i = 10; i < size; i++)
116 * Like test_realloc, but test allocating an array instead. Returns true on
117 * success, false on any failure.
120 test_reallocarray(size_t n, size_t size)
125 buffer = xmalloc(10);
128 memset(buffer, 1, 10);
129 buffer = xreallocarray(buffer, n, size);
132 if (n > 0 && size > 0)
133 memset(buffer + 10, 2, (n * size) - 10);
134 for (i = 0; i < 10; i++)
137 for (i = 10; i < n * size; i++)
146 * Generate a string of the size indicated, call xstrdup on it, and then
147 * ensure the result matches. Returns true on success, false on any failure.
150 test_strdup(size_t size)
155 string = xmalloc(size);
158 memset(string, 1, size - 1);
159 string[size - 1] = '\0';
160 copy = xstrdup(string);
163 match = strcmp(string, copy);
171 * Generate a string of the size indicated plus some, call xstrndup on it, and
172 * then ensure the result matches. Also test xstrdup on a string that's
173 * shorter than the specified size and ensure that we don't copy too much, and
174 * on a string that's not nul-terminated. Returns true on success, false on
178 test_strndup(size_t size)
181 int shortmatch, nonulmatch, match, toomuch;
183 /* Copy a short string. */
185 memcpy(string, "test", 5);
186 copy = xstrndup(string, size);
187 shortmatch = strcmp(string, copy);
191 /* Copy a string that's not nul-terminated. */
193 memcpy(string, "test", 4);
194 copy = xstrndup(string, 4);
195 nonulmatch = strcmp(copy, "test");
199 /* Now the test of running out of memory. */
200 string = xmalloc(size + 1);
203 memset(string, 1, size - 1);
204 string[size - 1] = 2;
206 copy = xstrndup(string, size - 1);
209 match = strncmp(string, copy, size - 1);
210 toomuch = strcmp(string, copy);
213 return (shortmatch == 0 && nonulmatch == 0 && match == 0 && toomuch != 0);
218 * Allocate the amount of memory given and check that it's all zeroed,
219 * returning true if that succeeded and false on any sort of detectable error.
222 test_calloc(size_t size)
228 if (nelems * 4 != size)
230 buffer = xcalloc(nelems, 4);
233 for (i = 0; i < size; i++)
242 * Test asprintf with a large string (essentially using it as strdup).
243 * Returns true if successful, false otherwise.
246 test_asprintf(size_t size)
251 string = xmalloc(size);
252 memset(string, 42, size - 1);
253 string[size - 1] = '\0';
254 xasprintf(©, "%s", string);
256 for (i = 0; i < size - 1; i++)
259 if (copy[size - 1] != '\0')
266 /* Wrapper around vasprintf to do the va_list stuff. */
267 static void __attribute__((__format__(printf, 2, 3)))
268 xvasprintf_wrapper(char **strp, const char *format, ...)
272 va_start(args, format);
273 xvasprintf(strp, format, args);
279 * Test vasprintf with a large string (essentially using it as strdup).
280 * Returns true if successful, false otherwise.
283 test_vasprintf(size_t size)
288 string = xmalloc(size);
289 memset(string, 42, size - 1);
290 string[size - 1] = '\0';
291 xvasprintf_wrapper(©, "%s", string);
293 for (i = 0; i < size - 1; i++)
296 if (copy[size - 1] != '\0')
304 * Take the amount of memory to allocate in bytes as a command-line argument
305 * and call test_malloc with that amount of memory.
308 main(int argc, char *argv[])
316 die("Usage error. Type, size, and limit must be given.");
318 size = strtol(argv[2], 0, 10);
319 if (size == 0 && errno != 0)
320 sysdie("Invalid size");
322 limit = strtol(argv[3], 0, 10);
323 if (limit == 0 && errno != 0)
324 sysdie("Invalid limit");
326 /* If the code is capitalized, install our customized error handler. */
329 xmalloc_error_handler = test_handler;
330 code = tolower(code);
334 * Decide if the allocation should fail. If it should, set willfail to 2,
335 * so that if it unexpectedly succeeds, we exit with a status indicating
336 * that the test should be skipped.
339 if (code == 's' || code == 'n' || code == 'a' || code == 'v') {
344 if (limit > 0 && max > limit)
348 * If a memory limit was given and we can set memory limits, set it.
349 * Otherwise, exit 2, signalling to the driver that the test should be
350 * skipped. We do this here rather than in the driver due to some
351 * pathological problems with Linux (setting ulimit in the shell caused
355 #if HAVE_SETRLIMIT && defined(RLIMIT_AS)
362 if (setrlimit(RLIMIT_AS, &rl) < 0) {
363 syswarn("Can't set data limit to %lu", (unsigned long) limit);
366 if (size < limit || code == 'r' || code == 'y') {
367 test_size = (code == 'r' || code == 'y') ? 10 : size;
370 tmp = malloc(test_size);
372 syswarn("Can't allocate initial memory of %lu (limit %lu)",
373 (unsigned long) test_size, (unsigned long) limit);
379 warn("Data limits aren't supported.");
385 case 'c': exit(test_calloc(size) ? willfail : 1);
386 case 'm': exit(test_malloc(size) ? willfail : 1);
387 case 'r': exit(test_realloc(size) ? willfail : 1);
388 case 'y': exit(test_reallocarray(4, size / 4) ? willfail : 1);
389 case 's': exit(test_strdup(size) ? willfail : 1);
390 case 'n': exit(test_strndup(size) ? willfail : 1);
391 case 'a': exit(test_asprintf(size) ? willfail : 1);
392 case 'v': exit(test_vasprintf(size) ? willfail : 1);
394 die("Unknown mode %c", argv[1][0]);