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