]> git.proxmox.com Git - mirror_ovs.git/blame - lib/leak-checker.c
ofproto: Only zero stats for non exact-match sub-rules.
[mirror_ovs.git] / lib / leak-checker.c
CommitLineData
064af421
BP
1/*
2 * Copyright (c) 2008, 2009 Nicira Networks.
3 *
a14bc59f
BP
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:
064af421 7 *
a14bc59f
BP
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.
064af421
BP
15 */
16
17#include <config.h>
18#include "leak-checker.h"
19#include <inttypes.h>
20#include "backtrace.h"
21
22#define THIS_MODULE VLM_leak_checker
23#include "vlog.h"
24
25#ifndef HAVE_MALLOC_HOOKS
26void
27leak_checker_start(const char *file_name UNUSED)
28{
29 VLOG_WARN("not enabling leak checker because the libc in use does not "
30 "have the required hooks");
31}
32
33void
34leak_checker_set_limit(off_t max_size UNUSED)
35{
36}
37
38void
39leak_checker_claim(const void *p UNUSED)
40{
41}
42
43void
44leak_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
54typedef void *malloc_hook_type(size_t, const void *);
55typedef void *realloc_hook_type(void *, size_t, const void *);
56typedef void free_hook_type(void *, const void *);
57
58struct hooks {
59 malloc_hook_type *malloc_hook_func;
60 realloc_hook_type *realloc_hook_func;
61 free_hook_type *free_hook_func;
62};
63
64static malloc_hook_type hook_malloc;
65static realloc_hook_type hook_realloc;
66static free_hook_type hook_free;
67
68static struct hooks libc_hooks;
69static const struct hooks our_hooks = { hook_malloc, hook_realloc, hook_free };
70
71static FILE *file;
72static off_t limit = 10 * 1000 * 1000;
73
74static void
75get_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
82static void
83set_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
90void
91leak_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
107void
108leak_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
118void
119leak_checker_set_limit(off_t limit_)
120{
121 limit = limit_;
122}
123
124void
125leak_checker_usage(void)
126{
127 printf(" --check-leaks=FILE log malloc and free calls to FILE\n");
128}
129
130static void PRINTF_FORMAT(1, 2)
131log_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%x", backtrace.frames[i]);
145 }
146 putc('\n', file);
147}
148
149static void
150reset_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
182static void *
183hook_malloc(size_t size, const void *caller 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
197void
198leak_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
211static void
212hook_free(void *p, const void *caller UNUSED)
213{
214 if (!p) {
215 return;
216 }
217
218 set_hooks(&libc_hooks);
219 free(p);
220 get_hooks(&libc_hooks);
221
222 log_callers("free(%p)", p);
223
224 reset_hooks();
225}
226
227static void *
228hook_realloc(void *p, size_t size, const void *caller UNUSED)
229{
230 void *q;
231
232 set_hooks(&libc_hooks);
233 q = realloc(p, size);
234 get_hooks(&libc_hooks);
235
236 if (p != q) {
237 log_callers("realloc(%p, %zu) -> %p", p, size, q);
238 }
239
240 reset_hooks();
241
242 return q;
243}
244#endif /* HAVE_MALLOC_HOOKS */