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