]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/util.c
3 * $Id: util.c,v 1.77 2001/01/12 00:37:13 wessels Exp $
6 * AUTHOR: Harvest Derived
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
56 #include <gnumalloc.h>
57 #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
73 static void default_failure_notify(const char *);
75 void (*failure_notify
) (const char *) = default_failure_notify
;
78 #if !defined(__CYGWIN__)
81 #define sys_nerr _sys_nerr
87 static FILE *tracefp
= NULL
;
90 log_trace_init(char *fn
)
92 tracefp
= fopen(fn
, "a+");
94 perror("log_trace_init");
108 #if XMALLOC_STATISTICS
109 #define DBG_MAXSIZE (1024*1024)
110 #define DBG_SPLIT (256) /* mallocs below this value are tracked with DBG_GRAIN_SM precision instead of DBG_GRAIN */
111 #define DBG_GRAIN (16)
112 #define DBG_GRAIN_SM (4)
113 #define DBG_OFFSET (DBG_SPLIT/DBG_GRAIN_SM - DBG_SPLIT/DBG_GRAIN )
114 #define DBG_MAXINDEX (DBG_MAXSIZE/DBG_GRAIN + DBG_OFFSET)
115 // #define DBG_INDEX(sz) (sz<DBG_MAXSIZE?(sz+DBG_GRAIN-1)/DBG_GRAIN:DBG_MAXINDEX)
116 static int malloc_sizes
[DBG_MAXINDEX
+ 1];
117 static int malloc_histo
[DBG_MAXINDEX
+ 1];
118 static int dbg_stat_init
= 0;
123 if (sz
>= DBG_MAXSIZE
)
127 return (sz
+ DBG_GRAIN_SM
- 1) / DBG_GRAIN_SM
;
129 return (sz
+ DBG_GRAIN
- 1) / DBG_GRAIN
+ DBG_OFFSET
;
136 for (i
= 0; i
<= DBG_MAXINDEX
; i
++)
137 malloc_sizes
[i
] = malloc_histo
[i
] = 0;
146 return malloc_sizes
[DBG_INDEX(sz
)] += 1;
150 malloc_statistics(void (*func
) (int, int, int, void *), void *data
)
153 for (i
= 0; i
<= DBG_SPLIT
; i
+= DBG_GRAIN_SM
)
154 func(i
, malloc_sizes
[DBG_INDEX(i
)], malloc_histo
[DBG_INDEX(i
)], data
);
156 for (i
= i
; i
<= DBG_MAXSIZE
; i
+= DBG_GRAIN
)
157 func(i
, malloc_sizes
[DBG_INDEX(i
)], malloc_histo
[DBG_INDEX(i
)], data
);
158 xmemcpy(&malloc_histo
, &malloc_sizes
, sizeof(malloc_sizes
));
160 #endif /* XMALLOC_STATISTICS */
165 char *xmalloc_file
= "";
166 int xmalloc_line
= 0;
167 char *xmalloc_func
= "";
168 static int xmalloc_count
= 0;
169 int xmalloc_trace
= 0; /* Enable with -m option */
170 size_t xmalloc_total
= 0;
180 #define DBG_ARRY_SZ (1<<11)
181 #define DBG_ARRY_BKTS (1<<8)
182 static void *(*malloc_ptrs
)[DBG_ARRY_SZ
];
183 static int malloc_size
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
185 static char *malloc_file
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
186 static short malloc_line
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
187 static int malloc_count
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
189 static int dbg_initd
= 0;
191 #define DBG_HASH_BUCKET(ptr) (((((int)ptr)>>4)+(((int)ptr)>>12)+(((int)ptr)>>20))&0xFF)
197 /* calloc the ptrs so that we don't see them when hunting lost memory */
198 malloc_ptrs
= calloc(DBG_ARRY_BKTS
, sizeof(*malloc_ptrs
));
199 for (B
= 0; B
< DBG_ARRY_BKTS
; B
++) {
200 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
201 malloc_ptrs
[B
][I
] = NULL
;
202 malloc_size
[B
][I
] = 0;
204 malloc_file
[B
][I
] = NULL
;
205 malloc_line
[B
][I
] = 0;
206 malloc_count
[B
][I
] = 0;
217 B
= DBG_HASH_BUCKET(s
);
218 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
219 if (malloc_ptrs
[B
][I
] != s
)
221 malloc_ptrs
[B
][I
] = NULL
;
222 malloc_size
[B
][I
] = 0;
224 malloc_file
[B
][I
] = NULL
;
225 malloc_line
[B
][I
] = 0;
226 malloc_count
[B
][I
] = 0;
230 if (I
== DBG_ARRY_SZ
) {
231 snprintf(msg
, 128, "xfree: ERROR: s=%p not found!", s
);
232 (*failure_notify
) (msg
);
237 check_malloc(void *p
, size_t sz
)
243 B
= DBG_HASH_BUCKET(p
);
244 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
245 if (!(P
= malloc_ptrs
[B
][I
]))
247 Q
= P
+ malloc_size
[B
][I
];
248 if (P
<= p
&& p
< Q
) {
249 snprintf(msg
, 128, "xmalloc: ERROR: p=%p falls in P=%p+%d",
250 p
, P
, malloc_size
[B
][I
]);
251 (*failure_notify
) (msg
);
254 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
255 if (malloc_ptrs
[B
][I
])
257 malloc_ptrs
[B
][I
] = p
;
258 malloc_size
[B
][I
] = (int) sz
;
260 malloc_file
[B
][I
] = xmalloc_file
;
261 malloc_line
[B
][I
] = xmalloc_line
;
262 malloc_count
[B
][I
] = xmalloc_count
;
266 if (I
== DBG_ARRY_SZ
)
267 (*failure_notify
) ("xmalloc: debug out of array space!");
271 #if XMALLOC_TRACE && !HAVE_MALLOCBLKSIZE
273 xmallocblksize(void *p
)
276 B
= DBG_HASH_BUCKET(p
);
277 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
278 if (malloc_ptrs
[B
][I
] == p
)
279 return malloc_size
[B
][I
];
287 malloc_file_name(void *p
)
290 B
= DBG_HASH_BUCKET(p
);
291 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
292 if (malloc_ptrs
[B
][I
] == p
)
293 return malloc_file
[B
][I
];
298 malloc_line_number(void *p
)
301 B
= DBG_HASH_BUCKET(p
);
302 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
303 if (malloc_ptrs
[B
][I
] == p
)
304 return malloc_line
[B
][I
];
309 malloc_number(void *p
)
312 B
= DBG_HASH_BUCKET(p
);
313 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
314 if (malloc_ptrs
[B
][I
] == p
)
315 return malloc_count
[B
][I
];
320 xmalloc_show_trace(void *p
, int sign
)
322 int statMemoryAccounted();
323 static size_t last_total
= 0, last_accounted
= 0, last_mallinfo
= 0;
324 size_t accounted
= statMemoryAccounted();
328 struct mallinfo mp
= mallinfo();
329 mi
= mp
.uordblks
+ mp
.usmblks
+ mp
.hblkhd
;
331 sz
= xmallocblksize(p
) * sign
;
333 xmalloc_count
+= sign
> 0;
335 fprintf(stderr
, "%c%8p size=%5d/%d acc=%5d/%d mallinfo=%5d/%d %s:%d %s",
336 sign
> 0 ? '+' : '-', p
,
337 (int) xmalloc_total
- last_total
, (int) xmalloc_total
,
338 (int) accounted
- last_accounted
, (int) accounted
,
339 (int) mi
- last_mallinfo
, (int) mi
,
340 xmalloc_file
, xmalloc_line
, xmalloc_func
);
342 fprintf(stderr
, " (%d %s:%d)\n", malloc_number(p
), malloc_file_name(p
), malloc_line_number(p
));
344 fprintf(stderr
, " %d\n", xmalloc_count
);
346 last_total
= xmalloc_total
;
347 last_accounted
= accounted
;
351 short malloc_refs
[DBG_ARRY_BKTS
][DBG_ARRY_SZ
];
352 #define XMALLOC_LEAK_ALIGN (4)
354 xmalloc_scan_region(void *start
, int size
, int depth
)
358 char *end
= ptr
+ size
- XMALLOC_LEAK_ALIGN
;
361 void *p
= *(void **) ptr
;
362 if (p
&& p
!= start
) {
363 B
= DBG_HASH_BUCKET(p
);
364 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
365 if (malloc_ptrs
[B
][I
] == p
) {
366 if (!malloc_refs
[B
][I
]++) {
367 /* A new reference */
368 fprintf(stderr
, "%*s%p %s:%d size %d allocation %d\n",
370 malloc_ptrs
[B
][I
], malloc_file
[B
][I
],
371 malloc_line
[B
][I
], malloc_size
[B
][I
],
373 sum
+= malloc_size
[B
][I
];
374 xmalloc_scan_region(malloc_ptrs
[B
][I
], malloc_size
[B
][I
], depth
+ 1);
376 if (sum
!= malloc_size
[B
][I
])
377 fprintf(stderr
, "=== %d bytes\n", sum
);
380 #if XMALLOC_SHOW_ALL_REFERENCES
382 /* We have already scanned this pointer... */
383 fprintf(stderr
, "%*s%p %s:%d size %d allocation %d ... (%d)\n",
385 malloc_ptrs
[B
][I
], malloc_file
[B
][I
],
386 malloc_line
[B
][I
], malloc_size
[B
][I
],
387 malloc_count
[B
][I
], malloc_refs
[B
][I
]);
393 ptr
+= XMALLOC_LEAK_ALIGN
;
398 xmalloc_find_leaks(void)
404 fprintf(stderr
, "----- Memory map ----\n");
405 xmalloc_scan_region(&_etext
, (void *) sbrk(0) - (void *) &_etext
, 0);
406 for (B
= 0; B
< DBG_ARRY_BKTS
; B
++) {
407 for (I
= 0; I
< DBG_ARRY_SZ
; I
++) {
408 if (malloc_ptrs
[B
][I
] && malloc_refs
[B
][I
] == 0) {
409 /* Found a leak... */
410 fprintf(stderr
, "Leak found: %p", malloc_ptrs
[B
][I
]);
411 fprintf(stderr
, " %s", malloc_file
[B
][I
]);
412 fprintf(stderr
, ":%d", malloc_line
[B
][I
]);
413 fprintf(stderr
, " size %d", malloc_size
[B
][I
]);
414 fprintf(stderr
, " allocation %d\n", malloc_count
[B
][I
]);
415 leak_sum
+= malloc_size
[B
][I
];
420 fprintf(stderr
, "Total leaked memory: %d\n", leak_sum
);
422 fprintf(stderr
, "No memory leaks detected\n");
424 fprintf(stderr
, "----------------------\n");
426 #endif /* XMALLOC_TRACE */
429 * xmalloc() - same as malloc(3). Used for portability.
430 * Never returns NULL; fatal on error.
440 if ((p
= malloc(sz
)) == NULL
) {
441 if (failure_notify
) {
442 snprintf(msg
, 128, "xmalloc: Unable to allocate %d bytes!\n",
444 (*failure_notify
) (msg
);
453 #if XMALLOC_STATISTICS
457 xmalloc_show_trace(p
, 1);
461 fprintf(tracefp
, "m:%d:%p\n", sz
, p
);
467 * xfree() - same as free(3). Will not call free(3) if s == NULL.
473 xmalloc_show_trace(s
, -1);
484 fprintf(tracefp
, "f:%p\n", s
);
488 /* xxfree() - like xfree(), but we already know s != NULL */
493 xmalloc_show_trace(s
, -1);
501 fprintf(tracefp
, "f:%p\n", s
);
506 * xrealloc() - same as realloc(3). Used for portability.
507 * Never returns NULL; fatal on error.
510 xrealloc(void *s
, size_t sz
)
515 xmalloc_show_trace(s
, -1);
524 if ((p
= realloc(s
, sz
)) == NULL
) {
525 if (failure_notify
) {
526 snprintf(msg
, 128, "xrealloc: Unable to reallocate %d bytes!\n",
528 (*failure_notify
) (msg
);
537 #if XMALLOC_STATISTICS
541 xmalloc_show_trace(p
, 1);
544 if (tracefp
) /* new ptr, old ptr, new size */
545 fprintf(tracefp
, "r:%p:%p:%d\n", p
, s
, sz
);
551 * xcalloc() - same as calloc(3). Used for portability.
552 * Never returns NULL; fatal on error.
555 xcalloc(int n
, size_t sz
)
563 if ((p
= calloc(n
, sz
)) == NULL
) {
564 if (failure_notify
) {
565 snprintf(msg
, 128, "xcalloc: Unable to allocate %d blocks of %d bytes!\n",
567 (*failure_notify
) (msg
);
574 check_malloc(p
, sz
* n
);
576 #if XMALLOC_STATISTICS
580 xmalloc_show_trace(p
, 1);
584 fprintf(tracefp
, "c:%d:%d:%p\n", n
, sz
, p
);
590 * xstrdup() - same as strdup(3). Used for portability.
591 * Never returns NULL; fatal on error.
594 xstrdup(const char *s
)
598 if (failure_notify
) {
599 (*failure_notify
) ("xstrdup: tried to dup a NULL pointer!\n");
601 fprintf(stderr
, "xstrdup: tried to dup a NULL pointer!\n");
605 /* copy string, including terminating character */
607 return memcpy(xmalloc(sz
), s
, sz
);
611 * xstrndup() - string dup with length limit.
614 xstrndup(const char *s
, size_t n
)
622 return xstrncpy(xmalloc(sz
), s
, sz
);
626 * xstrerror() - strerror() wrapper
631 static char xstrerror_buf
[BUFSIZ
];
632 if (errno
< 0 || errno
>= sys_nerr
)
633 snprintf(xstrerror_buf
, BUFSIZ
, "(%d) Unknown", errno
);
635 snprintf(xstrerror_buf
, BUFSIZ
, "(%d) %s", errno
, strerror(errno
));
636 return xstrerror_buf
;
641 * xbstrerror with argument for late notification */
646 static char xbstrerror_buf
[BUFSIZ
];
647 if (err
< 0 || err
>= sys_nerr
)
649 snprintf(xbstrerror_buf
, BUFSIZ
, "(%d) %s", err
, strerror(err
));
650 return xbstrerror_buf
;
659 *s
= tolower((unsigned char) *s
);
665 tvSubMsec(struct timeval t1
, struct timeval t2
)
667 return (t2
.tv_sec
- t1
.tv_sec
) * 1000 +
668 (t2
.tv_usec
- t1
.tv_usec
) / 1000;
672 tvSubUsec(struct timeval t1
, struct timeval t2
)
674 return (t2
.tv_sec
- t1
.tv_sec
) * 1000000 +
675 (t2
.tv_usec
- t1
.tv_usec
);
679 tvSubDsec(struct timeval t1
, struct timeval t2
)
681 return (double) (t2
.tv_sec
- t1
.tv_sec
) +
682 (double) (t2
.tv_usec
- t1
.tv_usec
) / 1000000.0;
686 * xstrncpy() - similar to strncpy(3) but terminates string
687 * always with '\0' if (n != 0 and dst != NULL),
688 * and doesn't do padding
691 xstrncpy(char *dst
, const char *src
, size_t n
)
697 while (--n
!= 0 && *src
!= '\0')
703 /* returns the number of leading white spaces in str; handy in skipping ws */
705 xcountws(const char *str
)
709 while (xisspace(*str
)) {
717 /* somewhat safer calculation of %s */
719 xpercent(double part
, double whole
)
721 return xdiv(100 * part
, whole
);
725 xpercentInt(double part
, double whole
)
728 return (int) rint(xpercent(part
, whole
));
730 /* SCO 3.2v4.2 doesn't have rint() -- mauri@mbp.ee */
731 return (int) floor(xpercent(part
, whole
) + 0.5);
735 /* somewhat safer division */
737 xdiv(double nom
, double denom
)
739 return (denom
!= 0.0) ? nom
/ denom
: -1.0;
742 /* integer to string */
746 static char buf
[24]; /* 2^64 = 18446744073709551616 */
747 snprintf(buf
, sizeof(buf
), "%d", num
);
751 /* A default failure notifier when the main program hasn't installed any */
753 default_failure_notify(const char *msg
)
755 write(2, msg
, strlen(msg
));