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