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