Chris@19: /* Chris@19: * Copyright (c) 2003, 2007-14 Matteo Frigo Chris@19: * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology Chris@19: * Chris@19: * This program is free software; you can redistribute it and/or modify Chris@19: * it under the terms of the GNU General Public License as published by Chris@19: * the Free Software Foundation; either version 2 of the License, or Chris@19: * (at your option) any later version. Chris@19: * Chris@19: * This program is distributed in the hope that it will be useful, Chris@19: * but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@19: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@19: * GNU General Public License for more details. Chris@19: * Chris@19: * You should have received a copy of the GNU General Public License Chris@19: * along with this program; if not, write to the Free Software Chris@19: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Chris@19: * Chris@19: */ Chris@19: Chris@19: #include "ifftw.h" Chris@19: Chris@19: /********************************************************** Chris@19: * DEBUGGING CODE Chris@19: **********************************************************/ Chris@19: #if defined(FFTW_DEBUG_MALLOC) Chris@19: Chris@19: #include Chris@19: Chris@19: /* Chris@19: debugging malloc/free. Chris@19: Chris@19: 1) Initialize every malloced and freed area to random values, just Chris@19: to make sure we are not using uninitialized pointers. Chris@19: Chris@19: 2) check for blocks freed twice. Chris@19: Chris@19: 3) Check for writes past the ends of allocated blocks Chris@19: Chris@19: 4) destroy contents of freed blocks in order to detect incorrect reuse. Chris@19: Chris@19: 5) keep track of who allocates what and report memory leaks Chris@19: Chris@19: This code is a quick and dirty hack. May be nonportable. Chris@19: Use at your own risk. Chris@19: Chris@19: */ Chris@19: Chris@19: #define MAGIC ((size_t)0xABadCafe) Chris@19: #define PAD_FACTOR 2 Chris@19: #define SZ_HEADER (4 * sizeof(size_t)) Chris@19: #define HASHSZ 1031 Chris@19: Chris@19: static unsigned int hashaddr(void *p) Chris@19: { Chris@19: return ((unsigned long)p) % HASHSZ; Chris@19: } Chris@19: Chris@19: struct mstat { Chris@19: int siz; Chris@19: int maxsiz; Chris@19: int cnt; Chris@19: int maxcnt; Chris@19: }; Chris@19: Chris@19: static struct mstat mstat[MALLOC_WHAT_LAST]; Chris@19: Chris@19: struct minfo { Chris@19: const char *file; Chris@19: int line; Chris@19: size_t n; Chris@19: void *p; Chris@19: struct minfo *next; Chris@19: }; Chris@19: Chris@19: static struct minfo *minfo[HASHSZ] = {0}; Chris@19: Chris@19: #if defined(HAVE_THREADS) || defined(HAVE_OPENMP) Chris@19: int X(in_thread) = 0; Chris@19: #endif Chris@19: Chris@19: void *X(malloc_debug)(size_t n, enum malloc_tag what, Chris@19: const char *file, int line) Chris@19: { Chris@19: char *p; Chris@19: size_t i; Chris@19: struct minfo *info; Chris@19: struct mstat *stat = mstat + what; Chris@19: struct mstat *estat = mstat + EVERYTHING; Chris@19: Chris@19: if (n == 0) Chris@19: n = 1; Chris@19: Chris@19: if (!IN_THREAD) { Chris@19: stat->siz += n; Chris@19: if (stat->siz > stat->maxsiz) Chris@19: stat->maxsiz = stat->siz; Chris@19: estat->siz += n; Chris@19: if (estat->siz > estat->maxsiz) Chris@19: estat->maxsiz = estat->siz; Chris@19: } Chris@19: Chris@19: p = (char *) X(kernel_malloc)(PAD_FACTOR * n + SZ_HEADER); Chris@19: A(p); Chris@19: Chris@19: /* store the sz in a known position */ Chris@19: ((size_t *) p)[0] = n; Chris@19: ((size_t *) p)[1] = MAGIC; Chris@19: ((size_t *) p)[2] = what; Chris@19: Chris@19: /* fill with junk */ Chris@19: for (i = 0; i < PAD_FACTOR * n; i++) Chris@19: p[i + SZ_HEADER] = (char) (i ^ 0xEF); Chris@19: Chris@19: if (!IN_THREAD) { Chris@19: ++stat->cnt; Chris@19: ++estat->cnt; Chris@19: Chris@19: if (stat->cnt > stat->maxcnt) Chris@19: stat->maxcnt = stat->cnt; Chris@19: if (estat->cnt > estat->maxcnt) Chris@19: estat->maxcnt = estat->cnt; Chris@19: } Chris@19: Chris@19: /* skip the info we stored previously */ Chris@19: p = p + SZ_HEADER; Chris@19: Chris@19: if (!IN_THREAD) { Chris@19: unsigned int h = hashaddr(p); Chris@19: /* record allocation in allocation list */ Chris@19: info = (struct minfo *) malloc(sizeof(struct minfo)); Chris@19: info->n = n; Chris@19: info->file = file; Chris@19: info->line = line; Chris@19: info->p = p; Chris@19: info->next = minfo[h]; Chris@19: minfo[h] = info; Chris@19: } Chris@19: Chris@19: return (void *) p; Chris@19: } Chris@19: Chris@19: void X(ifree)(void *p) Chris@19: { Chris@19: char *q; Chris@19: Chris@19: A(p); Chris@19: Chris@19: q = ((char *) p) - SZ_HEADER; Chris@19: A(q); Chris@19: Chris@19: { Chris@19: size_t n = ((size_t *) q)[0]; Chris@19: size_t magic = ((size_t *) q)[1]; Chris@19: int what = ((size_t *) q)[2]; Chris@19: size_t i; Chris@19: struct mstat *stat = mstat + what; Chris@19: struct mstat *estat = mstat + EVERYTHING; Chris@19: Chris@19: /* set to zero to detect duplicate free's */ Chris@19: ((size_t *) q)[0] = 0; Chris@19: Chris@19: A(magic == MAGIC); Chris@19: ((size_t *) q)[1] = ~MAGIC; Chris@19: Chris@19: if (!IN_THREAD) { Chris@19: stat->siz -= n; Chris@19: A(stat->siz >= 0); Chris@19: estat->siz -= n; Chris@19: A(estat->siz >= 0); Chris@19: } Chris@19: Chris@19: /* check for writing past end of array: */ Chris@19: for (i = n; i < PAD_FACTOR * n; ++i) Chris@19: if (q[i + SZ_HEADER] != (char) (i ^ 0xEF)) { Chris@19: A(0 /* array bounds overwritten */ ); Chris@19: } Chris@19: for (i = 0; i < PAD_FACTOR * n; ++i) Chris@19: q[i + SZ_HEADER] = (char) (i ^ 0xAD); Chris@19: Chris@19: if (!IN_THREAD) { Chris@19: --stat->cnt; Chris@19: --estat->cnt; Chris@19: Chris@19: A(stat->cnt >= 0); Chris@19: A((stat->cnt == 0 && stat->siz == 0) || Chris@19: (stat->cnt > 0 && stat->siz > 0)); Chris@19: A(estat->cnt >= 0); Chris@19: A((estat->cnt == 0 && estat->siz == 0) || Chris@19: (estat->cnt > 0 && estat->siz > 0)); Chris@19: } Chris@19: Chris@19: X(kernel_free)(q); Chris@19: } Chris@19: Chris@19: if (!IN_THREAD) { Chris@19: /* delete minfo entry */ Chris@19: unsigned int h = hashaddr(p); Chris@19: struct minfo **i; Chris@19: Chris@19: for (i = minfo + h; *i; i = &((*i)->next)) { Chris@19: if ((*i)->p == p) { Chris@19: struct minfo *i0 = (*i)->next; Chris@19: free(*i); Chris@19: *i = i0; Chris@19: return; Chris@19: } Chris@19: } Chris@19: Chris@19: A(0 /* no entry in minfo list */ ); Chris@19: } Chris@19: } Chris@19: Chris@19: void X(malloc_print_minfo)(int verbose) Chris@19: { Chris@19: struct minfo *info; Chris@19: int what; Chris@19: unsigned int h; Chris@19: int leak = 0; Chris@19: Chris@19: if (verbose > 2) { Chris@19: static const char *names[MALLOC_WHAT_LAST] = { Chris@19: "EVERYTHING", Chris@19: "PLANS", "SOLVERS", "PROBLEMS", "BUFFERS", Chris@19: "HASHT", "TENSORS", "PLANNERS", "SLVDSC", "TWIDDLES", Chris@19: "STRIDES", "OTHER" Chris@19: }; Chris@19: Chris@19: printf("%12s %8s %8s %10s %10s\n", Chris@19: "what", "cnt", "maxcnt", "siz", "maxsiz"); Chris@19: Chris@19: for (what = 0; what < MALLOC_WHAT_LAST; ++what) { Chris@19: struct mstat *stat = mstat + what; Chris@19: printf("%12s %8d %8d %10d %10d\n", Chris@19: names[what], stat->cnt, stat->maxcnt, Chris@19: stat->siz, stat->maxsiz); Chris@19: } Chris@19: } Chris@19: Chris@19: for (h = 0; h < HASHSZ; ++h) Chris@19: if (minfo[h]) { Chris@19: printf("\nUnfreed allocations:\n"); Chris@19: break; Chris@19: } Chris@19: Chris@19: for (h = 0; h < HASHSZ; ++h) Chris@19: for (info = minfo[h]; info; info = info->next) { Chris@19: leak = 1; Chris@19: printf("%s:%d: %zd bytes at %p\n", Chris@19: info->file, info->line, info->n, info->p); Chris@19: } Chris@19: Chris@19: if (leak) Chris@19: abort(); Chris@19: } Chris@19: Chris@19: #else Chris@19: /********************************************************** Chris@19: * NON DEBUGGING CODE Chris@19: **********************************************************/ Chris@19: /* production version, no hacks */ Chris@19: Chris@19: void *X(malloc_plain)(size_t n) Chris@19: { Chris@19: void *p; Chris@19: if (n == 0) Chris@19: n = 1; Chris@19: p = X(kernel_malloc)(n); Chris@19: CK(p); Chris@19: Chris@19: #ifdef MIN_ALIGNMENT Chris@19: A((((uintptr_t)p) % MIN_ALIGNMENT) == 0); Chris@19: #endif Chris@19: Chris@19: return p; Chris@19: } Chris@19: Chris@19: void X(ifree)(void *p) Chris@19: { Chris@19: X(kernel_free)(p); Chris@19: } Chris@19: Chris@19: #endif Chris@19: Chris@19: void X(ifree0)(void *p) Chris@19: { Chris@19: /* common pattern */ Chris@19: if (p) X(ifree)(p); Chris@19: }