]>
Commit | Line | Data |
---|---|---|
be335c22 | 1 | |
30a4f2a8 | 2 | /* |
e4755e29 | 3 | * $Id: util.c,v 1.95 2007/04/06 12:15:51 serassio Exp $ |
30a4f2a8 | 4 | * |
5 | * DEBUG: | |
6 | * AUTHOR: Harvest Derived | |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
30a4f2a8 | 10 | * |
2b6662ba | 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. | |
30a4f2a8 | 19 | * |
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. | |
24 | * | |
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. | |
29 | * | |
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 | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
30a4f2a8 | 34 | */ |
7fc9f088 | 35 | |
e25c139f | 36 | #define _etext etext |
0d94e9fe | 37 | |
30a4f2a8 | 38 | #include "config.h" |
88bfe092 | 39 | #include "profiling.h" |
30a4f2a8 | 40 | |
41 | #if HAVE_STDIO_H | |
090089c4 | 42 | #include <stdio.h> |
30a4f2a8 | 43 | #endif |
44 | #if HAVE_STDLIB_H | |
090089c4 | 45 | #include <stdlib.h> |
30a4f2a8 | 46 | #endif |
47 | #if HAVE_STRING_H | |
090089c4 | 48 | #include <string.h> |
30a4f2a8 | 49 | #endif |
673d7a4d | 50 | #if HAVE_CTYPE_H |
51 | #include <ctype.h> | |
52 | #endif | |
30a4f2a8 | 53 | #if HAVE_UNISTD_H |
090089c4 | 54 | #include <unistd.h> |
30a4f2a8 | 55 | #endif |
88738790 | 56 | #if HAVE_GNUMALLLOC_H |
57 | #include <gnumalloc.h> | |
482aa790 | 58 | #elif HAVE_MALLOC_H |
090089c4 | 59 | #include <malloc.h> |
983061ed | 60 | #endif |
30a4f2a8 | 61 | #if HAVE_ERRNO_H |
090089c4 | 62 | #include <errno.h> |
30a4f2a8 | 63 | #endif |
02922e76 | 64 | #if HAVE_MATH_H |
65 | #include <math.h> | |
66 | #endif | |
c68e9c6b | 67 | #if HAVE_ASSERT_H |
68 | #include <assert.h> | |
69 | #endif | |
090089c4 | 70 | |
473471f2 | 71 | #include "util.h" |
5e2e108b | 72 | #include "snprintf.h" |
30a4f2a8 | 73 | |
5ac23588 | 74 | static void default_failure_notify(const char *); |
75 | ||
76 | void (*failure_notify) (const char *) = default_failure_notify; | |
090089c4 | 77 | static char msg[128]; |
78 | ||
36a97e19 | 79 | #if MEM_GEN_TRACE |
80 | ||
3213655a | 81 | static FILE *tracefp = NULL; |
36a97e19 | 82 | |
83 | void | |
84 | log_trace_init(char *fn) | |
85 | { | |
3213655a | 86 | tracefp = fopen(fn, "a+"); |
e45d4fb5 | 87 | |
3213655a | 88 | if (!tracefp) { |
e45d4fb5 | 89 | perror("log_trace_init"); |
90 | exit(1); | |
3213655a | 91 | } |
36a97e19 | 92 | } |
93 | ||
94 | void | |
95 | log_trace_done() | |
96 | { | |
3213655a | 97 | fclose(tracefp); |
98 | tracefp = NULL; | |
36a97e19 | 99 | } |
100 | ||
101 | #endif | |
102 | ||
30a4f2a8 | 103 | #if XMALLOC_STATISTICS |
104 | #define DBG_MAXSIZE (1024*1024) | |
58cd5bbd | 105 | #define DBG_SPLIT (256) /* mallocs below this value are tracked with DBG_GRAIN_SM precision instead of DBG_GRAIN */ |
30a4f2a8 | 106 | #define DBG_GRAIN (16) |
58cd5bbd | 107 | #define DBG_GRAIN_SM (4) |
108 | #define DBG_OFFSET (DBG_SPLIT/DBG_GRAIN_SM - DBG_SPLIT/DBG_GRAIN ) | |
109 | #define DBG_MAXINDEX (DBG_MAXSIZE/DBG_GRAIN + DBG_OFFSET) | |
110 | // #define DBG_INDEX(sz) (sz<DBG_MAXSIZE?(sz+DBG_GRAIN-1)/DBG_GRAIN:DBG_MAXINDEX) | |
30a4f2a8 | 111 | static int malloc_sizes[DBG_MAXINDEX + 1]; |
58cd5bbd | 112 | static int malloc_histo[DBG_MAXINDEX + 1]; |
30a4f2a8 | 113 | static int dbg_stat_init = 0; |
114 | ||
58cd5bbd | 115 | static int |
116 | DBG_INDEX(int sz) | |
117 | { | |
118 | if (sz >= DBG_MAXSIZE) | |
e45d4fb5 | 119 | return DBG_MAXINDEX; |
58cd5bbd | 120 | |
121 | if (sz <= DBG_SPLIT) | |
e45d4fb5 | 122 | return (sz + DBG_GRAIN_SM - 1) / DBG_GRAIN_SM; |
58cd5bbd | 123 | |
468ae12b | 124 | return (sz + DBG_GRAIN - 1) / DBG_GRAIN + DBG_OFFSET; |
58cd5bbd | 125 | } |
36a97e19 | 126 | |
b8d8561b | 127 | static void |
0673c0ba | 128 | stat_init(void) |
30a4f2a8 | 129 | { |
130 | int i; | |
e45d4fb5 | 131 | |
30a4f2a8 | 132 | for (i = 0; i <= DBG_MAXINDEX; i++) |
e45d4fb5 | 133 | malloc_sizes[i] = malloc_histo[i] = 0; |
134 | ||
30a4f2a8 | 135 | dbg_stat_init = 1; |
136 | } | |
137 | ||
b8d8561b | 138 | static int |
139 | malloc_stat(int sz) | |
30a4f2a8 | 140 | { |
141 | if (!dbg_stat_init) | |
e45d4fb5 | 142 | stat_init(); |
143 | ||
30a4f2a8 | 144 | return malloc_sizes[DBG_INDEX(sz)] += 1; |
145 | } | |
146 | ||
b8d8561b | 147 | void |
58cd5bbd | 148 | malloc_statistics(void (*func) (int, int, int, void *), void *data) |
30a4f2a8 | 149 | { |
150 | int i; | |
e45d4fb5 | 151 | |
58cd5bbd | 152 | for (i = 0; i <= DBG_SPLIT; i += DBG_GRAIN_SM) |
e45d4fb5 | 153 | func(i, malloc_sizes[DBG_INDEX(i)], malloc_histo[DBG_INDEX(i)], data); |
154 | ||
58cd5bbd | 155 | i -= DBG_GRAIN_SM; |
e45d4fb5 | 156 | |
58cd5bbd | 157 | for (i = i; i <= DBG_MAXSIZE; i += DBG_GRAIN) |
e45d4fb5 | 158 | func(i, malloc_sizes[DBG_INDEX(i)], malloc_histo[DBG_INDEX(i)], data); |
159 | ||
58cd5bbd | 160 | xmemcpy(&malloc_histo, &malloc_sizes, sizeof(malloc_sizes)); |
30a4f2a8 | 161 | } |
e45d4fb5 | 162 | |
30a4f2a8 | 163 | #endif /* XMALLOC_STATISTICS */ |
164 | ||
090089c4 | 165 | |
45e93040 | 166 | |
59272939 | 167 | #if XMALLOC_TRACE |
33ab18e8 | 168 | char *xmalloc_file = ""; |
169 | int xmalloc_line = 0; | |
170 | char *xmalloc_func = ""; | |
171 | static int xmalloc_count = 0; | |
172 | int xmalloc_trace = 0; /* Enable with -m option */ | |
173 | size_t xmalloc_total = 0; | |
59272939 | 174 | #undef xmalloc |
175 | #undef xfree | |
176 | #undef xxfree | |
177 | #undef xrealloc | |
178 | #undef xcalloc | |
179 | #undef xstrdup | |
180 | #endif | |
181 | ||
1d012b4c | 182 | #if XMALLOC_DEBUG |
8eb042dc | 183 | #define DBG_ARRY_SZ (1<<11) |
68b468e5 | 184 | #define DBG_ARRY_BKTS (1<<8) |
33ab18e8 | 185 | static void *(*malloc_ptrs)[DBG_ARRY_SZ]; |
8c6551ac | 186 | static int malloc_size[DBG_ARRY_BKTS][DBG_ARRY_SZ]; |
59272939 | 187 | #if XMALLOC_TRACE |
33ab18e8 | 188 | static char *malloc_file[DBG_ARRY_BKTS][DBG_ARRY_SZ]; |
189 | static short malloc_line[DBG_ARRY_BKTS][DBG_ARRY_SZ]; | |
59272939 | 190 | static int malloc_count[DBG_ARRY_BKTS][DBG_ARRY_SZ]; |
191 | #endif | |
45e93040 | 192 | static int dbg_initd = 0; |
45e93040 | 193 | |
26a7dee4 | 194 | #define DBG_HASH_BUCKET(ptr) (((((int)ptr)>>4)+(((int)ptr)>>12)+(((int)ptr)>>20))&0xFF) |
195 | ||
b8d8561b | 196 | static void |
0673c0ba | 197 | check_init(void) |
45e93040 | 198 | { |
33ab18e8 | 199 | int B = 0, I = 0; |
200 | /* calloc the ptrs so that we don't see them when hunting lost memory */ | |
201 | malloc_ptrs = calloc(DBG_ARRY_BKTS, sizeof(*malloc_ptrs)); | |
e45d4fb5 | 202 | |
68b468e5 | 203 | for (B = 0; B < DBG_ARRY_BKTS; B++) { |
e45d4fb5 | 204 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
205 | malloc_ptrs[B][I] = NULL; | |
206 | malloc_size[B][I] = 0; | |
59272939 | 207 | #if XMALLOC_TRACE |
e45d4fb5 | 208 | |
209 | malloc_file[B][I] = NULL; | |
210 | malloc_line[B][I] = 0; | |
211 | malloc_count[B][I] = 0; | |
59272939 | 212 | #endif |
e45d4fb5 | 213 | |
214 | } | |
45e93040 | 215 | } |
e45d4fb5 | 216 | |
45e93040 | 217 | dbg_initd = 1; |
218 | } | |
219 | ||
b8d8561b | 220 | static void |
221 | check_free(void *s) | |
45e93040 | 222 | { |
33ab18e8 | 223 | int B, I; |
26a7dee4 | 224 | B = DBG_HASH_BUCKET(s); |
e45d4fb5 | 225 | |
45e93040 | 226 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
e45d4fb5 | 227 | if (malloc_ptrs[B][I] != s) |
228 | continue; | |
229 | ||
230 | malloc_ptrs[B][I] = NULL; | |
231 | ||
232 | malloc_size[B][I] = 0; | |
233 | ||
59272939 | 234 | #if XMALLOC_TRACE |
e45d4fb5 | 235 | |
236 | malloc_file[B][I] = NULL; | |
237 | ||
238 | malloc_line[B][I] = 0; | |
239 | ||
240 | malloc_count[B][I] = 0; | |
241 | ||
59272939 | 242 | #endif |
e45d4fb5 | 243 | |
244 | break; | |
45e93040 | 245 | } |
e45d4fb5 | 246 | |
45e93040 | 247 | if (I == DBG_ARRY_SZ) { |
e45d4fb5 | 248 | snprintf(msg, 128, "xfree: ERROR: s=%p not found!", s); |
249 | (*failure_notify) (msg); | |
45e93040 | 250 | } |
251 | } | |
252 | ||
b8d8561b | 253 | static void |
254 | check_malloc(void *p, size_t sz) | |
45e93040 | 255 | { |
33ab18e8 | 256 | void *P, *Q; |
257 | int B, I; | |
e45d4fb5 | 258 | |
45e93040 | 259 | if (!dbg_initd) |
e45d4fb5 | 260 | check_init(); |
261 | ||
6f7e508b | 262 | B = DBG_HASH_BUCKET(p); |
e45d4fb5 | 263 | |
45e93040 | 264 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
e45d4fb5 | 265 | if (!(P = malloc_ptrs[B][I])) |
266 | continue; | |
267 | ||
268 | Q = P + malloc_size[B][I]; | |
269 | ||
270 | if (P <= p && p < Q) { | |
271 | snprintf(msg, 128, "xmalloc: ERROR: p=%p falls in P=%p+%d", | |
272 | p, P, malloc_size[B][I]); | |
273 | (*failure_notify) (msg); | |
274 | } | |
45e93040 | 275 | } |
e45d4fb5 | 276 | |
45e93040 | 277 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
e45d4fb5 | 278 | if (malloc_ptrs[B][I]) |
279 | continue; | |
280 | ||
281 | malloc_ptrs[B][I] = p; | |
282 | ||
283 | malloc_size[B][I] = (int) sz; | |
284 | ||
59272939 | 285 | #if XMALLOC_TRACE |
e45d4fb5 | 286 | |
287 | malloc_file[B][I] = xmalloc_file; | |
288 | ||
289 | malloc_line[B][I] = xmalloc_line; | |
290 | ||
291 | malloc_count[B][I] = xmalloc_count; | |
292 | ||
59272939 | 293 | #endif |
e45d4fb5 | 294 | |
295 | break; | |
45e93040 | 296 | } |
e45d4fb5 | 297 | |
45e93040 | 298 | if (I == DBG_ARRY_SZ) |
e45d4fb5 | 299 | (*failure_notify) ("xmalloc: debug out of array space!"); |
45e93040 | 300 | } |
e45d4fb5 | 301 | |
45e93040 | 302 | #endif |
303 | ||
59272939 | 304 | #if XMALLOC_TRACE && !HAVE_MALLOCBLKSIZE |
5e5cb0fc | 305 | size_t |
306 | xmallocblksize(void *p) | |
7fc9f088 | 307 | { |
33ab18e8 | 308 | int B, I; |
6f7e508b | 309 | B = DBG_HASH_BUCKET(p); |
e45d4fb5 | 310 | |
7fc9f088 | 311 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
e45d4fb5 | 312 | if (malloc_ptrs[B][I] == p) |
313 | return malloc_size[B][I]; | |
7fc9f088 | 314 | } |
e45d4fb5 | 315 | |
7fc9f088 | 316 | return 0; |
317 | } | |
e45d4fb5 | 318 | |
7fc9f088 | 319 | #endif |
320 | ||
59272939 | 321 | #ifdef XMALLOC_TRACE |
322 | static char * | |
323 | malloc_file_name(void *p) | |
324 | { | |
33ab18e8 | 325 | int B, I; |
6f7e508b | 326 | B = DBG_HASH_BUCKET(p); |
e45d4fb5 | 327 | |
59272939 | 328 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
e45d4fb5 | 329 | if (malloc_ptrs[B][I] == p) |
330 | return malloc_file[B][I]; | |
59272939 | 331 | } |
e45d4fb5 | 332 | |
59272939 | 333 | return 0; |
334 | } | |
e45d4fb5 | 335 | |
59272939 | 336 | int |
337 | malloc_line_number(void *p) | |
338 | { | |
33ab18e8 | 339 | int B, I; |
6f7e508b | 340 | B = DBG_HASH_BUCKET(p); |
e45d4fb5 | 341 | |
59272939 | 342 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
e45d4fb5 | 343 | if (malloc_ptrs[B][I] == p) |
344 | return malloc_line[B][I]; | |
59272939 | 345 | } |
e45d4fb5 | 346 | |
59272939 | 347 | return 0; |
348 | } | |
e45d4fb5 | 349 | |
59272939 | 350 | int |
351 | malloc_number(void *p) | |
352 | { | |
33ab18e8 | 353 | int B, I; |
6f7e508b | 354 | B = DBG_HASH_BUCKET(p); |
e45d4fb5 | 355 | |
59272939 | 356 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
e45d4fb5 | 357 | if (malloc_ptrs[B][I] == p) |
358 | return malloc_count[B][I]; | |
59272939 | 359 | } |
e45d4fb5 | 360 | |
59272939 | 361 | return 0; |
362 | } | |
e45d4fb5 | 363 | |
b8d8561b | 364 | static void |
33ab18e8 | 365 | xmalloc_show_trace(void *p, int sign) |
68b468e5 | 366 | { |
e5f4e1b0 | 367 | int statMemoryAccounted(); |
0e473d70 | 368 | static size_t last_total = 0, last_accounted = 0, last_mallinfo = 0; |
0e473d70 | 369 | size_t accounted = statMemoryAccounted(); |
5e5cb0fc | 370 | size_t mi = 0; |
7fc9f088 | 371 | size_t sz; |
5e5cb0fc | 372 | #if HAVE_MALLINFO |
e45d4fb5 | 373 | |
5e5cb0fc | 374 | struct mallinfo mp = mallinfo(); |
375 | mi = mp.uordblks + mp.usmblks + mp.hblkhd; | |
376 | #endif | |
e45d4fb5 | 377 | |
5e5cb0fc | 378 | sz = xmallocblksize(p) * sign; |
33ab18e8 | 379 | xmalloc_total += sz; |
380 | xmalloc_count += sign > 0; | |
e45d4fb5 | 381 | |
33ab18e8 | 382 | if (xmalloc_trace) { |
e45d4fb5 | 383 | fprintf(stderr, "%c%8p size=%5d/%d acc=%5d/%d mallinfo=%5d/%d %s:%d %s", |
384 | sign > 0 ? '+' : '-', p, | |
385 | (int) xmalloc_total - last_total, (int) xmalloc_total, | |
386 | (int) accounted - last_accounted, (int) accounted, | |
387 | (int) mi - last_mallinfo, (int) mi, | |
388 | xmalloc_file, xmalloc_line, xmalloc_func); | |
389 | ||
390 | if (sign < 0) | |
391 | fprintf(stderr, " (%d %s:%d)\n", malloc_number(p), malloc_file_name(p), malloc_line_number(p)); | |
392 | else | |
393 | fprintf(stderr, " %d\n", xmalloc_count); | |
33ab18e8 | 394 | } |
e45d4fb5 | 395 | |
33ab18e8 | 396 | last_total = xmalloc_total; |
0e473d70 | 397 | last_accounted = accounted; |
398 | last_mallinfo = mi; | |
68b468e5 | 399 | } |
7ce875eb | 400 | |
401 | short malloc_refs[DBG_ARRY_BKTS][DBG_ARRY_SZ]; | |
33ab18e8 | 402 | #define XMALLOC_LEAK_ALIGN (4) |
7ce875eb | 403 | static void |
404 | xmalloc_scan_region(void *start, int size, int depth) | |
33ab18e8 | 405 | { |
406 | int B, I; | |
407 | char *ptr = start; | |
408 | char *end = ptr + size - XMALLOC_LEAK_ALIGN; | |
7ce875eb | 409 | static int sum = 0; |
e45d4fb5 | 410 | |
33ab18e8 | 411 | while (ptr <= end) { |
e45d4fb5 | 412 | void *p = *(void **) ptr; |
413 | ||
414 | if (p && p != start) { | |
415 | B = DBG_HASH_BUCKET(p); | |
416 | ||
417 | for (I = 0; I < DBG_ARRY_SZ; I++) { | |
418 | if (malloc_ptrs[B][I] == p) { | |
419 | if (!malloc_refs[B][I]++) { | |
420 | /* A new reference */ | |
421 | fprintf(stderr, "%*s%p %s:%d size %d allocation %d\n", | |
422 | depth, "", | |
423 | malloc_ptrs[B][I], malloc_file[B][I], | |
424 | malloc_line[B][I], malloc_size[B][I], | |
425 | malloc_count[B][I]); | |
426 | sum += malloc_size[B][I]; | |
427 | xmalloc_scan_region(malloc_ptrs[B][I], malloc_size[B][I], depth + 1); | |
428 | ||
429 | if (depth == 0) { | |
430 | if (sum != malloc_size[B][I]) | |
431 | fprintf(stderr, "=== %d bytes\n", sum); | |
432 | ||
433 | sum = 0; | |
434 | } | |
435 | ||
7ce875eb | 436 | #if XMALLOC_SHOW_ALL_REFERENCES |
e45d4fb5 | 437 | |
438 | } else { | |
439 | /* We have already scanned this pointer... */ | |
440 | fprintf(stderr, "%*s%p %s:%d size %d allocation %d ... (%d)\n", | |
441 | depth * 2, "", | |
442 | malloc_ptrs[B][I], malloc_file[B][I], | |
443 | malloc_line[B][I], malloc_size[B][I], | |
444 | malloc_count[B][I], malloc_refs[B][I]); | |
445 | #endif | |
446 | ||
447 | } | |
448 | } | |
449 | } | |
450 | } | |
451 | ||
452 | ptr += XMALLOC_LEAK_ALIGN; | |
33ab18e8 | 453 | } |
33ab18e8 | 454 | } |
7ce875eb | 455 | |
33ab18e8 | 456 | void |
457 | xmalloc_find_leaks(void) | |
458 | { | |
459 | int B, I; | |
33ab18e8 | 460 | int leak_sum = 0; |
c8f322d5 | 461 | |
7ce875eb | 462 | extern void _etext; |
463 | fprintf(stderr, "----- Memory map ----\n"); | |
464 | xmalloc_scan_region(&_etext, (void *) sbrk(0) - (void *) &_etext, 0); | |
e45d4fb5 | 465 | |
33ab18e8 | 466 | for (B = 0; B < DBG_ARRY_BKTS; B++) { |
e45d4fb5 | 467 | for (I = 0; I < DBG_ARRY_SZ; I++) { |
468 | if (malloc_ptrs[B][I] && malloc_refs[B][I] == 0) { | |
469 | /* Found a leak... */ | |
470 | fprintf(stderr, "Leak found: %p", malloc_ptrs[B][I]); | |
471 | fprintf(stderr, " %s", malloc_file[B][I]); | |
472 | fprintf(stderr, ":%d", malloc_line[B][I]); | |
473 | fprintf(stderr, " size %d", malloc_size[B][I]); | |
474 | fprintf(stderr, " allocation %d\n", malloc_count[B][I]); | |
475 | leak_sum += malloc_size[B][I]; | |
476 | } | |
477 | } | |
33ab18e8 | 478 | } |
e45d4fb5 | 479 | |
33ab18e8 | 480 | if (leak_sum) { |
e45d4fb5 | 481 | fprintf(stderr, "Total leaked memory: %d\n", leak_sum); |
33ab18e8 | 482 | } else { |
e45d4fb5 | 483 | fprintf(stderr, "No memory leaks detected\n"); |
33ab18e8 | 484 | } |
e45d4fb5 | 485 | |
33ab18e8 | 486 | fprintf(stderr, "----------------------\n"); |
487 | } | |
e45d4fb5 | 488 | |
59272939 | 489 | #endif /* XMALLOC_TRACE */ |
68b468e5 | 490 | |
090089c4 | 491 | /* |
492 | * xmalloc() - same as malloc(3). Used for portability. | |
493 | * Never returns NULL; fatal on error. | |
494 | */ | |
b8d8561b | 495 | void * |
496 | xmalloc(size_t sz) | |
090089c4 | 497 | { |
c5a615e3 | 498 | void *p; |
090089c4 | 499 | |
88bfe092 | 500 | PROF_start(xmalloc); |
e45d4fb5 | 501 | |
090089c4 | 502 | if (sz < 1) |
e45d4fb5 | 503 | sz = 1; |
36a97e19 | 504 | |
88bfe092 | 505 | PROF_start(malloc); |
e45d4fb5 | 506 | |
88bfe092 | 507 | p = malloc(sz); |
e45d4fb5 | 508 | |
88bfe092 | 509 | PROF_stop(malloc); |
e45d4fb5 | 510 | |
88bfe092 | 511 | if (p == NULL) { |
e45d4fb5 | 512 | if (failure_notify) { |
513 | snprintf(msg, 128, "xmalloc: Unable to allocate %d bytes!\n", | |
514 | (int) sz); | |
515 | (*failure_notify) (msg); | |
516 | } else { | |
517 | perror("malloc"); | |
518 | } | |
519 | ||
520 | exit(1); | |
090089c4 | 521 | } |
e45d4fb5 | 522 | |
1d012b4c | 523 | #if XMALLOC_DEBUG |
45e93040 | 524 | check_malloc(p, sz); |
e45d4fb5 | 525 | |
30a4f2a8 | 526 | #endif |
527 | #if XMALLOC_STATISTICS | |
e45d4fb5 | 528 | |
30a4f2a8 | 529 | malloc_stat(sz); |
e45d4fb5 | 530 | |
68b468e5 | 531 | #endif |
59272939 | 532 | #if XMALLOC_TRACE |
e45d4fb5 | 533 | |
33ab18e8 | 534 | xmalloc_show_trace(p, 1); |
e45d4fb5 | 535 | |
36a97e19 | 536 | #endif |
537 | #if MEM_GEN_TRACE | |
e45d4fb5 | 538 | |
3213655a | 539 | if (tracefp) |
e45d4fb5 | 540 | fprintf(tracefp, "m:%d:%p\n", sz, p); |
541 | ||
45e93040 | 542 | #endif |
e45d4fb5 | 543 | |
88bfe092 | 544 | PROF_stop(xmalloc); |
e45d4fb5 | 545 | |
090089c4 | 546 | return (p); |
547 | } | |
548 | ||
549 | /* | |
550 | * xfree() - same as free(3). Will not call free(3) if s == NULL. | |
551 | */ | |
b8d8561b | 552 | void |
553 | xfree(void *s) | |
090089c4 | 554 | { |
88bfe092 | 555 | PROF_start(xfree); |
59272939 | 556 | #if XMALLOC_TRACE |
e45d4fb5 | 557 | |
33ab18e8 | 558 | xmalloc_show_trace(s, -1); |
7fc9f088 | 559 | #endif |
36a97e19 | 560 | |
7fc9f088 | 561 | #if XMALLOC_DEBUG |
e45d4fb5 | 562 | |
8eb042dc | 563 | if (s != NULL) |
e45d4fb5 | 564 | check_free(s); |
565 | ||
45e93040 | 566 | #endif |
e45d4fb5 | 567 | |
45e93040 | 568 | if (s != NULL) |
e45d4fb5 | 569 | free(s); |
570 | ||
36a97e19 | 571 | #if MEM_GEN_TRACE |
e45d4fb5 | 572 | |
3213655a | 573 | if (tracefp && s) |
e45d4fb5 | 574 | fprintf(tracefp, "f:%p\n", s); |
575 | ||
36a97e19 | 576 | #endif |
e45d4fb5 | 577 | |
88bfe092 | 578 | PROF_stop(xfree); |
45e93040 | 579 | } |
580 | ||
581 | /* xxfree() - like xfree(), but we already know s != NULL */ | |
b8d8561b | 582 | void |
e7106f62 | 583 | xxfree(const void *s_const) |
45e93040 | 584 | { |
db17c597 | 585 | void *s = (void *) s_const; |
88bfe092 | 586 | PROF_start(xxfree); |
59272939 | 587 | #if XMALLOC_TRACE |
e45d4fb5 | 588 | |
33ab18e8 | 589 | xmalloc_show_trace(s, -1); |
7fc9f088 | 590 | #endif |
591 | #if XMALLOC_DEBUG | |
e45d4fb5 | 592 | |
7fc9f088 | 593 | check_free(s); |
45e93040 | 594 | #endif |
e45d4fb5 | 595 | |
45e93040 | 596 | free(s); |
36a97e19 | 597 | #if MEM_GEN_TRACE |
e45d4fb5 | 598 | |
3213655a | 599 | if (tracefp && s) |
e45d4fb5 | 600 | fprintf(tracefp, "f:%p\n", s); |
601 | ||
36a97e19 | 602 | #endif |
e45d4fb5 | 603 | |
88bfe092 | 604 | PROF_stop(xxfree); |
090089c4 | 605 | } |
606 | ||
607 | /* | |
608 | * xrealloc() - same as realloc(3). Used for portability. | |
609 | * Never returns NULL; fatal on error. | |
610 | */ | |
b8d8561b | 611 | void * |
612 | xrealloc(void *s, size_t sz) | |
090089c4 | 613 | { |
c5a615e3 | 614 | void *p; |
090089c4 | 615 | |
88bfe092 | 616 | PROF_start(xrealloc); |
59272939 | 617 | #if XMALLOC_TRACE |
e45d4fb5 | 618 | |
33ab18e8 | 619 | xmalloc_show_trace(s, -1); |
68b468e5 | 620 | #endif |
621 | ||
090089c4 | 622 | if (sz < 1) |
e45d4fb5 | 623 | sz = 1; |
624 | ||
3213655a | 625 | #if XMALLOC_DEBUG |
e45d4fb5 | 626 | |
3213655a | 627 | if (s != NULL) |
e45d4fb5 | 628 | check_free(s); |
629 | ||
3213655a | 630 | #endif |
e45d4fb5 | 631 | |
090089c4 | 632 | if ((p = realloc(s, sz)) == NULL) { |
e45d4fb5 | 633 | if (failure_notify) { |
634 | snprintf(msg, 128, "xrealloc: Unable to reallocate %d bytes!\n", | |
635 | (int) sz); | |
636 | (*failure_notify) (msg); | |
637 | } else { | |
638 | perror("realloc"); | |
639 | } | |
640 | ||
641 | exit(1); | |
090089c4 | 642 | } |
e45d4fb5 | 643 | |
1d012b4c | 644 | #if XMALLOC_DEBUG |
45e93040 | 645 | check_malloc(p, sz); |
e45d4fb5 | 646 | |
30a4f2a8 | 647 | #endif |
648 | #if XMALLOC_STATISTICS | |
e45d4fb5 | 649 | |
30a4f2a8 | 650 | malloc_stat(sz); |
e45d4fb5 | 651 | |
68b468e5 | 652 | #endif |
59272939 | 653 | #if XMALLOC_TRACE |
e45d4fb5 | 654 | |
33ab18e8 | 655 | xmalloc_show_trace(p, 1); |
e45d4fb5 | 656 | |
71a17702 | 657 | #endif |
658 | #if MEM_GEN_TRACE | |
e45d4fb5 | 659 | |
3213655a | 660 | if (tracefp) /* new ptr, old ptr, new size */ |
e45d4fb5 | 661 | fprintf(tracefp, "r:%p:%p:%d\n", p, s, sz); |
662 | ||
45e93040 | 663 | #endif |
e45d4fb5 | 664 | |
88bfe092 | 665 | PROF_stop(xrealloc); |
e45d4fb5 | 666 | |
090089c4 | 667 | return (p); |
668 | } | |
669 | ||
670 | /* | |
671 | * xcalloc() - same as calloc(3). Used for portability. | |
672 | * Never returns NULL; fatal on error. | |
673 | */ | |
b8d8561b | 674 | void * |
8a7e978a | 675 | xcalloc(size_t n, size_t sz) |
090089c4 | 676 | { |
c5a615e3 | 677 | void *p; |
090089c4 | 678 | |
88bfe092 | 679 | PROF_start(xcalloc); |
e45d4fb5 | 680 | |
090089c4 | 681 | if (n < 1) |
e45d4fb5 | 682 | n = 1; |
683 | ||
090089c4 | 684 | if (sz < 1) |
e45d4fb5 | 685 | sz = 1; |
686 | ||
88bfe092 | 687 | PROF_start(calloc); |
e45d4fb5 | 688 | |
88bfe092 | 689 | p = calloc(n, sz); |
e45d4fb5 | 690 | |
88bfe092 | 691 | PROF_stop(calloc); |
e45d4fb5 | 692 | |
88bfe092 | 693 | if (p == NULL) { |
e45d4fb5 | 694 | if (failure_notify) { |
695 | snprintf(msg, 128, "xcalloc: Unable to allocate %u blocks of %u bytes!\n", | |
696 | (unsigned int) n, (unsigned int) sz); | |
697 | (*failure_notify) (msg); | |
698 | } else { | |
699 | perror("xcalloc"); | |
700 | } | |
701 | ||
702 | exit(1); | |
090089c4 | 703 | } |
e45d4fb5 | 704 | |
1d012b4c | 705 | #if XMALLOC_DEBUG |
45e93040 | 706 | check_malloc(p, sz * n); |
e45d4fb5 | 707 | |
30a4f2a8 | 708 | #endif |
709 | #if XMALLOC_STATISTICS | |
e45d4fb5 | 710 | |
97e9fcb6 | 711 | malloc_stat(sz * n); |
e45d4fb5 | 712 | |
68b468e5 | 713 | #endif |
59272939 | 714 | #if XMALLOC_TRACE |
e45d4fb5 | 715 | |
33ab18e8 | 716 | xmalloc_show_trace(p, 1); |
e45d4fb5 | 717 | |
36a97e19 | 718 | #endif |
719 | #if MEM_GEN_TRACE | |
e45d4fb5 | 720 | |
3213655a | 721 | if (tracefp) |
e45d4fb5 | 722 | fprintf(tracefp, "c:%u:%u:%p\n", (unsigned int) n, (unsigned int) sz, p); |
723 | ||
45e93040 | 724 | #endif |
e45d4fb5 | 725 | |
88bfe092 | 726 | PROF_stop(xcalloc); |
e45d4fb5 | 727 | |
090089c4 | 728 | return (p); |
729 | } | |
730 | ||
731 | /* | |
732 | * xstrdup() - same as strdup(3). Used for portability. | |
733 | * Never returns NULL; fatal on error. | |
734 | */ | |
b8d8561b | 735 | char * |
0ee4272b | 736 | xstrdup(const char *s) |
090089c4 | 737 | { |
30a4f2a8 | 738 | size_t sz; |
88bfe092 | 739 | void *p; |
740 | PROF_start(xstrdup); | |
e45d4fb5 | 741 | |
090089c4 | 742 | if (s == NULL) { |
e45d4fb5 | 743 | if (failure_notify) { |
744 | (*failure_notify) ("xstrdup: tried to dup a NULL pointer!\n"); | |
745 | } else { | |
746 | fprintf(stderr, "xstrdup: tried to dup a NULL pointer!\n"); | |
747 | } | |
748 | ||
749 | exit(1); | |
090089c4 | 750 | } |
e45d4fb5 | 751 | |
c68e9c6b | 752 | /* copy string, including terminating character */ |
753 | sz = strlen(s) + 1; | |
e45d4fb5 | 754 | |
88bfe092 | 755 | p = memcpy(xmalloc(sz), s, sz); |
e45d4fb5 | 756 | |
88bfe092 | 757 | PROF_stop(xstrdup); |
e45d4fb5 | 758 | |
88bfe092 | 759 | return p; |
c68e9c6b | 760 | } |
761 | ||
762 | /* | |
763 | * xstrndup() - string dup with length limit. | |
764 | */ | |
765 | char * | |
766 | xstrndup(const char *s, size_t n) | |
767 | { | |
768 | size_t sz; | |
88bfe092 | 769 | void *p; |
770 | PROF_start(xstrndup); | |
137a13ea | 771 | assert(s != NULL); |
c68e9c6b | 772 | assert(n); |
3213655a | 773 | sz = strlen(s) + 1; |
e45d4fb5 | 774 | |
c68e9c6b | 775 | if (sz > n) |
e45d4fb5 | 776 | sz = n; |
777 | ||
88bfe092 | 778 | p = xstrncpy(xmalloc(sz), s, sz); |
e45d4fb5 | 779 | |
88bfe092 | 780 | PROF_stop(xstrndup); |
e45d4fb5 | 781 | |
88bfe092 | 782 | return p; |
090089c4 | 783 | } |
784 | ||
090089c4 | 785 | /* |
4d38fc7e | 786 | * xstrerror() - strerror() wrapper |
090089c4 | 787 | */ |
0ee4272b | 788 | const char * |
02e640fe | 789 | xstrerr(int error) |
090089c4 | 790 | { |
35570558 | 791 | static char xstrerror_buf[BUFSIZ]; |
e45d4fb5 | 792 | const char *errmsg; |
04b7f2e0 | 793 | |
e45d4fb5 | 794 | errmsg = strerror(error); |
795 | ||
796 | if (!errmsg || !*errmsg) | |
797 | errmsg = "Unknown error"; | |
798 | ||
799 | snprintf(xstrerror_buf, BUFSIZ, "(%d) %s", error, errmsg); | |
db17c597 | 800 | |
35570558 | 801 | return xstrerror_buf; |
090089c4 | 802 | } |
803 | ||
02e640fe | 804 | const char * |
805 | xstrerror(void) | |
806 | { | |
807 | return xstrerr(errno); | |
808 | } | |
809 | ||
b8d8561b | 810 | void |
811 | Tolower(char *q) | |
673d7a4d | 812 | { |
813 | char *s = q; | |
e45d4fb5 | 814 | |
673d7a4d | 815 | while (*s) { |
e4755e29 | 816 | *s = xtolower(*s); |
e45d4fb5 | 817 | s++; |
673d7a4d | 818 | } |
819 | } | |
9d90e665 | 820 | |
821 | int | |
e45d4fb5 | 822 | |
9d90e665 | 823 | tvSubMsec(struct timeval t1, struct timeval t2) |
824 | { | |
825 | return (t2.tv_sec - t1.tv_sec) * 1000 + | |
e45d4fb5 | 826 | (t2.tv_usec - t1.tv_usec) / 1000; |
9d90e665 | 827 | } |
d5aa0e3b | 828 | |
88738790 | 829 | int |
e45d4fb5 | 830 | |
88738790 | 831 | tvSubUsec(struct timeval t1, struct timeval t2) |
832 | { | |
833 | return (t2.tv_sec - t1.tv_sec) * 1000000 + | |
e45d4fb5 | 834 | (t2.tv_usec - t1.tv_usec); |
88738790 | 835 | } |
836 | ||
260e56a3 | 837 | double |
e45d4fb5 | 838 | |
260e56a3 | 839 | tvSubDsec(struct timeval t1, struct timeval t2) |
840 | { | |
841 | return (double) (t2.tv_sec - t1.tv_sec) + | |
e45d4fb5 | 842 | (double) (t2.tv_usec - t1.tv_usec) / 1000000.0; |
260e56a3 | 843 | } |
844 | ||
d5aa0e3b | 845 | /* |
846 | * xstrncpy() - similar to strncpy(3) but terminates string | |
cb69b4c7 | 847 | * always with '\0' if (n != 0 and dst != NULL), |
848 | * and doesn't do padding | |
d5aa0e3b | 849 | */ |
850 | char * | |
851 | xstrncpy(char *dst, const char *src, size_t n) | |
852 | { | |
c68e9c6b | 853 | char *r = dst; |
88bfe092 | 854 | PROF_start(xstrncpy); |
e45d4fb5 | 855 | |
cb69b4c7 | 856 | if (!n || !dst) |
e45d4fb5 | 857 | return dst; |
858 | ||
cb69b4c7 | 859 | if (src) |
e45d4fb5 | 860 | while (--n != 0 && *src != '\0') |
861 | *dst++ = *src++; | |
862 | ||
c1764328 | 863 | *dst = '\0'; |
e45d4fb5 | 864 | |
88bfe092 | 865 | PROF_stop(xstrncpy); |
e45d4fb5 | 866 | |
c68e9c6b | 867 | return r; |
d5aa0e3b | 868 | } |
cb69b4c7 | 869 | |
870 | /* returns the number of leading white spaces in str; handy in skipping ws */ | |
871 | size_t | |
872 | xcountws(const char *str) | |
873 | { | |
874 | size_t count = 0; | |
88bfe092 | 875 | PROF_start(xcountws); |
e45d4fb5 | 876 | |
cb69b4c7 | 877 | if (str) { |
e45d4fb5 | 878 | while (xisspace(*str)) { |
879 | str++; | |
880 | count++; | |
881 | } | |
cb69b4c7 | 882 | } |
e45d4fb5 | 883 | |
88bfe092 | 884 | PROF_stop(xcountws); |
cb69b4c7 | 885 | return count; |
886 | } | |
7021844c | 887 | |
888 | /* somewhat safer calculation of %s */ | |
889 | double | |
890 | xpercent(double part, double whole) | |
891 | { | |
892 | return xdiv(100 * part, whole); | |
893 | } | |
894 | ||
02922e76 | 895 | int |
896 | xpercentInt(double part, double whole) | |
897 | { | |
4915be3b | 898 | #if HAVE_RINT |
ebd3f27a | 899 | return (int) rint(xpercent(part, whole)); |
4915be3b | 900 | #else |
901 | /* SCO 3.2v4.2 doesn't have rint() -- mauri@mbp.ee */ | |
ebd3f27a | 902 | return (int) floor(xpercent(part, whole) + 0.5); |
4915be3b | 903 | #endif |
02922e76 | 904 | } |
905 | ||
7021844c | 906 | /* somewhat safer division */ |
907 | double | |
908 | xdiv(double nom, double denom) | |
909 | { | |
910 | return (denom != 0.0) ? nom / denom : -1.0; | |
911 | } | |
de336bbe | 912 | |
913 | /* integer to string */ | |
914 | const char * | |
915 | xitoa(int num) | |
916 | { | |
461eef68 | 917 | static char buf[24]; /* 2^64 = 18446744073709551616 */ |
de336bbe | 918 | snprintf(buf, sizeof(buf), "%d", num); |
919 | return buf; | |
920 | } | |
5ac23588 | 921 | |
922 | /* A default failure notifier when the main program hasn't installed any */ | |
94439e4e | 923 | void |
e016fecf | 924 | default_failure_notify(const char *message) |
5ac23588 | 925 | { |
e016fecf | 926 | write(2, message, strlen(message)); |
5ac23588 | 927 | write(2, "\n", 1); |
928 | abort(); | |
929 | } | |
d96ceb8e | 930 | |
931 | void | |
932 | gb_flush(gb_t * g) | |
933 | { | |
934 | g->gb += (g->bytes >> 30); | |
935 | g->bytes &= (1 << 30) - 1; | |
936 | } | |
937 | ||
938 | double | |
939 | gb_to_double(const gb_t * g) | |
940 | { | |
941 | return ((double) g->gb) * ((double) (1 << 30)) + ((double) g->bytes); | |
942 | } | |
943 | ||
944 | const char * | |
945 | double_to_str(char *buf, int buf_size, double value) | |
946 | { | |
947 | /* select format */ | |
e45d4fb5 | 948 | |
d96ceb8e | 949 | if (value < 1e9) |
e45d4fb5 | 950 | snprintf(buf, buf_size, "%.2f MB", value / 1e6); |
d96ceb8e | 951 | else if (value < 1e12) |
e45d4fb5 | 952 | snprintf(buf, buf_size, "%.3f GB", value / 1e9); |
d96ceb8e | 953 | else |
e45d4fb5 | 954 | snprintf(buf, buf_size, "%.4f TB", value / 1e12); |
955 | ||
d96ceb8e | 956 | return buf; |
957 | } | |
958 | ||
959 | const char * | |
960 | gb_to_str(const gb_t * g) | |
961 | { | |
962 | /* | |
963 | * it is often convenient to call gb_to_str several times for _one_ printf | |
964 | */ | |
965 | #define max_cc_calls 5 | |
966 | typedef char GbBuf[32]; | |
967 | static GbBuf bufs[max_cc_calls]; | |
968 | static int call_id = 0; | |
969 | double value = gb_to_double(g); | |
970 | char *buf = bufs[call_id++]; | |
e45d4fb5 | 971 | |
d96ceb8e | 972 | if (call_id >= max_cc_calls) |
e45d4fb5 | 973 | call_id = 0; |
974 | ||
d96ceb8e | 975 | /* select format */ |
976 | if (value < 1e9) | |
e45d4fb5 | 977 | snprintf(buf, sizeof(GbBuf), "%.2f MB", value / 1e6); |
d96ceb8e | 978 | else if (value < 1e12) |
e45d4fb5 | 979 | snprintf(buf, sizeof(GbBuf), "%.2f GB", value / 1e9); |
d96ceb8e | 980 | else |
e45d4fb5 | 981 | snprintf(buf, sizeof(GbBuf), "%.2f TB", value / 1e12); |
982 | ||
d96ceb8e | 983 | return buf; |
984 | } |