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