1234370Sjasone#define assert(e) do { \ 2234370Sjasone if (config_debug && !(e)) { \ 3234370Sjasone malloc_write("<jemalloc>: Failed assertion\n"); \ 4234370Sjasone abort(); \ 5234370Sjasone } \ 6234370Sjasone} while (0) 7234370Sjasone 8234370Sjasone#define not_reached() do { \ 9234370Sjasone if (config_debug) { \ 10234370Sjasone malloc_write("<jemalloc>: Unreachable code reached\n"); \ 11234370Sjasone abort(); \ 12234370Sjasone } \ 13234370Sjasone} while (0) 14234370Sjasone 15234370Sjasone#define not_implemented() do { \ 16234370Sjasone if (config_debug) { \ 17234370Sjasone malloc_write("<jemalloc>: Not implemented\n"); \ 18234370Sjasone abort(); \ 19234370Sjasone } \ 20234370Sjasone} while (0) 21234370Sjasone 22234370Sjasone#define JEMALLOC_UTIL_C_ 23234370Sjasone#include "jemalloc/internal/jemalloc_internal.h" 24234370Sjasone 25234370Sjasone/******************************************************************************/ 26234370Sjasone/* Function prototypes for non-inline static functions. */ 27234370Sjasone 28234370Sjasonestatic void wrtmessage(void *cbopaque, const char *s); 29234370Sjasone#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1) 30234370Sjasonestatic char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s, 31234370Sjasone size_t *slen_p); 32234370Sjasone#define D2S_BUFSIZE (1 + U2S_BUFSIZE) 33234370Sjasonestatic char *d2s(intmax_t x, char sign, char *s, size_t *slen_p); 34234370Sjasone#define O2S_BUFSIZE (1 + U2S_BUFSIZE) 35234370Sjasonestatic char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p); 36234370Sjasone#define X2S_BUFSIZE (2 + U2S_BUFSIZE) 37234370Sjasonestatic char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, 38234370Sjasone size_t *slen_p); 39234370Sjasone 40234370Sjasone/******************************************************************************/ 41234370Sjasone 42234370Sjasone/* malloc_message() setup. */ 43235238Sjasonestatic void 44234370Sjasonewrtmessage(void *cbopaque, const char *s) 45234370Sjasone{ 46234370Sjasone 47234370Sjasone#ifdef SYS_write 48234370Sjasone /* 49234370Sjasone * Use syscall(2) rather than write(2) when possible in order to avoid 50234370Sjasone * the possibility of memory allocation within libc. This is necessary 51234370Sjasone * on FreeBSD; most operating systems do not have this problem though. 52234370Sjasone */ 53234370Sjasone UNUSED int result = syscall(SYS_write, STDERR_FILENO, s, strlen(s)); 54234370Sjasone#else 55234370Sjasone UNUSED int result = write(STDERR_FILENO, s, strlen(s)); 56234370Sjasone#endif 57234370Sjasone} 58234370Sjasone 59235238SjasoneJEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s); 60234370Sjasone 61235238SjasoneJEMALLOC_ATTR(visibility("hidden")) 62234370Sjasonevoid 63234370Sjasonewrtmessage_1_0(const char *s1, const char *s2, const char *s3, 64234370Sjasone const char *s4) 65234370Sjasone{ 66234370Sjasone 67234370Sjasone wrtmessage(NULL, s1); 68234370Sjasone wrtmessage(NULL, s2); 69234370Sjasone wrtmessage(NULL, s3); 70234370Sjasone wrtmessage(NULL, s4); 71234370Sjasone} 72234370Sjasone 73234370Sjasonevoid (*__malloc_message_1_0)(const char *s1, const char *s2, const char *s3, 74234370Sjasone const char *s4) = wrtmessage_1_0; 75234370Sjasone__sym_compat(_malloc_message, __malloc_message_1_0, FBSD_1.0); 76234370Sjasone 77234370Sjasone/* 78235238Sjasone * Wrapper around malloc_message() that avoids the need for 79235238Sjasone * je_malloc_message(...) throughout the code. 80235238Sjasone */ 81235238Sjasonevoid 82235238Sjasonemalloc_write(const char *s) 83235238Sjasone{ 84235238Sjasone 85235238Sjasone if (je_malloc_message != NULL) 86235238Sjasone je_malloc_message(NULL, s); 87235238Sjasone else 88235238Sjasone wrtmessage(NULL, s); 89235238Sjasone} 90235238Sjasone 91235238Sjasone/* 92234370Sjasone * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so 93234370Sjasone * provide a wrapper. 94234370Sjasone */ 95234370Sjasoneint 96235238Sjasonebuferror(char *buf, size_t buflen) 97234370Sjasone{ 98235238Sjasone 99235238Sjasone#ifdef _WIN32 100235238Sjasone FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, 101235238Sjasone (LPSTR)buf, buflen, NULL); 102235238Sjasone return (0); 103235238Sjasone#elif defined(_GNU_SOURCE) 104234370Sjasone char *b = strerror_r(errno, buf, buflen); 105234370Sjasone if (b != buf) { 106234370Sjasone strncpy(buf, b, buflen); 107234370Sjasone buf[buflen-1] = '\0'; 108234370Sjasone } 109234370Sjasone return (0); 110234370Sjasone#else 111234370Sjasone return (strerror_r(errno, buf, buflen)); 112234370Sjasone#endif 113234370Sjasone} 114234370Sjasone 115234370Sjasoneuintmax_t 116234370Sjasonemalloc_strtoumax(const char *nptr, char **endptr, int base) 117234370Sjasone{ 118234370Sjasone uintmax_t ret, digit; 119234370Sjasone int b; 120234370Sjasone bool neg; 121234370Sjasone const char *p, *ns; 122234370Sjasone 123234370Sjasone if (base < 0 || base == 1 || base > 36) { 124235238Sjasone set_errno(EINVAL); 125234370Sjasone return (UINTMAX_MAX); 126234370Sjasone } 127234370Sjasone b = base; 128234370Sjasone 129234370Sjasone /* Swallow leading whitespace and get sign, if any. */ 130234370Sjasone neg = false; 131234370Sjasone p = nptr; 132234370Sjasone while (true) { 133234370Sjasone switch (*p) { 134234370Sjasone case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': 135234370Sjasone p++; 136234370Sjasone break; 137234370Sjasone case '-': 138234370Sjasone neg = true; 139234370Sjasone /* Fall through. */ 140234370Sjasone case '+': 141234370Sjasone p++; 142234370Sjasone /* Fall through. */ 143234370Sjasone default: 144234370Sjasone goto label_prefix; 145234370Sjasone } 146234370Sjasone } 147234370Sjasone 148234370Sjasone /* Get prefix, if any. */ 149234370Sjasone label_prefix: 150234370Sjasone /* 151234370Sjasone * Note where the first non-whitespace/sign character is so that it is 152234370Sjasone * possible to tell whether any digits are consumed (e.g., " 0" vs. 153234370Sjasone * " -x"). 154234370Sjasone */ 155234370Sjasone ns = p; 156234370Sjasone if (*p == '0') { 157234370Sjasone switch (p[1]) { 158234370Sjasone case '0': case '1': case '2': case '3': case '4': case '5': 159234370Sjasone case '6': case '7': 160234370Sjasone if (b == 0) 161234370Sjasone b = 8; 162234370Sjasone if (b == 8) 163234370Sjasone p++; 164234370Sjasone break; 165234370Sjasone case 'x': 166234370Sjasone switch (p[2]) { 167234370Sjasone case '0': case '1': case '2': case '3': case '4': 168234370Sjasone case '5': case '6': case '7': case '8': case '9': 169234370Sjasone case 'A': case 'B': case 'C': case 'D': case 'E': 170234370Sjasone case 'F': 171234370Sjasone case 'a': case 'b': case 'c': case 'd': case 'e': 172234370Sjasone case 'f': 173234370Sjasone if (b == 0) 174234370Sjasone b = 16; 175234370Sjasone if (b == 16) 176234370Sjasone p += 2; 177234370Sjasone break; 178234370Sjasone default: 179234370Sjasone break; 180234370Sjasone } 181234370Sjasone break; 182234370Sjasone default: 183234370Sjasone break; 184234370Sjasone } 185234370Sjasone } 186234370Sjasone if (b == 0) 187234370Sjasone b = 10; 188234370Sjasone 189234370Sjasone /* Convert. */ 190234370Sjasone ret = 0; 191234370Sjasone while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b) 192234370Sjasone || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b) 193234370Sjasone || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) { 194234370Sjasone uintmax_t pret = ret; 195234370Sjasone ret *= b; 196234370Sjasone ret += digit; 197234370Sjasone if (ret < pret) { 198234370Sjasone /* Overflow. */ 199235238Sjasone set_errno(ERANGE); 200234370Sjasone return (UINTMAX_MAX); 201234370Sjasone } 202234370Sjasone p++; 203234370Sjasone } 204234370Sjasone if (neg) 205234370Sjasone ret = -ret; 206234370Sjasone 207234370Sjasone if (endptr != NULL) { 208234370Sjasone if (p == ns) { 209234370Sjasone /* No characters were converted. */ 210234370Sjasone *endptr = (char *)nptr; 211234370Sjasone } else 212234370Sjasone *endptr = (char *)p; 213234370Sjasone } 214234370Sjasone 215234370Sjasone return (ret); 216234370Sjasone} 217234370Sjasone 218234370Sjasonestatic char * 219234370Sjasoneu2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) 220234370Sjasone{ 221234370Sjasone unsigned i; 222234370Sjasone 223234370Sjasone i = U2S_BUFSIZE - 1; 224234370Sjasone s[i] = '\0'; 225234370Sjasone switch (base) { 226234370Sjasone case 10: 227234370Sjasone do { 228234370Sjasone i--; 229234370Sjasone s[i] = "0123456789"[x % (uint64_t)10]; 230234370Sjasone x /= (uint64_t)10; 231234370Sjasone } while (x > 0); 232234370Sjasone break; 233234370Sjasone case 16: { 234234370Sjasone const char *digits = (uppercase) 235234370Sjasone ? "0123456789ABCDEF" 236234370Sjasone : "0123456789abcdef"; 237234370Sjasone 238234370Sjasone do { 239234370Sjasone i--; 240234370Sjasone s[i] = digits[x & 0xf]; 241234370Sjasone x >>= 4; 242234370Sjasone } while (x > 0); 243234370Sjasone break; 244234370Sjasone } default: { 245234370Sjasone const char *digits = (uppercase) 246234370Sjasone ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 247234370Sjasone : "0123456789abcdefghijklmnopqrstuvwxyz"; 248234370Sjasone 249234370Sjasone assert(base >= 2 && base <= 36); 250234370Sjasone do { 251234370Sjasone i--; 252234370Sjasone s[i] = digits[x % (uint64_t)base]; 253234370Sjasone x /= (uint64_t)base; 254234370Sjasone } while (x > 0); 255234370Sjasone }} 256234370Sjasone 257234370Sjasone *slen_p = U2S_BUFSIZE - 1 - i; 258234370Sjasone return (&s[i]); 259234370Sjasone} 260234370Sjasone 261234370Sjasonestatic char * 262234370Sjasoned2s(intmax_t x, char sign, char *s, size_t *slen_p) 263234370Sjasone{ 264234370Sjasone bool neg; 265234370Sjasone 266234370Sjasone if ((neg = (x < 0))) 267234370Sjasone x = -x; 268234370Sjasone s = u2s(x, 10, false, s, slen_p); 269234370Sjasone if (neg) 270234370Sjasone sign = '-'; 271234370Sjasone switch (sign) { 272234370Sjasone case '-': 273234370Sjasone if (neg == false) 274234370Sjasone break; 275234370Sjasone /* Fall through. */ 276234370Sjasone case ' ': 277234370Sjasone case '+': 278234370Sjasone s--; 279234370Sjasone (*slen_p)++; 280234370Sjasone *s = sign; 281234370Sjasone break; 282234370Sjasone default: not_reached(); 283234370Sjasone } 284234370Sjasone return (s); 285234370Sjasone} 286234370Sjasone 287234370Sjasonestatic char * 288234370Sjasoneo2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) 289234370Sjasone{ 290234370Sjasone 291234370Sjasone s = u2s(x, 8, false, s, slen_p); 292234370Sjasone if (alt_form && *s != '0') { 293234370Sjasone s--; 294234370Sjasone (*slen_p)++; 295234370Sjasone *s = '0'; 296234370Sjasone } 297234370Sjasone return (s); 298234370Sjasone} 299234370Sjasone 300234370Sjasonestatic char * 301234370Sjasonex2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) 302234370Sjasone{ 303234370Sjasone 304234370Sjasone s = u2s(x, 16, uppercase, s, slen_p); 305234370Sjasone if (alt_form) { 306234370Sjasone s -= 2; 307234370Sjasone (*slen_p) += 2; 308234370Sjasone memcpy(s, uppercase ? "0X" : "0x", 2); 309234370Sjasone } 310234370Sjasone return (s); 311234370Sjasone} 312234370Sjasone 313234370Sjasoneint 314234370Sjasonemalloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) 315234370Sjasone{ 316234370Sjasone int ret; 317234370Sjasone size_t i; 318234370Sjasone const char *f; 319234370Sjasone 320234370Sjasone#define APPEND_C(c) do { \ 321234370Sjasone if (i < size) \ 322234370Sjasone str[i] = (c); \ 323234370Sjasone i++; \ 324234370Sjasone} while (0) 325234370Sjasone#define APPEND_S(s, slen) do { \ 326234370Sjasone if (i < size) { \ 327234370Sjasone size_t cpylen = (slen <= size - i) ? slen : size - i; \ 328234370Sjasone memcpy(&str[i], s, cpylen); \ 329234370Sjasone } \ 330234370Sjasone i += slen; \ 331234370Sjasone} while (0) 332234370Sjasone#define APPEND_PADDED_S(s, slen, width, left_justify) do { \ 333234370Sjasone /* Left padding. */ \ 334234370Sjasone size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \ 335234370Sjasone (size_t)width - slen : 0); \ 336234370Sjasone if (left_justify == false && pad_len != 0) { \ 337234370Sjasone size_t j; \ 338234370Sjasone for (j = 0; j < pad_len; j++) \ 339234370Sjasone APPEND_C(' '); \ 340234370Sjasone } \ 341234370Sjasone /* Value. */ \ 342234370Sjasone APPEND_S(s, slen); \ 343234370Sjasone /* Right padding. */ \ 344234370Sjasone if (left_justify && pad_len != 0) { \ 345234370Sjasone size_t j; \ 346234370Sjasone for (j = 0; j < pad_len; j++) \ 347234370Sjasone APPEND_C(' '); \ 348234370Sjasone } \ 349234370Sjasone} while (0) 350234370Sjasone#define GET_ARG_NUMERIC(val, len) do { \ 351234370Sjasone switch (len) { \ 352234370Sjasone case '?': \ 353234370Sjasone val = va_arg(ap, int); \ 354234370Sjasone break; \ 355234543Sjasone case '?' | 0x80: \ 356234543Sjasone val = va_arg(ap, unsigned int); \ 357234543Sjasone break; \ 358234370Sjasone case 'l': \ 359234370Sjasone val = va_arg(ap, long); \ 360234370Sjasone break; \ 361234543Sjasone case 'l' | 0x80: \ 362234543Sjasone val = va_arg(ap, unsigned long); \ 363234543Sjasone break; \ 364234370Sjasone case 'q': \ 365234370Sjasone val = va_arg(ap, long long); \ 366234370Sjasone break; \ 367234543Sjasone case 'q' | 0x80: \ 368234543Sjasone val = va_arg(ap, unsigned long long); \ 369234543Sjasone break; \ 370234370Sjasone case 'j': \ 371234370Sjasone val = va_arg(ap, intmax_t); \ 372234370Sjasone break; \ 373234370Sjasone case 't': \ 374234370Sjasone val = va_arg(ap, ptrdiff_t); \ 375234370Sjasone break; \ 376234370Sjasone case 'z': \ 377234370Sjasone val = va_arg(ap, ssize_t); \ 378234370Sjasone break; \ 379234543Sjasone case 'z' | 0x80: \ 380234543Sjasone val = va_arg(ap, size_t); \ 381234543Sjasone break; \ 382234370Sjasone case 'p': /* Synthetic; used for %p. */ \ 383234370Sjasone val = va_arg(ap, uintptr_t); \ 384234370Sjasone break; \ 385234370Sjasone default: not_reached(); \ 386234370Sjasone } \ 387234370Sjasone} while (0) 388234370Sjasone 389234370Sjasone i = 0; 390234370Sjasone f = format; 391234370Sjasone while (true) { 392234370Sjasone switch (*f) { 393234370Sjasone case '\0': goto label_out; 394234370Sjasone case '%': { 395234370Sjasone bool alt_form = false; 396234370Sjasone bool left_justify = false; 397234370Sjasone bool plus_space = false; 398234370Sjasone bool plus_plus = false; 399234370Sjasone int prec = -1; 400234370Sjasone int width = -1; 401234543Sjasone unsigned char len = '?'; 402234370Sjasone 403234370Sjasone f++; 404234370Sjasone if (*f == '%') { 405234370Sjasone /* %% */ 406234370Sjasone APPEND_C(*f); 407234370Sjasone break; 408234370Sjasone } 409234370Sjasone /* Flags. */ 410234370Sjasone while (true) { 411234370Sjasone switch (*f) { 412234370Sjasone case '#': 413234370Sjasone assert(alt_form == false); 414234370Sjasone alt_form = true; 415234370Sjasone break; 416234370Sjasone case '-': 417234370Sjasone assert(left_justify == false); 418234370Sjasone left_justify = true; 419234370Sjasone break; 420234370Sjasone case ' ': 421234370Sjasone assert(plus_space == false); 422234370Sjasone plus_space = true; 423234370Sjasone break; 424234370Sjasone case '+': 425234370Sjasone assert(plus_plus == false); 426234370Sjasone plus_plus = true; 427234370Sjasone break; 428234370Sjasone default: goto label_width; 429234370Sjasone } 430234370Sjasone f++; 431234370Sjasone } 432234370Sjasone /* Width. */ 433234370Sjasone label_width: 434234370Sjasone switch (*f) { 435234370Sjasone case '*': 436234370Sjasone width = va_arg(ap, int); 437234370Sjasone f++; 438234370Sjasone break; 439234370Sjasone case '0': case '1': case '2': case '3': case '4': 440234370Sjasone case '5': case '6': case '7': case '8': case '9': { 441234370Sjasone uintmax_t uwidth; 442235238Sjasone set_errno(0); 443234370Sjasone uwidth = malloc_strtoumax(f, (char **)&f, 10); 444235238Sjasone assert(uwidth != UINTMAX_MAX || get_errno() != 445234370Sjasone ERANGE); 446234370Sjasone width = (int)uwidth; 447234370Sjasone if (*f == '.') { 448234370Sjasone f++; 449234370Sjasone goto label_precision; 450234370Sjasone } else 451234370Sjasone goto label_length; 452234370Sjasone break; 453234370Sjasone } case '.': 454234370Sjasone f++; 455234370Sjasone goto label_precision; 456234370Sjasone default: goto label_length; 457234370Sjasone } 458234370Sjasone /* Precision. */ 459234370Sjasone label_precision: 460234370Sjasone switch (*f) { 461234370Sjasone case '*': 462234370Sjasone prec = va_arg(ap, int); 463234370Sjasone f++; 464234370Sjasone break; 465234370Sjasone case '0': case '1': case '2': case '3': case '4': 466234370Sjasone case '5': case '6': case '7': case '8': case '9': { 467234370Sjasone uintmax_t uprec; 468235238Sjasone set_errno(0); 469234370Sjasone uprec = malloc_strtoumax(f, (char **)&f, 10); 470235238Sjasone assert(uprec != UINTMAX_MAX || get_errno() != 471235238Sjasone ERANGE); 472234370Sjasone prec = (int)uprec; 473234370Sjasone break; 474234370Sjasone } 475234370Sjasone default: break; 476234370Sjasone } 477234370Sjasone /* Length. */ 478234370Sjasone label_length: 479234370Sjasone switch (*f) { 480234370Sjasone case 'l': 481234370Sjasone f++; 482234370Sjasone if (*f == 'l') { 483234370Sjasone len = 'q'; 484234370Sjasone f++; 485234370Sjasone } else 486234370Sjasone len = 'l'; 487234370Sjasone break; 488234370Sjasone case 'j': 489234370Sjasone len = 'j'; 490234370Sjasone f++; 491234370Sjasone break; 492234370Sjasone case 't': 493234370Sjasone len = 't'; 494234370Sjasone f++; 495234370Sjasone break; 496234370Sjasone case 'z': 497234370Sjasone len = 'z'; 498234370Sjasone f++; 499234370Sjasone break; 500234370Sjasone default: break; 501234370Sjasone } 502234370Sjasone /* Conversion specifier. */ 503234370Sjasone switch (*f) { 504234370Sjasone char *s; 505234370Sjasone size_t slen; 506234370Sjasone case 'd': case 'i': { 507234370Sjasone intmax_t val JEMALLOC_CC_SILENCE_INIT(0); 508234370Sjasone char buf[D2S_BUFSIZE]; 509234370Sjasone 510234370Sjasone GET_ARG_NUMERIC(val, len); 511234370Sjasone s = d2s(val, (plus_plus ? '+' : (plus_space ? 512234370Sjasone ' ' : '-')), buf, &slen); 513234370Sjasone APPEND_PADDED_S(s, slen, width, left_justify); 514234370Sjasone f++; 515234370Sjasone break; 516234370Sjasone } case 'o': { 517234370Sjasone uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 518234370Sjasone char buf[O2S_BUFSIZE]; 519234370Sjasone 520234543Sjasone GET_ARG_NUMERIC(val, len | 0x80); 521234370Sjasone s = o2s(val, alt_form, buf, &slen); 522234370Sjasone APPEND_PADDED_S(s, slen, width, left_justify); 523234370Sjasone f++; 524234370Sjasone break; 525234370Sjasone } case 'u': { 526234370Sjasone uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 527234370Sjasone char buf[U2S_BUFSIZE]; 528234370Sjasone 529234543Sjasone GET_ARG_NUMERIC(val, len | 0x80); 530234370Sjasone s = u2s(val, 10, false, buf, &slen); 531234370Sjasone APPEND_PADDED_S(s, slen, width, left_justify); 532234370Sjasone f++; 533234370Sjasone break; 534234370Sjasone } case 'x': case 'X': { 535234370Sjasone uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 536234370Sjasone char buf[X2S_BUFSIZE]; 537234370Sjasone 538234543Sjasone GET_ARG_NUMERIC(val, len | 0x80); 539234370Sjasone s = x2s(val, alt_form, *f == 'X', buf, &slen); 540234370Sjasone APPEND_PADDED_S(s, slen, width, left_justify); 541234370Sjasone f++; 542234370Sjasone break; 543234370Sjasone } case 'c': { 544234370Sjasone unsigned char val; 545234370Sjasone char buf[2]; 546234370Sjasone 547234370Sjasone assert(len == '?' || len == 'l'); 548234370Sjasone assert_not_implemented(len != 'l'); 549234370Sjasone val = va_arg(ap, int); 550234370Sjasone buf[0] = val; 551234370Sjasone buf[1] = '\0'; 552234370Sjasone APPEND_PADDED_S(buf, 1, width, left_justify); 553234370Sjasone f++; 554234370Sjasone break; 555234370Sjasone } case 's': 556234370Sjasone assert(len == '?' || len == 'l'); 557234370Sjasone assert_not_implemented(len != 'l'); 558234370Sjasone s = va_arg(ap, char *); 559234370Sjasone slen = (prec == -1) ? strlen(s) : prec; 560234370Sjasone APPEND_PADDED_S(s, slen, width, left_justify); 561234370Sjasone f++; 562234370Sjasone break; 563234370Sjasone case 'p': { 564234370Sjasone uintmax_t val; 565234370Sjasone char buf[X2S_BUFSIZE]; 566234370Sjasone 567234370Sjasone GET_ARG_NUMERIC(val, 'p'); 568234370Sjasone s = x2s(val, true, false, buf, &slen); 569234370Sjasone APPEND_PADDED_S(s, slen, width, left_justify); 570234370Sjasone f++; 571234370Sjasone break; 572234370Sjasone } 573234370Sjasone default: not_implemented(); 574234370Sjasone } 575234370Sjasone break; 576234370Sjasone } default: { 577234370Sjasone APPEND_C(*f); 578234370Sjasone f++; 579234370Sjasone break; 580234370Sjasone }} 581234370Sjasone } 582234370Sjasone label_out: 583234370Sjasone if (i < size) 584234370Sjasone str[i] = '\0'; 585234370Sjasone else 586234370Sjasone str[size - 1] = '\0'; 587234370Sjasone ret = i; 588234370Sjasone 589234370Sjasone#undef APPEND_C 590234370Sjasone#undef APPEND_S 591234370Sjasone#undef APPEND_PADDED_S 592234370Sjasone#undef GET_ARG_NUMERIC 593234370Sjasone return (ret); 594234370Sjasone} 595234370Sjasone 596234370SjasoneJEMALLOC_ATTR(format(printf, 3, 4)) 597234370Sjasoneint 598234370Sjasonemalloc_snprintf(char *str, size_t size, const char *format, ...) 599234370Sjasone{ 600234370Sjasone int ret; 601234370Sjasone va_list ap; 602234370Sjasone 603234370Sjasone va_start(ap, format); 604234370Sjasone ret = malloc_vsnprintf(str, size, format, ap); 605234370Sjasone va_end(ap); 606234370Sjasone 607234370Sjasone return (ret); 608234370Sjasone} 609234370Sjasone 610234370Sjasonevoid 611234370Sjasonemalloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, 612234370Sjasone const char *format, va_list ap) 613234370Sjasone{ 614234370Sjasone char buf[MALLOC_PRINTF_BUFSIZE]; 615234370Sjasone 616234370Sjasone if (write_cb == NULL) { 617234370Sjasone /* 618234370Sjasone * The caller did not provide an alternate write_cb callback 619234370Sjasone * function, so use the default one. malloc_write() is an 620234370Sjasone * inline function, so use malloc_message() directly here. 621234370Sjasone */ 622235238Sjasone write_cb = (je_malloc_message != NULL) ? je_malloc_message : 623235238Sjasone wrtmessage; 624234370Sjasone cbopaque = NULL; 625234370Sjasone } 626234370Sjasone 627234370Sjasone malloc_vsnprintf(buf, sizeof(buf), format, ap); 628234370Sjasone write_cb(cbopaque, buf); 629234370Sjasone} 630234370Sjasone 631234370Sjasone/* 632234370Sjasone * Print to a callback function in such a way as to (hopefully) avoid memory 633234370Sjasone * allocation. 634234370Sjasone */ 635234370SjasoneJEMALLOC_ATTR(format(printf, 3, 4)) 636234370Sjasonevoid 637234370Sjasonemalloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque, 638234370Sjasone const char *format, ...) 639234370Sjasone{ 640234370Sjasone va_list ap; 641234370Sjasone 642234370Sjasone va_start(ap, format); 643234370Sjasone malloc_vcprintf(write_cb, cbopaque, format, ap); 644234370Sjasone va_end(ap); 645234370Sjasone} 646234370Sjasone 647234370Sjasone/* Print to stderr in such a way as to avoid memory allocation. */ 648234370SjasoneJEMALLOC_ATTR(format(printf, 1, 2)) 649234370Sjasonevoid 650234370Sjasonemalloc_printf(const char *format, ...) 651234370Sjasone{ 652234370Sjasone va_list ap; 653234370Sjasone 654234370Sjasone va_start(ap, format); 655234370Sjasone malloc_vcprintf(NULL, NULL, format, ap); 656234370Sjasone va_end(ap); 657234370Sjasone} 658