From 8e0f4a293e0264b0bfdb0b3e8751418b7eaedbb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Wed, 10 May 2017 23:45:56 +0200 Subject: [PATCH] Determine the default for CRYB_LEAKTEST at run-time. When cryb-test is used as a framework for another project, the compile-time test is useless since cryb-test itself will have been built with coverage disabled. Besides, it is not a reliable indicator of whether leak detection will work. Instead, check if the heap is already dirty when we first gain control. --- include/cryb/test.h | 1 + lib/test/cryb_t_main.c | 17 ++++++++++------- lib/test/cryb_t_malloc.c | 27 +++++++++++++++++++-------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/include/cryb/test.h b/include/cryb/test.h index a511287..340d7f8 100644 --- a/include/cryb/test.h +++ b/include/cryb/test.h @@ -146,6 +146,7 @@ size_t t_malloc_snapshot(void *, size_t); #if CRYB_TEST_HAVE_STDIO void t_malloc_printstats(FILE *); #endif +unsigned long t_malloc_outstanding(void); extern struct t_test t_memory_leak; /* diff --git a/lib/test/cryb_t_main.c b/lib/test/cryb_t_main.c index b1f2a6a..3a4f528 100644 --- a/lib/test/cryb_t_main.c +++ b/lib/test/cryb_t_main.c @@ -251,6 +251,16 @@ t_main(t_prepare_func t_prepare, t_cleanup_func t_cleanup, size_t nt; int opt; + /* + * Enable memory leak detection by default if and only if the heap + * is empty at the start of main(), since otherwise we have no + * reason to trust that it will be empty after we've run the tests + * and cleaned up what we could. + */ + leaktest = t_malloc_outstanding() ? + t_str_is_true(getenv("CRYB_LEAKTEST")) : + !t_str_is_false(getenv("CRYB_LEAKTEST")); + /* make all unintentional allocation failures fatal */ t_malloc_fatal = 1; @@ -266,13 +276,6 @@ t_main(t_prepare_func t_prepare, t_cleanup_func t_cleanup, else 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 */ while ((opt = getopt(argc, argv, "Llv")) != -1) switch (opt) { diff --git a/lib/test/cryb_t_malloc.c b/lib/test/cryb_t_malloc.c index 8059815..4cdd7ec 100644 --- a/lib/test/cryb_t_malloc.c +++ b/lib/test/cryb_t_malloc.c @@ -534,22 +534,33 @@ t_malloc_printstats(FILE *f) nmapalloc, nmapfree, nmapalloc - nmapfree); } +/* + * Return number of outstanding allocations + */ +unsigned long +t_malloc_outstanding(void) +{ + struct bucket *b; + unsigned int shift; + unsigned long n; + + n = nmapalloc - nmapfree; + for (shift = BUCKET_MIN_SHIFT; shift <= BUCKET_MAX_SHIFT; ++shift) { + b = &buckets[shift]; + n += b->nalloc - b->nfree; + } + return (n); +} + /* * Test that fails if we leaked memory */ static int t_malloc_leaked(char **desc, void *arg CRYB_UNUSED) { - struct bucket *b; - unsigned int shift; unsigned long nleaked; - nleaked = 0; - for (shift = BUCKET_MIN_SHIFT; shift <= BUCKET_MAX_SHIFT; ++shift) { - b = &buckets[shift]; - nleaked += b->nalloc - b->nfree; - } - nleaked += nmapalloc - nmapfree; + nleaked = t_malloc_outstanding(); if (nleaked > 0) (void)asprintf(desc, "%lu allocation(s) leaked", nleaked); else