xref: /illumos-gate/usr/src/cmd/fs.d/autofs/debug_alloc.c (revision 12fb9219923f41528f673d4f31667db2c3f103ff)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1998,2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #ifdef	MALLOC_DEBUG
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <thread.h>
31 #include <synch.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <syslog.h>
35 #include <netdb.h>
36 #include <netdir.h>
37 #include <rpc/nettype.h>
38 
39 /*
40  * To use debugging facility, compile with * -DMALLOC_DEBUG.
41  * You can do this by setting the environment variable
42  * MALLOC_DEBUG to "-DMALLOC_DEBUG"
43  *
44  * To make automountd dump trace records (i.e. make it call check_leaks),
45  * run:
46  * 	make malloc_dump
47  */
48 
49 struct alloc_list
50 {
51 	char type[20];
52 	void *addr;
53 	int size;
54 	char file[80];
55 	int line;
56 	struct alloc_list *next;
57 };
58 
59 static struct alloc_list *halist = NULL;
60 static mutex_t alloc_list_lock = DEFAULTMUTEX;
61 
62 int
63 add_alloc(char *type, void *addr, size_t size, const char *file, int line)
64 {
65 	struct alloc_list *alist = NULL;
66 
67 	/* allocate the list item */
68 	alist = (struct alloc_list *)malloc(sizeof (*alist));
69 	if (alist == NULL) {
70 		syslog(LOG_ERR, "add_alloc: out of memory\n");
71 		return (-1);
72 	}
73 	strcpy(alist->type, type);
74 	alist->addr = addr;
75 	alist->size = size;
76 	strcpy(alist->file, file);
77 	alist->line = line;
78 
79 	/* add it to the head of the list */
80 	if (halist == NULL)
81 		alist->next = NULL;
82 	else
83 		alist->next = halist;
84 	halist = alist;
85 	return (0);
86 }
87 
88 int
89 drop_alloc(const char *type, void *addr, const char *file, int line)
90 {
91 	struct alloc_list *alist, *alist_prev;
92 
93 	alist = halist;
94 	while (alist != NULL) {
95 		if (addr == alist->addr) {
96 			if (alist == halist)
97 				halist = halist->next;
98 			else
99 				alist_prev->next = alist->next;
100 			free(alist);
101 			break;
102 		}
103 		alist_prev = alist;
104 		alist = alist->next;
105 	}
106 
107 	if (alist == NULL) {
108 		syslog(LOG_ERR, "*** POSSIBLE CORRUPTION ****\n");
109 		syslog(LOG_ERR, "\tduplicate free, type %s, at %p in %s/%d\n",
110 		    type, addr, file, line);
111 		return (-1);
112 	}
113 	return (0);
114 }
115 
116 void *
117 my_malloc(size_t size, const char *file, int line)
118 {
119 	void *addr;
120 
121 	addr = (void *)malloc(size);
122 	if (addr == NULL)
123 		return (NULL);
124 	mutex_lock(&alloc_list_lock);
125 	add_alloc("MALLOC", addr, size, file, line);
126 	mutex_unlock(&alloc_list_lock);
127 	return (addr);
128 }
129 
130 void *
131 my_realloc(void *addr, size_t size, const char *file, int line)
132 {
133 	void *ptr;
134 
135 	ptr = (void *)realloc(addr, size);
136 	if (ptr == NULL)
137 		return (NULL);
138 	mutex_lock(&alloc_list_lock);
139 	drop_alloc("MALLOC", addr, file, line);
140 	add_alloc("MALLOC", ptr, size, file, line);
141 	mutex_unlock(&alloc_list_lock);
142 
143 	return (ptr);
144 }
145 
146 void
147 my_free(void *addr, const char *file, int line)
148 {
149 	mutex_lock(&alloc_list_lock);
150 	drop_alloc("MALLOC", addr, file, line);
151 	mutex_unlock(&alloc_list_lock);
152 	free(addr);
153 }
154 
155 char *
156 my_strdup(const char *straddr, const char *file, int line)
157 {
158 	void *addr;
159 	size_t size;
160 
161 	addr = strdup(straddr);
162 	if (addr == NULL)
163 		return (NULL);
164 	size = strlen(straddr);
165 	mutex_lock(&alloc_list_lock);
166 	add_alloc("STRDUP", addr, size, file, line);
167 	mutex_unlock(&alloc_list_lock);
168 
169 	return ((char *)addr);
170 }
171 
172 int
173 my_sethostent(int stay, const char *file, int line)
174 {
175 	(void) sethostent(stay);
176 	mutex_lock(&alloc_list_lock);
177 	add_alloc("SETHOSTENT", NULL, 0, file, line);
178 	mutex_unlock(&alloc_list_lock);
179 	return (0);
180 }
181 
182 int
183 my_endhostent(const char *file, int line)
184 {
185 	int ret;
186 
187 	ret = endhostent();
188 	if (ret != 0)
189 		return (ret);
190 	mutex_lock(&alloc_list_lock);
191 	drop_alloc("SETHOSTENT", NULL, file, line);
192 	mutex_unlock(&alloc_list_lock);
193 	return (ret);
194 }
195 
196 void *
197 my_setnetconfig(const char *file, int line)
198 {
199 	void *nconf;
200 
201 	nconf = setnetconfig();
202 	if (nconf == NULL)
203 		return (NULL);
204 	mutex_lock(&alloc_list_lock);
205 	add_alloc("SETNETCONFIG", nconf, 0, file, line);
206 	mutex_unlock(&alloc_list_lock);
207 	return (nconf);
208 }
209 
210 int
211 my_endnetconfig(void *nconf, const char *file, int line)
212 {
213 	int res;
214 
215 	res = endnetconfig(nconf);
216 	if (res != 0)
217 		return (res);
218 	mutex_lock(&alloc_list_lock);
219 	drop_alloc("SETNETCONFIG", nconf, file, line);
220 	mutex_unlock(&alloc_list_lock);
221 	return (0);
222 }
223 
224 void *
225 my_setnetpath(const char *file, int line)
226 {
227 	void *npath;
228 
229 	npath = setnetpath();
230 	if (npath == NULL)
231 		return (NULL);
232 	mutex_lock(&alloc_list_lock);
233 	add_alloc("SETNETPATH", npath, 0, file, line);
234 	mutex_unlock(&alloc_list_lock);
235 	return (npath);
236 }
237 
238 int
239 my_endnetpath(void *npath, const char *file, int line)
240 {
241 	int res;
242 
243 	res = endnetpath(npath);
244 	if (res != 0)
245 		return (res);
246 	mutex_lock(&alloc_list_lock);
247 	drop_alloc("SETNETPATH", npath, file, line);
248 	mutex_unlock(&alloc_list_lock);
249 	return (0);
250 }
251 
252 int
253 my_netdir_getbyname(
254 	struct netconfig *tp,
255 	struct nd_hostserv *serv,
256 	struct nd_addrlist **addrs,
257 	const char *file,
258 	int line)
259 {
260 	int res;
261 
262 	res = netdir_getbyname(tp, serv, addrs);
263 	if (res != 0)
264 		return (res);
265 	mutex_lock(&alloc_list_lock);
266 	add_alloc("NETDIR_GETBYNAME", *addrs, 0, file, line);
267 	mutex_unlock(&alloc_list_lock);
268 	return (0);
269 }
270 
271 void
272 my_netdir_free(void *ptr, int type, const char *file, int line)
273 {
274 	netdir_free(ptr, type);
275 	mutex_lock(&alloc_list_lock);
276 	drop_alloc("NETDIR_GETBYNAME", ptr, file, line);
277 	mutex_unlock(&alloc_list_lock);
278 }
279 
280 struct hostent *
281 my_getipnodebyname(
282 	const char *name,
283 	int af,
284 	int flags,
285 	int *error_num,
286 	char *file,
287 	int line)
288 {
289 	struct hostent *res;
290 
291 	res = getipnodebyname(name, af, flags, error_num);
292 	if (res == NULL)
293 		return (NULL);
294 	mutex_lock(&alloc_list_lock);
295 	add_alloc("GETIPNODEBYNAME", res, 0, file, line);
296 	mutex_unlock(&alloc_list_lock);
297 	return (res);
298 }
299 
300 void
301 my_freehostent(struct hostent *hent, char *file, int line)
302 {
303 	freehostent(hent);
304 	mutex_lock(&alloc_list_lock);
305 	drop_alloc("GETIPNODEBYNAME", hent, file, line);
306 	mutex_unlock(&alloc_list_lock);
307 }
308 
309 struct netconfig *
310 my_getnetconfigent(char *netid, char *file, int line)
311 {
312 	struct netconfig *res;
313 
314 	res = getnetconfigent(netid);
315 	if (res == NULL)
316 		return (NULL);
317 	mutex_lock(&alloc_list_lock);
318 	add_alloc("GETNETCONFIGENT", res, 0, file, line);
319 	mutex_unlock(&alloc_list_lock);
320 	return (res);
321 }
322 
323 void
324 my_freenetconfigent(struct netconfig *netp, char *file, int line)
325 {
326 	freenetconfigent(netp);
327 	mutex_lock(&alloc_list_lock);
328 	drop_alloc("GETNETCONFIGENT", netp, file, line);
329 	mutex_unlock(&alloc_list_lock);
330 }
331 
332 void *
333 my__rpc_setconf(char *nettype, char *file, int line)
334 {
335 	void *res;
336 
337 	res = __rpc_setconf(nettype);
338 	if (res == NULL)
339 		return (NULL);
340 	mutex_lock(&alloc_list_lock);
341 	add_alloc("RPC_SETCONF", res, 0, file, line);
342 	mutex_unlock(&alloc_list_lock);
343 	return (res);
344 }
345 
346 void
347 my__rpc_endconf(void *vhandle, char *file, int line)
348 {
349 	__rpc_endconf(vhandle);
350 	mutex_lock(&alloc_list_lock);
351 	drop_alloc("RPC_SETCONF", vhandle, file, line);
352 	mutex_unlock(&alloc_list_lock);
353 }
354 
355 extern void flush_caches();
356 void
357 _flush_caches()
358 {
359 }
360 #pragma weak    flush_caches = _flush_caches
361 
362 void
363 check_leaks(char *filename)
364 {
365 	struct alloc_list *alist;
366 
367 	FILE *fp;
368 	fp = fopen(filename, "a");
369 	if (fp == NULL) {
370 		syslog(LOG_ERR, "check_leaks, could not open file: %s",
371 			filename);
372 		return;
373 	}
374 
375 	flush_caches();
376 	fprintf(fp, "*** POSSIBLE LEAKS ****\n");
377 	mutex_lock(&alloc_list_lock);
378 	alist = halist;
379 	while (alist != NULL) {
380 		fprintf(fp, "\t%s: %d bytes at %p in %s/%d\n",
381 			alist->type, alist->size, alist->addr,
382 			alist->file, alist->line);
383 		alist = alist->next;
384 	}
385 	mutex_unlock(&alloc_list_lock);
386 
387 	(void) fclose(fp);
388 }
389 #else
390 /*
391  * To prevent a compiler warning.
392  */
393 static char filler;
394 #endif
395