From: otto Date: Mon, 8 May 2023 11:12:44 +0000 (+0000) Subject: Add a regress test to test various malloc API and heap mismanagement X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=83821b1ea00a9f648a52604999f09a4644502d06;p=openbsd 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. --- diff --git a/regress/lib/libc/malloc/malloc_errs/Makefile b/regress/lib/libc/malloc/malloc_errs/Makefile new file mode 100644 index 00000000000..150f30e671f --- /dev/null +++ b/regress/lib/libc/malloc/malloc_errs/Makefile @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile,v 1.1 2023/05/08 11:12:44 otto Exp $ + +PROG= malloc_errs + +.include diff --git a/regress/lib/libc/malloc/malloc_errs/malloc_errs.c b/regress/lib/libc/malloc/malloc_errs/malloc_errs.c new file mode 100644 index 00000000000..e2ac6dd79a4 --- /dev/null +++ b/regress/lib/libc/malloc/malloc_errs/malloc_errs.c @@ -0,0 +1,286 @@ +/* $OpenBSD: malloc_errs.c,v 1.1 2023/05/08 11:12:44 otto Exp $ */ +/* + * Copyright (c) 2023 Otto Moerbeek + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Test erroneous use of API and heap that malloc should catch */ + +void +clearq(void *p) +{ + int i; + void *q; + + /* Clear delayed free queue */ + for (i = 0; i < 400; i++) { + q = malloc(100); + free(q); + if (p == q) { + fprintf(stderr, "Re-use\n"); + abort(); + } + } +} + +/* test the test setup */ +void +t0(void) +{ + abort(); +} + +/* double free >= page size */ +void +t1(void) +{ + void *p = malloc(10000); + free(p); + free(p); +} + +/* double free chunks are different, have a delayed free list */ +void +t2(void) +{ + void *p, *q; + int i; + + p = malloc(100); + free(p); + clearq(p); + free(p); +} + +/* double free without clearing delayed free list, needs F */ +void +t3(void) +{ + void *p = malloc(100); + free(p); + free(p); +} + +/* free without prior allocation */ +void +t4(void) +{ + free((void*)1); +} + +/* realloc of bogus pointer */ +void +t5(void) +{ + realloc((void*)1, 10); +} + +/* write after free for chunk */ +void +t6(void) +{ + char *p = malloc(32); + free(p); + p[0] = ~p[0]; + clearq(NULL); +} + +/* write after free large alloction */ +void +t7(void) +{ + char *p, *q; + int i; + + p = malloc(10000); + free(p); + p[0] = ~p[0]; + /* force re-use from the cache */ + for (i = 0; i < 100; i++) { + q = malloc(10000); + free(q); + } +} + +/* write after free for chunk, no clearing of delayed free queue */ +void +t8(void) +{ + char *p, *q; + + p = malloc(32); + q = malloc(32); + free(p); + p[0] = ~p[0]; + free(q); +} + +/* canary check */ +void +t9(void) +{ + char *p; + + p = malloc(100); + p[100] = 0; + free(p); +} + +/* t10 is the same as t9 with different flags */ + +/* modified chunk pointer */ +void +t11(void) +{ + char *p = malloc(100); + free(p + 1); +} + +/* free chunk pointer */ +void +t12(void) +{ + char *p = malloc(16); + free(p + 16); +} + +/* freezero with wrong size */ +void +t13(void) +{ + char *p = malloc(16); + freezero(p, 17); +} + +/* freezero with wrong size 2 */ +void +t14(void) +{ + char *p = malloc(15); + freezero(p, 16); +} + +/* freezero with wrong size, pages */ +void +t15(void) +{ + char *p = malloc(getpagesize()); + freezero(p, getpagesize() + 1); +} + +/* recallocarray with wrong size */ +void +t16(void) +{ + abort(); /* not yet */ + char *p = recallocarray(NULL, 0, 16, 1); + char *q = recallocarray(p, 2, 3, 16); +} + +/* recallocarray with wrong size 2 */ +void +t17(void) +{ + char *p = recallocarray(NULL, 0, 15, 1); + char *q = recallocarray(p, 2, 3, 15); +} + +/* recallocarray with wrong size, pages */ +void +t18(void) +{ + abort(); /* not yet */ + char *p = recallocarray(NULL, 0, 1, getpagesize()); + char *q = recallocarray(p, 2, 3, getpagesize()); +} + +struct test { + void (*test)(void); + const char *flags; +}; + +struct test tests[] = { + { t0, "" }, + { t1, "" }, + { t2, "" }, + { t3, "F" }, + { t4, "" }, + { t5, "" }, + { t6, "J" }, + { t7, "JJ" }, + { t8, "FJ" }, + { t9, "C" }, + { t9, "JC" }, /* t10 re-uses code from t9 */ + { t11, "" }, + { t12, "" }, + { t13, "" }, + { t14, "C" }, + { t15, "" }, + { t16, "" }, + { t17, "C" }, + { t18, "" }, +}; + +int main(int argc, char *argv[]) +{ + + const struct rlimit lim = {0, 0}; + int i, status; + pid_t pid; + char num[10]; + char options[10]; + extern char* malloc_options; + + if (argc == 3) { + malloc_options = argv[2]; + /* prevent coredumps */ + setrlimit(RLIMIT_CORE, &lim); + i = atoi(argv[1]); + fprintf(stderr, "Test %d\n", i); + (*tests[i].test)(); + return 0; + } + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + pid = fork(); + switch (pid) { + case 0: + snprintf(options, sizeof(options), "cfjgu%s", tests[i].flags); + snprintf(num, sizeof(num), "%d", i); + execl(argv[0], argv[0], num, options, NULL); + err(1, "exec"); + break; + case -1: + err(1, "fork"); + break; + default: + if (waitpid(pid, &status, 0) == -1) + err(1, "wait"); + if (!WIFSIGNALED(status) || + WTERMSIG(status) != SIGABRT) + errx(1, "Test %d did not abort", i); + break; + } + } + return 0; +} +