1 /* 2 * Define simple versions of assertion macros that won't recurse in case 3 * of assertion failures in malloc_*printf(). 4 */ 5 #define assert(e) do { \ 6 if (config_debug && !(e)) { \ 7 malloc_write("<jemalloc>: Failed assertion\n"); \ 8 abort(); \ 9 } \ 10 } while (0) 11 12 #define not_reached() do { \ 13 if (config_debug) { \ 14 malloc_write("<jemalloc>: Unreachable code reached\n"); \ 15 abort(); \ 16 } \ 17 unreachable(); \ 18 } while (0) 19 20 #define not_implemented() do { \ 21 if (config_debug) { \ 22 malloc_write("<jemalloc>: Not implemented\n"); \ 23 abort(); \ 24 } \ 25 } while (0) 26 27 #define JEMALLOC_UTIL_C_ 28 #include "jemalloc/internal/jemalloc_internal.h" 29 30 /******************************************************************************/ 31 /* Function prototypes for non-inline static functions. */ 32 33 static void wrtmessage(void *cbopaque, const char *s); 34 #define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1) 35 static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s, 36 size_t *slen_p); 37 #define D2S_BUFSIZE (1 + U2S_BUFSIZE) 38 static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p); 39 #define O2S_BUFSIZE (1 + U2S_BUFSIZE) 40 static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p); 41 #define X2S_BUFSIZE (2 + U2S_BUFSIZE) 42 static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, 43 size_t *slen_p); 44 45 /******************************************************************************/ 46 47 /* malloc_message() setup. */ 48 static void 49 wrtmessage(void *cbopaque, const char *s) 50 { 51 52 #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_write) 53 /* 54 * Use syscall(2) rather than write(2) when possible in order to avoid 55 * the possibility of memory allocation within libc. This is necessary 56 * on FreeBSD; most operating systems do not have this problem though. 57 * 58 * syscall() returns long or int, depending on platform, so capture the 59 * unused result in the widest plausible type to avoid compiler 60 * warnings. 61 */ 62 UNUSED long result = syscall(SYS_write, STDERR_FILENO, s, strlen(s)); 63 #else 64 UNUSED ssize_t result = write(STDERR_FILENO, s, strlen(s)); 65 #endif 66 } 67 68 JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s); 69 70 /* 71 * Wrapper around malloc_message() that avoids the need for 72 * je_malloc_message(...) throughout the code. 73 */ 74 void 75 malloc_write(const char *s) 76 { 77 78 if (je_malloc_message != NULL) 79 je_malloc_message(NULL, s); 80 else 81 wrtmessage(NULL, s); 82 } 83 84 /* 85 * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so 86 * provide a wrapper. 87 */ 88 int 89 buferror(int err, char *buf, size_t buflen) 90 { 91 92 #ifdef _WIN32 93 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, 94 (LPSTR)buf, (DWORD)buflen, NULL); 95 return (0); 96 #elif defined(__GLIBC__) && defined(_GNU_SOURCE) 97 char *b = strerror_r(err, buf, buflen); 98 if (b != buf) { 99 strncpy(buf, b, buflen); 100 buf[buflen-1] = '\0'; 101 } 102 return (0); 103 #else 104 return (strerror_r(err, buf, buflen)); 105 #endif 106 } 107 108 uintmax_t 109 malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) 110 { 111 uintmax_t ret, digit; 112 unsigned b; 113 bool neg; 114 const char *p, *ns; 115 116 p = nptr; 117 if (base < 0 || base == 1 || base > 36) { 118 ns = p; 119 set_errno(EINVAL); 120 ret = UINTMAX_MAX; 121 goto label_return; 122 } 123 b = base; 124 125 /* Swallow leading whitespace and get sign, if any. */ 126 neg = false; 127 while (true) { 128 switch (*p) { 129 case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': 130 p++; 131 break; 132 case '-': 133 neg = true; 134 /* Fall through. */ 135 case '+': 136 p++; 137 /* Fall through. */ 138 default: 139 goto label_prefix; 140 } 141 } 142 143 /* Get prefix, if any. */ 144 label_prefix: 145 /* 146 * Note where the first non-whitespace/sign character is so that it is 147 * possible to tell whether any digits are consumed (e.g., " 0" vs. 148 * " -x"). 149 */ 150 ns = p; 151 if (*p == '0') { 152 switch (p[1]) { 153 case '0': case '1': case '2': case '3': case '4': case '5': 154 case '6': case '7': 155 if (b == 0) 156 b = 8; 157 if (b == 8) 158 p++; 159 break; 160 case 'X': case 'x': 161 switch (p[2]) { 162 case '0': case '1': case '2': case '3': case '4': 163 case '5': case '6': case '7': case '8': case '9': 164 case 'A': case 'B': case 'C': case 'D': case 'E': 165 case 'F': 166 case 'a': case 'b': case 'c': case 'd': case 'e': 167 case 'f': 168 if (b == 0) 169 b = 16; 170 if (b == 16) 171 p += 2; 172 break; 173 default: 174 break; 175 } 176 break; 177 default: 178 p++; 179 ret = 0; 180 goto label_return; 181 } 182 } 183 if (b == 0) 184 b = 10; 185 186 /* Convert. */ 187 ret = 0; 188 while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b) 189 || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b) 190 || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) { 191 uintmax_t pret = ret; 192 ret *= b; 193 ret += digit; 194 if (ret < pret) { 195 /* Overflow. */ 196 set_errno(ERANGE); 197 ret = UINTMAX_MAX; 198 goto label_return; 199 } 200 p++; 201 } 202 if (neg) 203 ret = (uintmax_t)(-((intmax_t)ret)); 204 205 if (p == ns) { 206 /* No conversion performed. */ 207 set_errno(EINVAL); 208 ret = UINTMAX_MAX; 209 goto label_return; 210 } 211 212 label_return: 213 if (endptr != NULL) { 214 if (p == ns) { 215 /* No characters were converted. */ 216 *endptr = (char *)nptr; 217 } else 218 *endptr = (char *)p; 219 } 220 return (ret); 221 } 222 223 static char * 224 u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) 225 { 226 unsigned i; 227 228 i = U2S_BUFSIZE - 1; 229 s[i] = '\0'; 230 switch (base) { 231 case 10: 232 do { 233 i--; 234 s[i] = "0123456789"[x % (uint64_t)10]; 235 x /= (uint64_t)10; 236 } while (x > 0); 237 break; 238 case 16: { 239 const char *digits = (uppercase) 240 ? "0123456789ABCDEF" 241 : "0123456789abcdef"; 242 243 do { 244 i--; 245 s[i] = digits[x & 0xf]; 246 x >>= 4; 247 } while (x > 0); 248 break; 249 } default: { 250 const char *digits = (uppercase) 251 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 252 : "0123456789abcdefghijklmnopqrstuvwxyz"; 253 254 assert(base >= 2 && base <= 36); 255 do { 256 i--; 257 s[i] = digits[x % (uint64_t)base]; 258 x /= (uint64_t)base; 259 } while (x > 0); 260 }} 261 262 *slen_p = U2S_BUFSIZE - 1 - i; 263 return (&s[i]); 264 } 265 266 static char * 267 d2s(intmax_t x, char sign, char *s, size_t *slen_p) 268 { 269 bool neg; 270 271 if ((neg = (x < 0))) 272 x = -x; 273 s = u2s(x, 10, false, s, slen_p); 274 if (neg) 275 sign = '-'; 276 switch (sign) { 277 case '-': 278 if (!neg) 279 break; 280 /* Fall through. */ 281 case ' ': 282 case '+': 283 s--; 284 (*slen_p)++; 285 *s = sign; 286 break; 287 default: not_reached(); 288 } 289 return (s); 290 } 291 292 static char * 293 o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) 294 { 295 296 s = u2s(x, 8, false, s, slen_p); 297 if (alt_form && *s != '0') { 298 s--; 299 (*slen_p)++; 300 *s = '0'; 301 } 302 return (s); 303 } 304 305 static char * 306 x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) 307 { 308 309 s = u2s(x, 16, uppercase, s, slen_p); 310 if (alt_form) { 311 s -= 2; 312 (*slen_p) += 2; 313 memcpy(s, uppercase ? "0X" : "0x", 2); 314 } 315 return (s); 316 } 317 318 size_t 319 malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) 320 { 321 size_t i; 322 const char *f; 323 324 #define APPEND_C(c) do { \ 325 if (i < size) \ 326 str[i] = (c); \ 327 i++; \ 328 } while (0) 329 #define APPEND_S(s, slen) do { \ 330 if (i < size) { \ 331 size_t cpylen = (slen <= size - i) ? slen : size - i; \ 332 memcpy(&str[i], s, cpylen); \ 333 } \ 334 i += slen; \ 335 } while (0) 336 #define APPEND_PADDED_S(s, slen, width, left_justify) do { \ 337 /* Left padding. */ \ 338 size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \ 339 (size_t)width - slen : 0); \ 340 if (!left_justify && pad_len != 0) { \ 341 size_t j; \ 342 for (j = 0; j < pad_len; j++) \ 343 APPEND_C(' '); \ 344 } \ 345 /* Value. */ \ 346 APPEND_S(s, slen); \ 347 /* Right padding. */ \ 348 if (left_justify && pad_len != 0) { \ 349 size_t j; \ 350 for (j = 0; j < pad_len; j++) \ 351 APPEND_C(' '); \ 352 } \ 353 } while (0) 354 #define GET_ARG_NUMERIC(val, len) do { \ 355 switch (len) { \ 356 case '?': \ 357 val = va_arg(ap, int); \ 358 break; \ 359 case '?' | 0x80: \ 360 val = va_arg(ap, unsigned int); \ 361 break; \ 362 case 'l': \ 363 val = va_arg(ap, long); \ 364 break; \ 365 case 'l' | 0x80: \ 366 val = va_arg(ap, unsigned long); \ 367 break; \ 368 case 'q': \ 369 val = va_arg(ap, long long); \ 370 break; \ 371 case 'q' | 0x80: \ 372 val = va_arg(ap, unsigned long long); \ 373 break; \ 374 case 'j': \ 375 val = va_arg(ap, intmax_t); \ 376 break; \ 377 case 'j' | 0x80: \ 378 val = va_arg(ap, uintmax_t); \ 379 break; \ 380 case 't': \ 381 val = va_arg(ap, ptrdiff_t); \ 382 break; \ 383 case 'z': \ 384 val = va_arg(ap, ssize_t); \ 385 break; \ 386 case 'z' | 0x80: \ 387 val = va_arg(ap, size_t); \ 388 break; \ 389 case 'p': /* Synthetic; used for %p. */ \ 390 val = va_arg(ap, uintptr_t); \ 391 break; \ 392 default: \ 393 not_reached(); \ 394 val = 0; \ 395 } \ 396 } while (0) 397 398 i = 0; 399 f = format; 400 while (true) { 401 switch (*f) { 402 case '\0': goto label_out; 403 case '%': { 404 bool alt_form = false; 405 bool left_justify = false; 406 bool plus_space = false; 407 bool plus_plus = false; 408 int prec = -1; 409 int width = -1; 410 unsigned char len = '?'; 411 char *s; 412 size_t slen; 413 414 f++; 415 /* Flags. */ 416 while (true) { 417 switch (*f) { 418 case '#': 419 assert(!alt_form); 420 alt_form = true; 421 break; 422 case '-': 423 assert(!left_justify); 424 left_justify = true; 425 break; 426 case ' ': 427 assert(!plus_space); 428 plus_space = true; 429 break; 430 case '+': 431 assert(!plus_plus); 432 plus_plus = true; 433 break; 434 default: goto label_width; 435 } 436 f++; 437 } 438 /* Width. */ 439 label_width: 440 switch (*f) { 441 case '*': 442 width = va_arg(ap, int); 443 f++; 444 if (width < 0) { 445 left_justify = true; 446 width = -width; 447 } 448 break; 449 case '0': case '1': case '2': case '3': case '4': 450 case '5': case '6': case '7': case '8': case '9': { 451 uintmax_t uwidth; 452 set_errno(0); 453 uwidth = malloc_strtoumax(f, (char **)&f, 10); 454 assert(uwidth != UINTMAX_MAX || get_errno() != 455 ERANGE); 456 width = (int)uwidth; 457 break; 458 } default: 459 break; 460 } 461 /* Width/precision separator. */ 462 if (*f == '.') 463 f++; 464 else 465 goto label_length; 466 /* Precision. */ 467 switch (*f) { 468 case '*': 469 prec = va_arg(ap, int); 470 f++; 471 break; 472 case '0': case '1': case '2': case '3': case '4': 473 case '5': case '6': case '7': case '8': case '9': { 474 uintmax_t uprec; 475 set_errno(0); 476 uprec = malloc_strtoumax(f, (char **)&f, 10); 477 assert(uprec != UINTMAX_MAX || get_errno() != 478 ERANGE); 479 prec = (int)uprec; 480 break; 481 } 482 default: break; 483 } 484 /* Length. */ 485 label_length: 486 switch (*f) { 487 case 'l': 488 f++; 489 if (*f == 'l') { 490 len = 'q'; 491 f++; 492 } else 493 len = 'l'; 494 break; 495 case 'q': case 'j': case 't': case 'z': 496 len = *f; 497 f++; 498 break; 499 default: break; 500 } 501 /* Conversion specifier. */ 502 switch (*f) { 503 case '%': 504 /* %% */ 505 APPEND_C(*f); 506 f++; 507 break; 508 case 'd': case 'i': { 509 intmax_t val JEMALLOC_CC_SILENCE_INIT(0); 510 char buf[D2S_BUFSIZE]; 511 512 GET_ARG_NUMERIC(val, len); 513 s = d2s(val, (plus_plus ? '+' : (plus_space ? 514 ' ' : '-')), buf, &slen); 515 APPEND_PADDED_S(s, slen, width, left_justify); 516 f++; 517 break; 518 } case 'o': { 519 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 520 char buf[O2S_BUFSIZE]; 521 522 GET_ARG_NUMERIC(val, len | 0x80); 523 s = o2s(val, alt_form, buf, &slen); 524 APPEND_PADDED_S(s, slen, width, left_justify); 525 f++; 526 break; 527 } case 'u': { 528 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 529 char buf[U2S_BUFSIZE]; 530 531 GET_ARG_NUMERIC(val, len | 0x80); 532 s = u2s(val, 10, false, buf, &slen); 533 APPEND_PADDED_S(s, slen, width, left_justify); 534 f++; 535 break; 536 } case 'x': case 'X': { 537 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 538 char buf[X2S_BUFSIZE]; 539 540 GET_ARG_NUMERIC(val, len | 0x80); 541 s = x2s(val, alt_form, *f == 'X', buf, &slen); 542 APPEND_PADDED_S(s, slen, width, left_justify); 543 f++; 544 break; 545 } case 'c': { 546 unsigned char val; 547 char buf[2]; 548 549 assert(len == '?' || len == 'l'); 550 assert_not_implemented(len != 'l'); 551 val = va_arg(ap, int); 552 buf[0] = val; 553 buf[1] = '\0'; 554 APPEND_PADDED_S(buf, 1, width, left_justify); 555 f++; 556 break; 557 } case 's': 558 assert(len == '?' || len == 'l'); 559 assert_not_implemented(len != 'l'); 560 s = va_arg(ap, char *); 561 slen = (prec < 0) ? strlen(s) : (size_t)prec; 562 APPEND_PADDED_S(s, slen, width, left_justify); 563 f++; 564 break; 565 case 'p': { 566 uintmax_t val; 567 char buf[X2S_BUFSIZE]; 568 569 GET_ARG_NUMERIC(val, 'p'); 570 s = x2s(val, true, false, buf, &slen); 571 APPEND_PADDED_S(s, slen, width, left_justify); 572 f++; 573 break; 574 } default: not_reached(); 575 } 576 break; 577 } default: { 578 APPEND_C(*f); 579 f++; 580 break; 581 }} 582 } 583 label_out: 584 if (i < size) 585 str[i] = '\0'; 586 else 587 str[size - 1] = '\0'; 588 589 #undef APPEND_C 590 #undef APPEND_S 591 #undef APPEND_PADDED_S 592 #undef GET_ARG_NUMERIC 593 return (i); 594 } 595 596 JEMALLOC_FORMAT_PRINTF(3, 4) 597 size_t 598 malloc_snprintf(char *str, size_t size, const char *format, ...) 599 { 600 size_t ret; 601 va_list ap; 602 603 va_start(ap, format); 604 ret = malloc_vsnprintf(str, size, format, ap); 605 va_end(ap); 606 607 return (ret); 608 } 609 610 void 611 malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, 612 const char *format, va_list ap) 613 { 614 char buf[MALLOC_PRINTF_BUFSIZE]; 615 616 if (write_cb == NULL) { 617 /* 618 * The caller did not provide an alternate write_cb callback 619 * function, so use the default one. malloc_write() is an 620 * inline function, so use malloc_message() directly here. 621 */ 622 write_cb = (je_malloc_message != NULL) ? je_malloc_message : 623 wrtmessage; 624 cbopaque = NULL; 625 } 626 627 malloc_vsnprintf(buf, sizeof(buf), format, ap); 628 write_cb(cbopaque, buf); 629 } 630 631 /* 632 * Print to a callback function in such a way as to (hopefully) avoid memory 633 * allocation. 634 */ 635 JEMALLOC_FORMAT_PRINTF(3, 4) 636 void 637 malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque, 638 const char *format, ...) 639 { 640 va_list ap; 641 642 va_start(ap, format); 643 malloc_vcprintf(write_cb, cbopaque, format, ap); 644 va_end(ap); 645 } 646 647 /* Print to stderr in such a way as to avoid memory allocation. */ 648 JEMALLOC_FORMAT_PRINTF(1, 2) 649 void 650 malloc_printf(const char *format, ...) 651 { 652 va_list ap; 653 654 va_start(ap, format); 655 malloc_vcprintf(NULL, NULL, format, ap); 656 va_end(ap); 657 } 658 659 /* 660 * Restore normal assertion macros, in order to make it possible to compile all 661 * C files as a single concatenation. 662 */ 663 #undef assert 664 #undef not_reached 665 #undef not_implemented 666 #include "jemalloc/internal/assert.h" 667