chiark / gitweb /
Commit 2.4.5-5 as unpacked
[inn-innduct.git] / tests / lib / xmalloc.c
1 /* $Id: xmalloc.c 5379 2002-03-31 21:45:12Z rra $ */
2 /* Test suite for xmalloc and family. */
3
4 #include "config.h"
5 #include "clibrary.h"
6 #include <ctype.h>
7 #include <errno.h>
8 #include <unistd.h>
9
10 /* Linux requires sys/time.h be included before sys/resource.h. */
11 #if HAVE_SYS_TIME_H
12 # include <sys/time.h>
13 #endif
14 #include <sys/resource.h>
15
16 #include "inn/messages.h"
17 #include "libinn.h"
18
19 /* A customized error handler for checking xmalloc's support of them.
20    Prints out the error message and exits with status 1. */
21 static void
22 test_handler(const char *function, size_t size, const char *file, int line)
23 {
24     die("%s %lu %s %d", function, (unsigned long) size, file, line);
25 }
26
27 /* Allocate the amount of memory given and write to all of it to make sure
28    we can, returning true if that succeeded and false on any sort of
29    detectable error. */
30 static int
31 test_malloc(size_t size)
32 {
33     char *buffer;
34     size_t i;
35
36     buffer = xmalloc(size);
37     if (buffer == NULL)
38         return 0;
39     if (size > 0)
40         memset(buffer, 1, size);
41     for (i = 0; i < size; i++)
42         if (buffer[i] != 1)
43             return 0;
44     free(buffer);
45     return 1;
46 }
47
48 /* Allocate half the memory given, write to it, then reallocate to the
49    desired size, writing to the rest and then checking it all.  Returns true
50    on success, false on any failure. */
51 static int
52 test_realloc(size_t size)
53 {
54     char *buffer;
55     size_t i;
56
57     buffer = xmalloc(size / 2);
58     if (buffer == NULL)
59         return 0;
60     if (size / 2 > 0)
61         memset(buffer, 1, size / 2);
62     buffer = xrealloc(buffer, size);
63     if (buffer == NULL)
64         return 0;
65     if (size > 0)
66         memset(buffer + size / 2, 2, size - size / 2);
67     for (i = 0; i < size / 2; i++)
68         if (buffer[i] != 1)
69             return 0;
70     for (i = size / 2; i < size; i++)
71         if (buffer[i] != 2)
72             return 0;
73     free(buffer);
74     return 1;
75 }
76
77 /* Generate a string of the size indicated, call xstrdup on it, and then
78    ensure the result matches.  Returns true on success, false on any
79    failure. */
80 static int
81 test_strdup(size_t size)
82 {
83     char *string, *copy;
84     int match;
85
86     string = xmalloc(size);
87     if (string == NULL)
88         return 0;
89     memset(string, 1, size - 1);
90     string[size - 1] = '\0';
91     copy = xstrdup(string);
92     if (copy == NULL)
93         return 0;
94     match = strcmp(string, copy);
95     free(string);
96     free(copy);
97     return (match == 0);
98 }
99
100 /* Generate a string of the size indicated plus some, call xstrndup on it, and
101    then ensure the result matches.  Returns true on success, false on any
102    failure. */
103 static int
104 test_strndup(size_t size)
105 {
106     char *string, *copy;
107     int match, toomuch;
108
109     string = xmalloc(size + 1);
110     if (string == NULL)
111         return 0;
112     memset(string, 1, size - 1);
113     string[size - 1] = 2;
114     string[size] = '\0';
115     copy = xstrndup(string, size - 1);
116     if (copy == NULL)
117         return 0;
118     match = strncmp(string, copy, size - 1);
119     toomuch = strcmp(string, copy);
120     free(string);
121     free(copy);
122     return (match == 0 && toomuch != 0);
123 }
124
125 /* Allocate the amount of memory given and check that it's all zeroed,
126    returning true if that succeeded and false on any sort of detectable
127    error. */
128 static int
129 test_calloc(size_t size)
130 {
131     char *buffer;
132     size_t i, nelems;
133
134     nelems = size / 4;
135     if (nelems * 4 != size)
136         return 0;
137     buffer = xcalloc(nelems, 4);
138     if (buffer == NULL)
139         return 0;
140     for (i = 0; i < size; i++)
141         if (buffer[i] != 0)
142             return 0;
143     free(buffer);
144     return 1;
145 }
146
147 /* Take the amount of memory to allocate in bytes as a command-line argument
148    and call test_malloc with that amount of memory. */
149 int
150 main(int argc, char *argv[])
151 {
152     size_t size, max;
153     size_t limit = 0;
154     int willfail = 0;
155     unsigned char code;
156     struct rlimit rl;
157
158     if (argc < 3)
159         die("Usage error.  Type, size, and limit must be given.");
160     errno = 0;
161     size = strtol(argv[2], 0, 10);
162     if (size == 0 && errno != 0)
163         sysdie("Invalid size");
164     errno = 0;
165     limit = strtol(argv[3], 0, 10);
166     if (limit == 0 && errno != 0)
167         sysdie("Invalid limit");
168
169     /* If a memory limit was given and we can set memory limits, set it.
170        Otherwise, exit 2, signalling to the driver that the test should be
171        skipped.  We do this here rather than in the driver due to some
172        pathological problems with Linux (setting ulimit in the shell caused
173        the shell to die). */
174     if (limit > 0) {
175 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
176         rl.rlim_cur = limit;
177         rl.rlim_max = limit;
178         if (setrlimit(RLIMIT_DATA, &rl) < 0) {
179             syswarn("Can't set data limit to %lu", (unsigned long) limit);
180             exit(2);
181         }
182 #else
183         warn("Data limits aren't supported.");
184         exit(2);
185 #endif
186     }
187
188     /* If the code is capitalized, install our customized error handler. */
189     code = argv[1][0];
190     if (isupper(code)) {
191         xmalloc_error_handler = test_handler;
192         code = tolower(code);
193     }
194
195     /* Decide if the allocation should fail.  If it should, set willfail to
196        2, so that if it unexpectedly succeeds, we exit with a status
197        indicating that the test should be skipped. */
198     max = size;
199     if (code == 's' || code == 'n')
200         max *= 2;
201     if (limit > 0 && max > limit)
202         willfail = 2;
203
204     switch (code) {
205     case 'c': exit(test_calloc(size) ? willfail : 1);
206     case 'm': exit(test_malloc(size) ? willfail : 1);
207     case 'r': exit(test_realloc(size) ? willfail : 1);
208     case 's': exit(test_strdup(size) ? willfail : 1);
209     case 'n': exit(test_strndup(size) ? willfail : 1);
210     default:
211         die("Unknown mode %c", argv[1][0]);
212         break;
213     }
214     exit(1);
215 }