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
add_alloc(char * type,void * addr,size_t size,const char * file,int line)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
drop_alloc(const char * type,void * addr,const char * file,int line)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 *
my_malloc(size_t size,const char * file,int line)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 *
my_realloc(void * addr,size_t size,const char * file,int line)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
my_free(void * addr,const char * file,int line)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 *
my_strdup(const char * straddr,const char * file,int line)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
my_sethostent(int stay,const char * file,int line)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
my_endhostent(const char * file,int line)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 *
my_setnetconfig(const char * file,int line)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
my_endnetconfig(void * nconf,const char * file,int line)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 *
my_setnetpath(const char * file,int line)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
my_endnetpath(void * npath,const char * file,int line)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
my_netdir_getbyname(struct netconfig * tp,struct nd_hostserv * serv,struct nd_addrlist ** addrs,const char * file,int line)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
my_netdir_free(void * ptr,int type,const char * file,int line)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 *
my_getipnodebyname(const char * name,int af,int flags,int * error_num,char * file,int line)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
my_freehostent(struct hostent * hent,char * file,int line)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 *
my_getnetconfigent(char * netid,char * file,int line)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
my_freenetconfigent(struct netconfig * netp,char * file,int line)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 *
my__rpc_setconf(char * nettype,char * file,int line)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
my__rpc_endconf(void * vhandle,char * file,int line)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
_flush_caches()359 _flush_caches()
360 {
361 }
362 #pragma weak flush_caches = _flush_caches
363
364 void
check_leaks(char * filename)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