1
0
mirror of https://github.com/openbsd/src.git synced 2025-01-10 06:47:55 -08:00

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.
This commit is contained in:
otto 2023-05-08 11:12:44 +00:00
parent 4b9d1c52db
commit 83821b1ea0
2 changed files with 291 additions and 0 deletions

View File

@ -0,0 +1,5 @@
# $OpenBSD: Makefile,v 1.1 2023/05/08 11:12:44 otto Exp $
PROG= malloc_errs
.include <bsd.regress.mk>

View File

@ -0,0 +1,286 @@
/* $OpenBSD: malloc_errs.c,v 1.1 2023/05/08 11:12:44 otto Exp $ */
/*
* Copyright (c) 2023 Otto Moerbeek <otto@drijf.net>
*
* 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 <sys/resource.h>
#include <sys/wait.h>
#include <err.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
/* 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;
}