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