summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorotto <>2023-05-08 11:12:44 +0000
committerotto <>2023-05-08 11:12:44 +0000
commit745cf5b816e8fe10c0a183d44dbe02c5164f3b9c (patch)
tree3af3023bc538eb764a6c59db7b8347092f91284c /src
parentdbacc95dab05b2f7f5be580c37bd7087b740fa0a (diff)
downloadopenbsd-745cf5b816e8fe10c0a183d44dbe02c5164f3b9c.tar.gz
openbsd-745cf5b816e8fe10c0a183d44dbe02c5164f3b9c.tar.bz2
openbsd-745cf5b816e8fe10c0a183d44dbe02c5164f3b9c.zip
Add a regress test to test various malloc API and heap mismanagement
errors which should cause abort. A few are not enabled yet, they will be once the corresponding diffs in malloc are committed.
Diffstat (limited to 'src')
-rw-r--r--src/regress/lib/libc/malloc/malloc_errs/Makefile5
-rw-r--r--src/regress/lib/libc/malloc/malloc_errs/malloc_errs.c286
2 files changed, 291 insertions, 0 deletions
diff --git a/src/regress/lib/libc/malloc/malloc_errs/Makefile b/src/regress/lib/libc/malloc/malloc_errs/Makefile
new file mode 100644
index 0000000000..150f30e671
--- /dev/null
+++ b/src/regress/lib/libc/malloc/malloc_errs/Makefile
@@ -0,0 +1,5 @@
1# $OpenBSD: Makefile,v 1.1 2023/05/08 11:12:44 otto Exp $
2
3PROG= malloc_errs
4
5.include <bsd.regress.mk>
diff --git a/src/regress/lib/libc/malloc/malloc_errs/malloc_errs.c b/src/regress/lib/libc/malloc/malloc_errs/malloc_errs.c
new file mode 100644
index 0000000000..e2ac6dd79a
--- /dev/null
+++ b/src/regress/lib/libc/malloc/malloc_errs/malloc_errs.c
@@ -0,0 +1,286 @@
1/* $OpenBSD: malloc_errs.c,v 1.1 2023/05/08 11:12:44 otto Exp $ */
2/*
3 * Copyright (c) 2023 Otto Moerbeek <otto@drijf.net>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/resource.h>
19#include <sys/wait.h>
20#include <err.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <signal.h>
24#include <unistd.h>
25
26/* Test erroneous use of API and heap that malloc should catch */
27
28void
29clearq(void *p)
30{
31 int i;
32 void *q;
33
34 /* Clear delayed free queue */
35 for (i = 0; i < 400; i++) {
36 q = malloc(100);
37 free(q);
38 if (p == q) {
39 fprintf(stderr, "Re-use\n");
40 abort();
41 }
42 }
43}
44
45/* test the test setup */
46void
47t0(void)
48{
49 abort();
50}
51
52/* double free >= page size */
53void
54t1(void)
55{
56 void *p = malloc(10000);
57 free(p);
58 free(p);
59}
60
61/* double free chunks are different, have a delayed free list */
62void
63t2(void)
64{
65 void *p, *q;
66 int i;
67
68 p = malloc(100);
69 free(p);
70 clearq(p);
71 free(p);
72}
73
74/* double free without clearing delayed free list, needs F */
75void
76t3(void)
77{
78 void *p = malloc(100);
79 free(p);
80 free(p);
81}
82
83/* free without prior allocation */
84void
85t4(void)
86{
87 free((void*)1);
88}
89
90/* realloc of bogus pointer */
91void
92t5(void)
93{
94 realloc((void*)1, 10);
95}
96
97/* write after free for chunk */
98void
99t6(void)
100{
101 char *p = malloc(32);
102 free(p);
103 p[0] = ~p[0];
104 clearq(NULL);
105}
106
107/* write after free large alloction */
108void
109t7(void)
110{
111 char *p, *q;
112 int i;
113
114 p = malloc(10000);
115 free(p);
116 p[0] = ~p[0];
117 /* force re-use from the cache */
118 for (i = 0; i < 100; i++) {
119 q = malloc(10000);
120 free(q);
121 }
122}
123
124/* write after free for chunk, no clearing of delayed free queue */
125void
126t8(void)
127{
128 char *p, *q;
129
130 p = malloc(32);
131 q = malloc(32);
132 free(p);
133 p[0] = ~p[0];
134 free(q);
135}
136
137/* canary check */
138void
139t9(void)
140{
141 char *p;
142
143 p = malloc(100);
144 p[100] = 0;
145 free(p);
146}
147
148/* t10 is the same as t9 with different flags */
149
150/* modified chunk pointer */
151void
152t11(void)
153{
154 char *p = malloc(100);
155 free(p + 1);
156}
157
158/* free chunk pointer */
159void
160t12(void)
161{
162 char *p = malloc(16);
163 free(p + 16);
164}
165
166/* freezero with wrong size */
167void
168t13(void)
169{
170 char *p = malloc(16);
171 freezero(p, 17);
172}
173
174/* freezero with wrong size 2 */
175void
176t14(void)
177{
178 char *p = malloc(15);
179 freezero(p, 16);
180}
181
182/* freezero with wrong size, pages */
183void
184t15(void)
185{
186 char *p = malloc(getpagesize());
187 freezero(p, getpagesize() + 1);
188}
189
190/* recallocarray with wrong size */
191void
192t16(void)
193{
194 abort(); /* not yet */
195 char *p = recallocarray(NULL, 0, 16, 1);
196 char *q = recallocarray(p, 2, 3, 16);
197}
198
199/* recallocarray with wrong size 2 */
200void
201t17(void)
202{
203 char *p = recallocarray(NULL, 0, 15, 1);
204 char *q = recallocarray(p, 2, 3, 15);
205}
206
207/* recallocarray with wrong size, pages */
208void
209t18(void)
210{
211 abort(); /* not yet */
212 char *p = recallocarray(NULL, 0, 1, getpagesize());
213 char *q = recallocarray(p, 2, 3, getpagesize());
214}
215
216struct test {
217 void (*test)(void);
218 const char *flags;
219};
220
221struct test tests[] = {
222 { t0, "" },
223 { t1, "" },
224 { t2, "" },
225 { t3, "F" },
226 { t4, "" },
227 { t5, "" },
228 { t6, "J" },
229 { t7, "JJ" },
230 { t8, "FJ" },
231 { t9, "C" },
232 { t9, "JC" }, /* t10 re-uses code from t9 */
233 { t11, "" },
234 { t12, "" },
235 { t13, "" },
236 { t14, "C" },
237 { t15, "" },
238 { t16, "" },
239 { t17, "C" },
240 { t18, "" },
241};
242
243int main(int argc, char *argv[])
244{
245
246 const struct rlimit lim = {0, 0};
247 int i, status;
248 pid_t pid;
249 char num[10];
250 char options[10];
251 extern char* malloc_options;
252
253 if (argc == 3) {
254 malloc_options = argv[2];
255 /* prevent coredumps */
256 setrlimit(RLIMIT_CORE, &lim);
257 i = atoi(argv[1]);
258 fprintf(stderr, "Test %d\n", i);
259 (*tests[i].test)();
260 return 0;
261 }
262
263 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
264 pid = fork();
265 switch (pid) {
266 case 0:
267 snprintf(options, sizeof(options), "cfjgu%s", tests[i].flags);
268 snprintf(num, sizeof(num), "%d", i);
269 execl(argv[0], argv[0], num, options, NULL);
270 err(1, "exec");
271 break;
272 case -1:
273 err(1, "fork");
274 break;
275 default:
276 if (waitpid(pid, &status, 0) == -1)
277 err(1, "wait");
278 if (!WIFSIGNALED(status) ||
279 WTERMSIG(status) != SIGABRT)
280 errx(1, "Test %d did not abort", i);
281 break;
282 }
283 }
284 return 0;
285}
286