]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/util.c
Bug #2016 fix: Prevent BodyPipe async calls from getting seemingly
[thirdparty/squid.git] / lib / util.c
CommitLineData
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 74static void default_failure_notify(const char *);
75
76void (*failure_notify) (const char *) = default_failure_notify;
090089c4 77static char msg[128];
78
36a97e19 79#if MEM_GEN_TRACE
80
3213655a 81static FILE *tracefp = NULL;
36a97e19 82
83void
84log_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
94void
95log_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 111static int malloc_sizes[DBG_MAXINDEX + 1];
58cd5bbd 112static int malloc_histo[DBG_MAXINDEX + 1];
30a4f2a8 113static int dbg_stat_init = 0;
114
58cd5bbd 115static int
116DBG_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 127static void
0673c0ba 128stat_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 138static int
139malloc_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 147void
58cd5bbd 148malloc_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 168char *xmalloc_file = "";
169int xmalloc_line = 0;
170char *xmalloc_func = "";
171static int xmalloc_count = 0;
172int xmalloc_trace = 0; /* Enable with -m option */
173size_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 185static void *(*malloc_ptrs)[DBG_ARRY_SZ];
8c6551ac 186static int malloc_size[DBG_ARRY_BKTS][DBG_ARRY_SZ];
59272939 187#if XMALLOC_TRACE
33ab18e8 188static char *malloc_file[DBG_ARRY_BKTS][DBG_ARRY_SZ];
189static short malloc_line[DBG_ARRY_BKTS][DBG_ARRY_SZ];
59272939 190static int malloc_count[DBG_ARRY_BKTS][DBG_ARRY_SZ];
191#endif
45e93040 192static 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 196static void
0673c0ba 197check_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 220static void
221check_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 253static void
254check_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 305size_t
306xmallocblksize(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
322static char *
323malloc_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 336int
337malloc_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 350int
351malloc_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 364static void
33ab18e8 365xmalloc_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
401short malloc_refs[DBG_ARRY_BKTS][DBG_ARRY_SZ];
33ab18e8 402#define XMALLOC_LEAK_ALIGN (4)
7ce875eb 403static void
404xmalloc_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 456void
457xmalloc_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 495void *
496xmalloc(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 552void
553xfree(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 582void
e7106f62 583xxfree(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 611void *
612xrealloc(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 674void *
8a7e978a 675xcalloc(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 735char *
0ee4272b 736xstrdup(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 */
765char *
766xstrndup(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 788const char *
02e640fe 789xstrerr(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 804const char *
805xstrerror(void)
806{
807 return xstrerr(errno);
808}
809
b8d8561b 810void
811Tolower(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
821int
e45d4fb5 822
9d90e665 823tvSubMsec(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 829int
e45d4fb5 830
88738790 831tvSubUsec(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 837double
e45d4fb5 838
260e56a3 839tvSubDsec(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 */
850char *
851xstrncpy(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 */
871size_t
872xcountws(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 */
889double
890xpercent(double part, double whole)
891{
892 return xdiv(100 * part, whole);
893}
894
02922e76 895int
896xpercentInt(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 */
907double
908xdiv(double nom, double denom)
909{
910 return (denom != 0.0) ? nom / denom : -1.0;
911}
de336bbe 912
913/* integer to string */
914const char *
915xitoa(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 923void
e016fecf 924default_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
931void
932gb_flush(gb_t * g)
933{
934 g->gb += (g->bytes >> 30);
935 g->bytes &= (1 << 30) - 1;
936}
937
938double
939gb_to_double(const gb_t * g)
940{
941 return ((double) g->gb) * ((double) (1 << 30)) + ((double) g->bytes);
942}
943
944const char *
945double_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
959const char *
960gb_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}