]> eyrie.org Git - kerberos/krb5-strength.git/blob - tests/util/xmalloc.c
Change CrackLib tests for system CrackLib
[kerberos/krb5-strength.git] / tests / util / xmalloc.c
1 /*
2  * Test suite for xmalloc and family.
3  *
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/>.
6  *
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
10  *
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:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
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.
28  */
29
30 #line 1 "xmalloc.c"
31
32 #include <config.h>
33 #include <portable/system.h>
34
35 #include <ctype.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_TIME_H
38 # include <sys/time.h>
39 #endif
40 #include <time.h>
41
42 /* Linux requires sys/time.h be included before sys/resource.h. */
43 #include <sys/resource.h>
44
45 #include <util/messages.h>
46 #include <util/xmalloc.h>
47
48
49 /*
50  * A customized error handler for checking xmalloc's support of them.  Prints
51  * out the error message and exits with status 1.
52  */
53 static void
54 test_handler(const char *function, size_t size, const char *file, int line)
55 {
56     die("%s %lu %s %d", function, (unsigned long) size, file, line);
57 }
58
59
60 /*
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
63  * error.
64  */
65 static int
66 test_malloc(size_t size)
67 {
68     char *buffer;
69     size_t i;
70
71     buffer = xmalloc(size);
72     if (buffer == NULL)
73         return 0;
74     if (size > 0)
75         memset(buffer, 1, size);
76     for (i = 0; i < size; i++)
77         if (buffer[i] != 1)
78             return 0;
79     free(buffer);
80     return 1;
81 }
82
83
84 /*
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.
88  */
89 static int
90 test_realloc(size_t size)
91 {
92     char *buffer;
93     size_t i;
94
95     buffer = xmalloc(10);
96     if (buffer == NULL)
97         return 0;
98     memset(buffer, 1, 10);
99     buffer = xrealloc(buffer, size);
100     if (buffer == NULL)
101         return 0;
102     if (size > 0)
103         memset(buffer + 10, 2, size - 10);
104     for (i = 0; i < 10; i++)
105         if (buffer[i] != 1)
106             return 0;
107     for (i = 10; i < size; i++)
108         if (buffer[i] != 2)
109             return 0;
110     free(buffer);
111     return 1;
112 }
113
114
115 /*
116  * Like test_realloc, but test allocating an array instead.  Returns true on
117  * success, false on any failure.
118  */
119 static int
120 test_reallocarray(size_t n, size_t size)
121 {
122     char *buffer;
123     size_t i;
124
125     buffer = xmalloc(10);
126     if (buffer == NULL)
127         return 0;
128     memset(buffer, 1, 10);
129     buffer = xreallocarray(buffer, n, size);
130     if (buffer == NULL)
131         return 0;
132     if (n > 0 && size > 0)
133         memset(buffer + 10, 2, (n * size) - 10);
134     for (i = 0; i < 10; i++)
135         if (buffer[i] != 1)
136             return 0;
137     for (i = 10; i < n * size; i++)
138         if (buffer[i] != 2)
139             return 0;
140     free(buffer);
141     return 1;
142 }
143
144
145 /*
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.
148  */
149 static int
150 test_strdup(size_t size)
151 {
152     char *string, *copy;
153     int match;
154
155     string = xmalloc(size);
156     if (string == NULL)
157         return 0;
158     memset(string, 1, size - 1);
159     string[size - 1] = '\0';
160     copy = xstrdup(string);
161     if (copy == NULL)
162         return 0;
163     match = strcmp(string, copy);
164     free(string);
165     free(copy);
166     return (match == 0);
167 }
168
169
170 /*
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
175  * any failure.
176  */
177 static int
178 test_strndup(size_t size)
179 {
180     char *string, *copy;
181     int shortmatch, nonulmatch, match, toomuch;
182
183     /* Copy a short string. */
184     string = xmalloc(5);
185     memcpy(string, "test", 5);
186     copy = xstrndup(string, size);
187     shortmatch = strcmp(string, copy);
188     free(string);
189     free(copy);
190
191     /* Copy a string that's not nul-terminated. */
192     string = xmalloc(4);
193     memcpy(string, "test", 4);
194     copy = xstrndup(string, 4);
195     nonulmatch = strcmp(copy, "test");
196     free(string);
197     free(copy);
198
199     /* Now the test of running out of memory. */
200     string = xmalloc(size + 1);
201     if (string == NULL)
202         return 0;
203     memset(string, 1, size - 1);
204     string[size - 1] = 2;
205     string[size] = '\0';
206     copy = xstrndup(string, size - 1);
207     if (copy == NULL)
208         return 0;
209     match = strncmp(string, copy, size - 1);
210     toomuch = strcmp(string, copy);
211     free(string);
212     free(copy);
213     return (shortmatch == 0 && nonulmatch == 0 && match == 0 && toomuch != 0);
214 }
215
216
217 /*
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.
220  */
221 static int
222 test_calloc(size_t size)
223 {
224     char *buffer;
225     size_t i, nelems;
226
227     nelems = size / 4;
228     if (nelems * 4 != size)
229         return 0;
230     buffer = xcalloc(nelems, 4);
231     if (buffer == NULL)
232         return 0;
233     for (i = 0; i < size; i++)
234         if (buffer[i] != 0)
235             return 0;
236     free(buffer);
237     return 1;
238 }
239
240
241 /*
242  * Test asprintf with a large string (essentially using it as strdup).
243  * Returns true if successful, false otherwise.
244  */
245 static int
246 test_asprintf(size_t size)
247 {
248     char *copy, *string;
249     size_t i;
250
251     string = xmalloc(size);
252     memset(string, 42, size - 1);
253     string[size - 1] = '\0';
254     xasprintf(&copy, "%s", string);
255     free(string);
256     for (i = 0; i < size - 1; i++)
257         if (copy[i] != 42)
258             return 0;
259     if (copy[size - 1] != '\0')
260         return 0;
261     free(copy);
262     return 1;
263 }
264
265
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, ...)
269 {
270     va_list args;
271
272     va_start(args, format);
273     xvasprintf(strp, format, args);
274     va_end(args);
275 }
276
277
278 /*
279  * Test vasprintf with a large string (essentially using it as strdup).
280  * Returns true if successful, false otherwise.
281  */
282 static int
283 test_vasprintf(size_t size)
284 {
285     char *copy, *string;
286     size_t i;
287
288     string = xmalloc(size);
289     memset(string, 42, size - 1);
290     string[size - 1] = '\0';
291     xvasprintf_wrapper(&copy, "%s", string);
292     free(string);
293     for (i = 0; i < size - 1; i++)
294         if (copy[i] != 42)
295             return 0;
296     if (copy[size - 1] != '\0')
297         return 0;
298     free(copy);
299     return 1;
300 }
301
302
303 /*
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.
306  */
307 int
308 main(int argc, char *argv[])
309 {
310     size_t size, max;
311     size_t limit = 0;
312     int willfail = 0;
313     unsigned char code;
314
315     if (argc < 3)
316         die("Usage error.  Type, size, and limit must be given.");
317     errno = 0;
318     size = strtol(argv[2], 0, 10);
319     if (size == 0 && errno != 0)
320         sysdie("Invalid size");
321     errno = 0;
322     limit = strtol(argv[3], 0, 10);
323     if (limit == 0 && errno != 0)
324         sysdie("Invalid limit");
325
326     /* If the code is capitalized, install our customized error handler. */
327     code = argv[1][0];
328     if (isupper(code)) {
329         xmalloc_error_handler = test_handler;
330         code = tolower(code);
331     }
332
333     /*
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.
337      */
338     max = size;
339     if (code == 's' || code == 'n' || code == 'a' || code == 'v') {
340         max += size;
341         if (limit > 0)
342             limit += size;
343     }
344     if (limit > 0 && max > limit)
345         willfail = 2;
346
347     /*
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
352      * the shell to die).
353      */
354     if (limit > 0) {
355 #if HAVE_SETRLIMIT && defined(RLIMIT_AS)
356         struct rlimit rl;
357         void *tmp;
358         size_t test_size;
359
360         rl.rlim_cur = limit;
361         rl.rlim_max = limit;
362         if (setrlimit(RLIMIT_AS, &rl) < 0) {
363             syswarn("Can't set data limit to %lu", (unsigned long) limit);
364             exit(2);
365         }
366         if (size < limit || code == 'r' || code == 'y') {
367             test_size = (code == 'r' || code == 'y') ? 10 : size;
368             if (test_size == 0)
369                 test_size = 1;
370             tmp = malloc(test_size);
371             if (tmp == NULL) {
372                 syswarn("Can't allocate initial memory of %lu (limit %lu)",
373                         (unsigned long) test_size, (unsigned long) limit);
374                 exit(2);
375             }
376             free(tmp);
377         }
378 #else
379         warn("Data limits aren't supported.");
380         exit(2);
381 #endif
382     }
383
384     switch (code) {
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);
393     default:
394         die("Unknown mode %c", argv[1][0]);
395         break;
396     }
397     exit(1);
398 }