mirror of
https://github.com/cryb-to/cryb-to.git
synced 2024-12-22 12:31:07 +00:00
Add t_malloc_snapshot() which writes a snapshot of the allocator state to
a caller-provided buffer. Use it to warn about leaks in each individual test case. Note that we can't fail a test case for leaking, because individual test cases in a unit may modify shared state which is cleaned up at the end of the series.
This commit is contained in:
parent
3e88a08c10
commit
955cbc3013
4 changed files with 58 additions and 14 deletions
|
@ -136,7 +136,7 @@ AM_CONDITIONAL([WITH_RSAREF], [test x"$with_rsaref" = x"yes"])
|
||||||
AC_ARG_ENABLE([developer-warnings],
|
AC_ARG_ENABLE([developer-warnings],
|
||||||
AS_HELP_STRING([--enable-developer-warnings],
|
AS_HELP_STRING([--enable-developer-warnings],
|
||||||
[enable strict warnings (default is NO)]),
|
[enable strict warnings (default is NO)]),
|
||||||
[CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual"])
|
[CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -Wunreachable-code"])
|
||||||
AC_ARG_ENABLE([debugging-symbols],
|
AC_ARG_ENABLE([debugging-symbols],
|
||||||
AS_HELP_STRING([--enable-debugging-symbols],
|
AS_HELP_STRING([--enable-debugging-symbols],
|
||||||
[enable debugging symbols (default is NO)]),
|
[enable debugging symbols (default is NO)]),
|
||||||
|
|
|
@ -125,6 +125,7 @@ extern const uint8_t t_seq8[256];
|
||||||
extern int t_malloc_fail;
|
extern int t_malloc_fail;
|
||||||
extern int t_malloc_fail_after;
|
extern int t_malloc_fail_after;
|
||||||
extern int t_malloc_fatal;
|
extern int t_malloc_fatal;
|
||||||
|
size_t t_malloc_snapshot(void *, size_t);
|
||||||
#ifdef _IONBF /* proxy for <stdio.h> */
|
#ifdef _IONBF /* proxy for <stdio.h> */
|
||||||
void t_malloc_printstats(FILE *);
|
void t_malloc_printstats(FILE *);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -48,6 +48,9 @@ const char *t_progname;
|
||||||
/* verbose flag */
|
/* verbose flag */
|
||||||
static int verbose;
|
static int verbose;
|
||||||
|
|
||||||
|
/* whether to check for leaks */
|
||||||
|
static int leaktest;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If verbose flag is set, print an array of bytes in hex
|
* If verbose flag is set, print an array of bytes in hex
|
||||||
*/
|
*/
|
||||||
|
@ -161,9 +164,13 @@ t_handle_signal(int signo)
|
||||||
static int
|
static int
|
||||||
t_run_test(struct t_test *t, int n)
|
t_run_test(struct t_test *t, int n)
|
||||||
{
|
{
|
||||||
|
unsigned long snap1[16], snap2[16];
|
||||||
|
size_t snaplen;
|
||||||
char *desc;
|
char *desc;
|
||||||
int i, ret, signo;
|
int i, ret, signo;
|
||||||
|
|
||||||
|
if (leaktest && verbose)
|
||||||
|
t_malloc_snapshot(snap1, sizeof snap1);
|
||||||
for (i = 0; sigs[i] > 0; ++i)
|
for (i = 0; sigs[i] > 0; ++i)
|
||||||
signal(sigs[i], t_handle_signal);
|
signal(sigs[i], t_handle_signal);
|
||||||
desc = t->desc;
|
desc = t->desc;
|
||||||
|
@ -192,6 +199,13 @@ t_run_test(struct t_test *t, int n)
|
||||||
free(desc);
|
free(desc);
|
||||||
for (i = 0; sigs[i] > 0; ++i)
|
for (i = 0; sigs[i] > 0; ++i)
|
||||||
signal(sigs[i], SIG_DFL);
|
signal(sigs[i], SIG_DFL);
|
||||||
|
if (leaktest && verbose) {
|
||||||
|
snaplen = t_malloc_snapshot(snap2, sizeof snap2);
|
||||||
|
if (snaplen > sizeof snap2)
|
||||||
|
snaplen = sizeof snap2;
|
||||||
|
if (memcmp(snap1, snap2, snaplen) != 0)
|
||||||
|
t_verbose("WARNING: allocator state changed\n");
|
||||||
|
}
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +216,7 @@ static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf(stderr, "usage: %s [-v]\n", t_progname);
|
fprintf(stderr, "usage: %s [-Llv]\n", t_progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,9 +242,22 @@ main(int argc, char *argv[])
|
||||||
else
|
else
|
||||||
t_progname = argv[0];
|
t_progname = argv[0];
|
||||||
|
|
||||||
|
/* check for leaks, unless doing coverage analysis */
|
||||||
|
#if CRYB_COVERAGE
|
||||||
|
leaktest = t_str_is_true(getenv("CRYB_LEAKTEST"));
|
||||||
|
#else
|
||||||
|
leaktest = !t_str_is_false(getenv("CRYB_LEAKTEST"));
|
||||||
|
#endif
|
||||||
|
|
||||||
/* parse command line options */
|
/* parse command line options */
|
||||||
while ((opt = getopt(argc, argv, "v")) != -1)
|
while ((opt = getopt(argc, argv, "Llv")) != -1)
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
case 'L':
|
||||||
|
leaktest = 0;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
leaktest = 1;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -246,17 +273,8 @@ main(int argc, char *argv[])
|
||||||
if (t_plan_len == 0)
|
if (t_plan_len == 0)
|
||||||
errx(1, "no plan\n");
|
errx(1, "no plan\n");
|
||||||
|
|
||||||
/* do not check for leaks when doing coverage analysis */
|
|
||||||
nt = t_plan_len;
|
|
||||||
#if CRYB_COVERAGE
|
|
||||||
nt = t_str_is_true(getenv("CRYB_LEAKTEST")) ?
|
|
||||||
t_plan_len + 1 : t_plan_len;
|
|
||||||
#else
|
|
||||||
nt = t_str_is_false(getenv("CRYB_LEAKTEST")) ?
|
|
||||||
t_plan_len : t_plan_len + 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* run the tests */
|
/* run the tests */
|
||||||
|
nt = leaktest ? t_plan_len + 1 : t_plan_len;
|
||||||
printf("1..%zu\n", nt);
|
printf("1..%zu\n", nt);
|
||||||
for (n = pass = fail = 0; n < t_plan_len; ++n)
|
for (n = pass = fail = 0; n < t_plan_len; ++n)
|
||||||
t_run_test(t_plan[n], n + 1) ? ++pass : ++fail;
|
t_run_test(t_plan[n], n + 1) ? ++pass : ++fail;
|
||||||
|
@ -270,7 +288,7 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
free(t_plan);
|
free(t_plan);
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
if (nt > t_plan_len) {
|
if (leaktest) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
t_malloc_printstats(stderr);
|
t_malloc_printstats(stderr);
|
||||||
t_run_test(&t_memory_leak, nt) ? ++pass : ++fail;
|
t_run_test(&t_memory_leak, nt) ? ++pass : ++fail;
|
||||||
|
|
|
@ -466,6 +466,31 @@ free(void *p)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a snapshot of the allocator state
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
t_malloc_snapshot(void *buf, size_t len)
|
||||||
|
{
|
||||||
|
unsigned long snapshot[BUCKET_MAX_SHIFT * 2];
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (buf == NULL)
|
||||||
|
return (sizeof snapshot);
|
||||||
|
snapshot[0] = nmapalloc;
|
||||||
|
snapshot[1] = nmapfree;
|
||||||
|
for (i = 2; i < BUCKET_MIN_SHIFT; ++i)
|
||||||
|
snapshot[i * 2 - 2] = snapshot[i * 2 - 1] = 0;
|
||||||
|
for (i = BUCKET_MIN_SHIFT; i <= BUCKET_MAX_SHIFT; ++i) {
|
||||||
|
snapshot[i * 2 - 2] = buckets[i].nalloc;
|
||||||
|
snapshot[i * 2 - 1] = buckets[i].nfree;
|
||||||
|
}
|
||||||
|
if (len > sizeof snapshot)
|
||||||
|
len = sizeof snapshot;
|
||||||
|
memcpy(buf, snapshot, len);
|
||||||
|
return (sizeof snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print allocator statistics
|
* Print allocator statistics
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue