]> git.proxmox.com Git - mirror_ovs.git/blob - lib/leak-checker.c
hash: Replace primary hash functions by murmurhash.
[mirror_ovs.git] / lib / leak-checker.c
1 /*
2 * Copyright (c) 2008, 2009, 2010 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18 #include "leak-checker.h"
19 #include <inttypes.h>
20 #include "backtrace.h"
21 #include "vlog.h"
22
23 VLOG_DEFINE_THIS_MODULE(leak_checker);
24
25 #ifndef HAVE_MALLOC_HOOKS
26 void
27 leak_checker_start(const char *file_name OVS_UNUSED)
28 {
29 VLOG_WARN("not enabling leak checker because the libc in use does not "
30 "have the required hooks");
31 }
32
33 void
34 leak_checker_set_limit(off_t max_size OVS_UNUSED)
35 {
36 }
37
38 void
39 leak_checker_claim(const void *p OVS_UNUSED)
40 {
41 }
42
43 void
44 leak_checker_usage(void)
45 {
46 printf(" --check-leaks=FILE (accepted but ignored in this build)\n");
47 }
48 #else /* HAVE_MALLOC_HOOKS */
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <malloc.h>
52 #include <sys/stat.h>
53
54 typedef void *malloc_hook_type(size_t, const void *);
55 typedef void *realloc_hook_type(void *, size_t, const void *);
56 typedef void free_hook_type(void *, const void *);
57
58 struct hooks {
59 malloc_hook_type *malloc_hook_func;
60 realloc_hook_type *realloc_hook_func;
61 free_hook_type *free_hook_func;
62 };
63
64 static malloc_hook_type hook_malloc;
65 static realloc_hook_type hook_realloc;
66 static free_hook_type hook_free;
67
68 static struct hooks libc_hooks;
69 static const struct hooks our_hooks = { hook_malloc, hook_realloc, hook_free };
70
71 static FILE *file;
72 static off_t limit = 10 * 1000 * 1000;
73
74 static void
75 get_hooks(struct hooks *hooks)
76 {
77 hooks->malloc_hook_func = __malloc_hook;
78 hooks->realloc_hook_func = __realloc_hook;
79 hooks->free_hook_func = __free_hook;
80 }
81
82 static void
83 set_hooks(const struct hooks *hooks)
84 {
85 __malloc_hook = hooks->malloc_hook_func;
86 __realloc_hook = hooks->realloc_hook_func;
87 __free_hook = hooks->free_hook_func;
88 }
89
90 void
91 leak_checker_start(const char *file_name)
92 {
93 if (!file) {
94 file = fopen(file_name, "w");
95 if (!file) {
96 VLOG_WARN("failed to create \"%s\": %s",
97 file_name, strerror(errno));
98 return;
99 }
100 setvbuf(file, NULL, _IOLBF, 0);
101 VLOG_WARN("enabled memory leak logging to \"%s\"", file_name);
102 get_hooks(&libc_hooks);
103 set_hooks(&our_hooks);
104 }
105 }
106
107 void
108 leak_checker_stop(void)
109 {
110 if (file) {
111 fclose(file);
112 file = NULL;
113 set_hooks(&libc_hooks);
114 VLOG_WARN("disabled memory leak logging");
115 }
116 }
117
118 void
119 leak_checker_set_limit(off_t limit_)
120 {
121 limit = limit_;
122 }
123
124 void
125 leak_checker_usage(void)
126 {
127 printf(" --check-leaks=FILE log malloc and free calls to FILE\n");
128 }
129
130 static void PRINTF_FORMAT(1, 2)
131 log_callers(const char *format, ...)
132 {
133 struct backtrace backtrace;
134 va_list args;
135 int i;
136
137 va_start(args, format);
138 vfprintf(file, format, args);
139 va_end(args);
140
141 putc(':', file);
142 backtrace_capture(&backtrace);
143 for (i = 0; i < backtrace.n_frames; i++) {
144 fprintf(file, " 0x%"PRIxPTR, backtrace.frames[i]);
145 }
146 putc('\n', file);
147 }
148
149 static void
150 reset_hooks(void)
151 {
152 static int count;
153
154 if (file) {
155 if (ferror(file)) {
156 VLOG_WARN("error writing leak checker log file");
157 leak_checker_stop();
158 return;
159 }
160
161 if (count++ >= 100 && limit) {
162 struct stat s;
163 count = 0;
164 if (fstat(fileno(file), &s) < 0) {
165 VLOG_WARN("cannot fstat leak checker log file: %s",
166 strerror(errno));
167 leak_checker_stop();
168 return;
169 }
170 if (s.st_size > limit) {
171 VLOG_WARN("leak checker log file size exceeded limit");
172 leak_checker_stop();
173 return;
174 }
175 }
176 }
177 if (file) {
178 set_hooks(&our_hooks);
179 }
180 }
181
182 static void *
183 hook_malloc(size_t size, const void *caller OVS_UNUSED)
184 {
185 void *p;
186
187 set_hooks(&libc_hooks);
188 p = malloc(size);
189 get_hooks(&libc_hooks);
190
191 log_callers("malloc(%zu) -> %p", size, p);
192
193 reset_hooks();
194 return p;
195 }
196
197 void
198 leak_checker_claim(const void *p)
199 {
200 if (!file) {
201 return;
202 }
203
204 if (p) {
205 set_hooks(&libc_hooks);
206 log_callers("claim(%p)", p);
207 reset_hooks();
208 }
209 }
210
211 static void
212 hook_free(void *p, const void *caller OVS_UNUSED)
213 {
214 if (!p) {
215 return;
216 }
217
218 set_hooks(&libc_hooks);
219 log_callers("free(%p)", p);
220 free(p);
221 get_hooks(&libc_hooks);
222
223 reset_hooks();
224 }
225
226 static void *
227 hook_realloc(void *p, size_t size, const void *caller OVS_UNUSED)
228 {
229 void *q;
230
231 set_hooks(&libc_hooks);
232 q = realloc(p, size);
233 get_hooks(&libc_hooks);
234
235 if (p != q) {
236 log_callers("realloc(%p, %zu) -> %p", p, size, q);
237 }
238
239 reset_hooks();
240
241 return q;
242 }
243 #endif /* HAVE_MALLOC_HOOKS */