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