1 /* Copyright (C) 1999-2020 Massachusetts Institute of Technology.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 /* Debugging versions of malloc & free, to help catch common errors.
19 The routines in this file were adapted from similar routines in the
20 FFTW library (www.fftw.org), written by Matteo Frigo and Steven
21 G. Johnson. FFTW is also GPLed and is also copyrighted by MIT. */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include "config.h"
27
28 #ifdef HAVE_MALLOC_H
29 #include <malloc.h>
30 #endif
31
32 #include "mpi_utils.h"
33 #include "check.h"
34
35 void* (*my_malloc_hook) (size_t) = 0;
36
37 /**********************************************************
38 * DEBUGGING CODE
39 **********************************************************/
40
41 #ifdef DEBUG
42
check_breakpoint(void)43 void check_breakpoint(void)
44 {
45 /* this function is only here so that we can drop into a breakpoint
46 in a debugger when a CHECK macro fails... */
47 }
48
49 #endif
50
51 #ifdef DEBUG_MALLOC
52
53 # undef malloc
54 # undef free
55
56 /*
57 * debugging malloc/free. Initialize every malloced and freed area to
58 * random values, just to make sure we are not using uninitialized
59 * pointers. Also check for writes past the ends of allocated blocks,
60 * and a couple of other things.
61 *
62 */
63
64 static int debug_malloc_cnt = 0;
65 static int debug_malloc_total = 0;
66
67 #define MAGIC 0xABadCafe
68 #define MMAGIC (((int) MAGIC) < 0 ? ((int) MAGIC) : -((int) MAGIC))
69 #define PAD_FACTOR 2
70 #define TWOINTS (2 * sizeof(int))
71
72 #define VERBOSE_ALLOCATION 0
73
74 #if VERBOSE_ALLOCATION
75 #define WHEN_VERBOSE(a) a
76 #else
77 #define WHEN_VERBOSE(a)
78 #endif
79
debug_malloc(size_t n)80 void *debug_malloc(size_t n)
81 {
82 char *p;
83 int i;
84
85 WHEN_VERBOSE(mpi_one_fprintf(stderr,"DEBUG_MALLOC %d\n", n));
86
87 if (n == 0)
88 mpi_one_fprintf(stderr, "(Allocating a block of zero size.)\n");
89
90 debug_malloc_total += n;
91
92 p = (char *) malloc(PAD_FACTOR * n + TWOINTS);
93 CHECK(p, "debug_malloc: out of memory\n");
94
95 /* store the size in a known position */
96 ((int *) p)[0] = n;
97 ((int *) p)[1] = MAGIC;
98 for (i = 0; i < PAD_FACTOR * n; ++i)
99 p[i + TWOINTS] = (char) (i ^ 0xDEADBEEF);
100
101 ++debug_malloc_cnt;
102
103 /* skip the size we stored previously */
104 return (void *) (p + TWOINTS);
105 }
106
debug_free(void * p)107 void debug_free(void *p)
108 {
109 char *q = ((char *) p) - TWOINTS;
110
111 CHECK(p, "debug_free: tried to free NULL pointer!\n");
112 CHECK(q, "debug_free: tried to free NULL+TWOINTS pointer!\n");
113
114 {
115 int n = ((int *) q)[0];
116 int magic = ((int *) q)[1];
117 int i;
118
119 WHEN_VERBOSE(mpi_one_fprintf(stderr,"DEBUG_FREE %d\n", n));
120 CHECK(n != MMAGIC, "Tried to free a freed pointer!\n");
121 *((int *) q) = MMAGIC; /* to detect duplicate free's */
122
123 CHECK(magic == MAGIC, "Wrong magic in debug_free()!\n");
124 ((int *) q)[1] = ~MAGIC;
125
126 CHECK(n >= 0, "Tried to free block with corrupt size descriptor!\n");
127
128 debug_malloc_total -= n;
129
130 CHECK(debug_malloc_total >= 0,
131 "debug_malloc_total went negative!\n");
132
133 /* check for writing past end of array: */
134 for (i = n; i < PAD_FACTOR * n; ++i)
135 if (q[i + TWOINTS] != (char) (i ^ 0xDEADBEEF))
136 mpi_die("Byte %d past end of array has changed!\n"
137 "Array bounds overwritten!\n",
138 i - n + 1);
139 for (i = 0; i < PAD_FACTOR * n; ++i)
140 q[i + TWOINTS] = (char) (i ^ 0xBEEFDEAD);
141
142 --debug_malloc_cnt;
143 free(q);
144 }
145 }
146
147 #endif /* DEBUG */
148
149 /* output current memory usage: */
debug_output_malloc_count(void)150 void debug_output_malloc_count(void)
151 {
152 #ifdef DEBUG_MALLOC
153 mpi_one_fprintf(stderr, "malloc: %d blocks, %g kB\n",
154 debug_malloc_cnt, debug_malloc_total / 1024.0);
155 #endif
156 }
157
158 /* check for memory leaks when debugging */
debug_check_memory_leaks(void)159 void debug_check_memory_leaks(void)
160 {
161 #ifdef DEBUG_MALLOC
162 if (debug_malloc_cnt || debug_malloc_total)
163 mpi_die("MEMORY LEAK!!!\n"
164 "number of unbalanced malloc calls = %d\n"
165 "total leaked bytes = %d\n",
166 debug_malloc_cnt,
167 debug_malloc_total);
168 #endif
169 }
170