13447SN/A#define assert(e) do { \ 23447SN/A if (config_debug && !(e)) { \ 33447SN/A malloc_write("<jemalloc>: Failed assertion\n"); \ 43447SN/A abort(); \ 53447SN/A } \ 63447SN/A} while (0) 73447SN/A 83447SN/A#define not_reached() do { \ 93447SN/A if (config_debug) { \ 103447SN/A malloc_write("<jemalloc>: Unreachable code reached\n"); \ 113447SN/A abort(); \ 123447SN/A } \ 133447SN/A} while (0) 143447SN/A 153447SN/A#define not_implemented() do { \ 163447SN/A if (config_debug) { \ 173447SN/A malloc_write("<jemalloc>: Not implemented\n"); \ 183447SN/A abort(); \ 193447SN/A } \ 203447SN/A} while (0) 213447SN/A 223447SN/A#define JEMALLOC_UTIL_C_ 233447SN/A#include "jemalloc/internal/jemalloc_internal.h" 243447SN/A 253447SN/A/******************************************************************************/ 263447SN/A/* Function prototypes for non-inline static functions. */ 273447SN/A 283447SN/Astatic void wrtmessage(void *cbopaque, const char *s); 2911707Stpivovarova#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1) 3011707Stpivovarovastatic char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s, 3111707Stpivovarova size_t *slen_p); 323447SN/A#define D2S_BUFSIZE (1 + U2S_BUFSIZE) 333447SN/Astatic char *d2s(intmax_t x, char sign, char *s, size_t *slen_p); 3411707Stpivovarova#define O2S_BUFSIZE (1 + U2S_BUFSIZE) 3511707Stpivovarovastatic char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p); 363447SN/A#define X2S_BUFSIZE (2 + U2S_BUFSIZE) 373447SN/Astatic char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, 383447SN/A size_t *slen_p); 393447SN/A 403447SN/A/******************************************************************************/ 413447SN/A 423447SN/A/* malloc_message() setup. */ 433447SN/Astatic void 443447SN/Awrtmessage(void *cbopaque, const char *s) 453447SN/A{ 463447SN/A 473447SN/A#ifdef SYS_write 483447SN/A /* 493447SN/A * Use syscall(2) rather than write(2) when possible in order to avoid 503447SN/A * the possibility of memory allocation within libc. This is necessary 513447SN/A * on FreeBSD; most operating systems do not have this problem though. 523447SN/A */ 533447SN/A UNUSED int result = syscall(SYS_write, STDERR_FILENO, s, strlen(s)); 543447SN/A#else 553447SN/A UNUSED int result = write(STDERR_FILENO, s, strlen(s)); 563447SN/A#endif 573447SN/A} 583447SN/A 593447SN/AJEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s); 603447SN/A 613447SN/AJEMALLOC_ATTR(visibility("hidden")) 623447SN/Avoid 633447SN/Awrtmessage_1_0(const char *s1, const char *s2, const char *s3, 643447SN/A const char *s4) 653447SN/A{ 663447SN/A 673447SN/A wrtmessage(NULL, s1); 683447SN/A wrtmessage(NULL, s2); 693447SN/A wrtmessage(NULL, s3); 703447SN/A wrtmessage(NULL, s4); 713447SN/A} 723447SN/A 733447SN/Avoid (*__malloc_message_1_0)(const char *s1, const char *s2, const char *s3, 743447SN/A const char *s4) = wrtmessage_1_0; 753447SN/A__sym_compat(_malloc_message, __malloc_message_1_0, FBSD_1.0); 763447SN/A 773447SN/A/* 783447SN/A * Wrapper around malloc_message() that avoids the need for 793447SN/A * je_malloc_message(...) throughout the code. 803447SN/A */ 813447SN/Avoid 823447SN/Amalloc_write(const char *s) 833447SN/A{ 843447SN/A 853447SN/A if (je_malloc_message != NULL) 863447SN/A je_malloc_message(NULL, s); 873447SN/A else 883447SN/A wrtmessage(NULL, s); 893447SN/A} 903447SN/A 913447SN/A/* 923447SN/A * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so 933447SN/A * provide a wrapper. 943447SN/A */ 953447SN/Aint 963447SN/Abuferror(char *buf, size_t buflen) 973447SN/A{ 983447SN/A 993447SN/A#ifdef _WIN32 1003447SN/A FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, 1013447SN/A (LPSTR)buf, buflen, NULL); 1023447SN/A return (0); 1033447SN/A#elif defined(_GNU_SOURCE) 1043447SN/A char *b = strerror_r(errno, buf, buflen); 1053447SN/A if (b != buf) { 1063447SN/A strncpy(buf, b, buflen); 1073447SN/A buf[buflen-1] = '\0'; 1083447SN/A } 1093447SN/A return (0); 1103447SN/A#else 1113447SN/A return (strerror_r(errno, buf, buflen)); 1123447SN/A#endif 1133447SN/A} 1143447SN/A 1153447SN/Auintmax_t 1163447SN/Amalloc_strtoumax(const char *nptr, char **endptr, int base) 1173447SN/A{ 1183447SN/A uintmax_t ret, digit; 1193447SN/A int b; 1203447SN/A bool neg; 1213447SN/A const char *p, *ns; 1223447SN/A 1233447SN/A if (base < 0 || base == 1 || base > 36) { 1243447SN/A set_errno(EINVAL); 1253447SN/A return (UINTMAX_MAX); 1263447SN/A } 1273447SN/A b = base; 1283447SN/A 1293447SN/A /* Swallow leading whitespace and get sign, if any. */ 1303447SN/A neg = false; 1313447SN/A p = nptr; 1323447SN/A while (true) { 1333447SN/A switch (*p) { 1343447SN/A case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': 1353447SN/A p++; 1363447SN/A break; 1373447SN/A case '-': 1383447SN/A neg = true; 1393447SN/A /* Fall through. */ 1403447SN/A case '+': 1413447SN/A p++; 1423447SN/A /* Fall through. */ 1433447SN/A default: 1443447SN/A goto label_prefix; 1453447SN/A } 1463447SN/A } 1473447SN/A 1483447SN/A /* Get prefix, if any. */ 1493447SN/A label_prefix: 1503447SN/A /* 1513447SN/A * Note where the first non-whitespace/sign character is so that it is 1523447SN/A * possible to tell whether any digits are consumed (e.g., " 0" vs. 1533447SN/A * " -x"). 1543447SN/A */ 1553447SN/A ns = p; 1563447SN/A if (*p == '0') { 1573447SN/A switch (p[1]) { 1583447SN/A case '0': case '1': case '2': case '3': case '4': case '5': 1593447SN/A case '6': case '7': 1603447SN/A if (b == 0) 1613447SN/A b = 8; 1623447SN/A if (b == 8) 1633447SN/A p++; 1643447SN/A break; 1653447SN/A case 'x': 1663447SN/A switch (p[2]) { 1673447SN/A case '0': case '1': case '2': case '3': case '4': 1683447SN/A case '5': case '6': case '7': case '8': case '9': 1693447SN/A case 'A': case 'B': case 'C': case 'D': case 'E': 1703447SN/A case 'F': 1713447SN/A case 'a': case 'b': case 'c': case 'd': case 'e': 1723447SN/A case 'f': 1733447SN/A if (b == 0) 1743447SN/A b = 16; 1753447SN/A if (b == 16) 1763447SN/A p += 2; 1773447SN/A break; 1783447SN/A default: 1793447SN/A break; 1803447SN/A } 1813447SN/A break; 1823447SN/A default: 1833447SN/A break; 1843447SN/A } 1853447SN/A } 1863447SN/A if (b == 0) 1873447SN/A b = 10; 1883447SN/A 1893447SN/A /* Convert. */ 1903447SN/A ret = 0; 1913447SN/A while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b) 1923447SN/A || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b) 1933447SN/A || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) { 1943447SN/A uintmax_t pret = ret; 1953447SN/A ret *= b; 1963447SN/A ret += digit; 1973447SN/A if (ret < pret) { 1983447SN/A /* Overflow. */ 1993447SN/A set_errno(ERANGE); 2003447SN/A return (UINTMAX_MAX); 2013447SN/A } 2023447SN/A p++; 2033447SN/A } 2043447SN/A if (neg) 2053447SN/A ret = -ret; 2063447SN/A 2073447SN/A if (endptr != NULL) { 2083447SN/A if (p == ns) { 2093447SN/A /* No characters were converted. */ 2103447SN/A *endptr = (char *)nptr; 2113447SN/A } else 2123447SN/A *endptr = (char *)p; 2133447SN/A } 2143447SN/A 2153447SN/A return (ret); 2163447SN/A} 2173447SN/A 2183447SN/Astatic char * 2193447SN/Au2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) 2203447SN/A{ 2213447SN/A unsigned i; 2223447SN/A 2233447SN/A i = U2S_BUFSIZE - 1; 2243447SN/A s[i] = '\0'; 2253447SN/A switch (base) { 2263447SN/A case 10: 2273447SN/A do { 2283447SN/A i--; 2293447SN/A s[i] = "0123456789"[x % (uint64_t)10]; 2303447SN/A x /= (uint64_t)10; 2313447SN/A } while (x > 0); 2323447SN/A break; 2333447SN/A case 16: { 2343447SN/A const char *digits = (uppercase) 2353447SN/A ? "0123456789ABCDEF" 2363447SN/A : "0123456789abcdef"; 2373447SN/A 2383447SN/A do { 2393447SN/A i--; 2403447SN/A s[i] = digits[x & 0xf]; 2413447SN/A x >>= 4; 2423447SN/A } while (x > 0); 2433447SN/A break; 2443447SN/A } default: { 2453447SN/A const char *digits = (uppercase) 2463447SN/A ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 2473447SN/A : "0123456789abcdefghijklmnopqrstuvwxyz"; 2483447SN/A 2493447SN/A assert(base >= 2 && base <= 36); 2503447SN/A do { 2513447SN/A i--; 2523447SN/A s[i] = digits[x % (uint64_t)base]; 2533447SN/A x /= (uint64_t)base; 2543447SN/A } while (x > 0); 2553447SN/A }} 2563447SN/A 2573447SN/A *slen_p = U2S_BUFSIZE - 1 - i; 2583447SN/A return (&s[i]); 2593447SN/A} 2603447SN/A 2613447SN/Astatic char * 2623447SN/Ad2s(intmax_t x, char sign, char *s, size_t *slen_p) 2633447SN/A{ 2643447SN/A bool neg; 2653447SN/A 2663447SN/A if ((neg = (x < 0))) 2673447SN/A x = -x; 2683447SN/A s = u2s(x, 10, false, s, slen_p); 2693447SN/A if (neg) 2703447SN/A sign = '-'; 2713447SN/A switch (sign) { 2723447SN/A case '-': 2733447SN/A if (neg == false) 2743447SN/A break; 2753447SN/A /* Fall through. */ 2763447SN/A case ' ': 2773447SN/A case '+': 2783447SN/A s--; 2793447SN/A (*slen_p)++; 2803447SN/A *s = sign; 2813447SN/A break; 2823447SN/A default: not_reached(); 2833447SN/A } 2843447SN/A return (s); 2853447SN/A} 2863447SN/A 2873447SN/Astatic char * 2883447SN/Ao2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) 2893447SN/A{ 2903447SN/A 2913447SN/A s = u2s(x, 8, false, s, slen_p); 2923447SN/A if (alt_form && *s != '0') { 2933447SN/A s--; 2943447SN/A (*slen_p)++; 2953447SN/A *s = '0'; 2963447SN/A } 2973447SN/A return (s); 2983447SN/A} 2993447SN/A 3003447SN/Astatic char * 3013447SN/Ax2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) 3023447SN/A{ 3033447SN/A 3043447SN/A s = u2s(x, 16, uppercase, s, slen_p); 3053447SN/A if (alt_form) { 3063447SN/A s -= 2; 3073447SN/A (*slen_p) += 2; 3083447SN/A memcpy(s, uppercase ? "0X" : "0x", 2); 3093447SN/A } 3103447SN/A return (s); 3113447SN/A} 3123447SN/A 3133447SN/Aint 3143447SN/Amalloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) 3153447SN/A{ 3163447SN/A int ret; 3173447SN/A size_t i; 3183447SN/A const char *f; 3193447SN/A 3203447SN/A#define APPEND_C(c) do { \ 3213447SN/A if (i < size) \ 3223447SN/A str[i] = (c); \ 3233447SN/A i++; \ 3243447SN/A} while (0) 3253447SN/A#define APPEND_S(s, slen) do { \ 3263447SN/A if (i < size) { \ 3273447SN/A size_t cpylen = (slen <= size - i) ? slen : size - i; \ 3283447SN/A memcpy(&str[i], s, cpylen); \ 3293447SN/A } \ 3303447SN/A i += slen; \ 3313447SN/A} while (0) 3323447SN/A#define APPEND_PADDED_S(s, slen, width, left_justify) do { \ 3333447SN/A /* Left padding. */ \ 3343447SN/A size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \ 3353447SN/A (size_t)width - slen : 0); \ 3363447SN/A if (left_justify == false && pad_len != 0) { \ 3373447SN/A size_t j; \ 3383447SN/A for (j = 0; j < pad_len; j++) \ 3393447SN/A APPEND_C(' '); \ 3403447SN/A } \ 3413447SN/A /* Value. */ \ 3423447SN/A APPEND_S(s, slen); \ 3433447SN/A /* Right padding. */ \ 3443447SN/A if (left_justify && pad_len != 0) { \ 3453447SN/A size_t j; \ 3463447SN/A for (j = 0; j < pad_len; j++) \ 3473447SN/A APPEND_C(' '); \ 3483447SN/A } \ 3493447SN/A} while (0) 3503447SN/A#define GET_ARG_NUMERIC(val, len) do { \ 3513447SN/A switch (len) { \ 3523447SN/A case '?': \ 3533447SN/A val = va_arg(ap, int); \ 3543447SN/A break; \ 3553447SN/A case '?' | 0x80: \ 3563447SN/A val = va_arg(ap, unsigned int); \ 3573447SN/A break; \ 3583447SN/A case 'l': \ 3593447SN/A val = va_arg(ap, long); \ 3603447SN/A break; \ 3613447SN/A case 'l' | 0x80: \ 3623447SN/A val = va_arg(ap, unsigned long); \ 3633447SN/A break; \ 3643447SN/A case 'q': \ 3653447SN/A val = va_arg(ap, long long); \ 3663447SN/A break; \ 3673447SN/A case 'q' | 0x80: \ 3683447SN/A val = va_arg(ap, unsigned long long); \ 3693447SN/A break; \ 3703447SN/A case 'j': \ 3713447SN/A val = va_arg(ap, intmax_t); \ 3723447SN/A break; \ 3733447SN/A case 't': \ 3743447SN/A val = va_arg(ap, ptrdiff_t); \ 3753447SN/A break; \ 3763447SN/A case 'z': \ 3773447SN/A val = va_arg(ap, ssize_t); \ 3783447SN/A break; \ 3793447SN/A case 'z' | 0x80: \ 3803447SN/A val = va_arg(ap, size_t); \ 3813447SN/A break; \ 3823447SN/A case 'p': /* Synthetic; used for %p. */ \ 3833447SN/A val = va_arg(ap, uintptr_t); \ 3843447SN/A break; \ 3853447SN/A default: not_reached(); \ 3863447SN/A } \ 3873447SN/A} while (0) 3883447SN/A 3893447SN/A i = 0; 3903447SN/A f = format; 3913447SN/A while (true) { 3923447SN/A switch (*f) { 3933447SN/A case '\0': goto label_out; 3943447SN/A case '%': { 3953447SN/A bool alt_form = false; 3963447SN/A bool left_justify = false; 3973447SN/A bool plus_space = false; 3983447SN/A bool plus_plus = false; 3993447SN/A int prec = -1; 4003447SN/A int width = -1; 4013447SN/A unsigned char len = '?'; 4023447SN/A 4033447SN/A f++; 4043447SN/A if (*f == '%') { 4053447SN/A /* %% */ 4063447SN/A APPEND_C(*f); 4073447SN/A break; 4083447SN/A } 4093447SN/A /* Flags. */ 4103447SN/A while (true) { 4113447SN/A switch (*f) { 4123447SN/A case '#': 4133447SN/A assert(alt_form == false); 4143447SN/A alt_form = true; 4153447SN/A break; 4163447SN/A case '-': 4173447SN/A assert(left_justify == false); 4183447SN/A left_justify = true; 4193447SN/A break; 4203447SN/A case ' ': 4213447SN/A assert(plus_space == false); 4223447SN/A plus_space = true; 4233447SN/A break; 4243447SN/A case '+': 4253447SN/A assert(plus_plus == false); 4263447SN/A plus_plus = true; 4273447SN/A break; 4283447SN/A default: goto label_width; 4293447SN/A } 4303447SN/A f++; 4313447SN/A } 4323447SN/A /* Width. */ 4333447SN/A label_width: 4343447SN/A switch (*f) { 4353447SN/A case '*': 4363447SN/A width = va_arg(ap, int); 4373447SN/A f++; 4383447SN/A break; 4393447SN/A case '0': case '1': case '2': case '3': case '4': 4403447SN/A case '5': case '6': case '7': case '8': case '9': { 4413447SN/A uintmax_t uwidth; 4423447SN/A set_errno(0); 4433447SN/A uwidth = malloc_strtoumax(f, (char **)&f, 10); 4443447SN/A assert(uwidth != UINTMAX_MAX || get_errno() != 4453447SN/A ERANGE); 4463447SN/A width = (int)uwidth; 4473447SN/A if (*f == '.') { 4483447SN/A f++; 4493447SN/A goto label_precision; 4503447SN/A } else 4513447SN/A goto label_length; 4523447SN/A break; 4533447SN/A } case '.': 4543447SN/A f++; 4553447SN/A goto label_precision; 4563447SN/A default: goto label_length; 4573447SN/A } 4583447SN/A /* Precision. */ 4593447SN/A label_precision: 4603447SN/A switch (*f) { 4613447SN/A case '*': 4623447SN/A prec = va_arg(ap, int); 4633447SN/A f++; 4643447SN/A break; 4653447SN/A case '0': case '1': case '2': case '3': case '4': 4663447SN/A case '5': case '6': case '7': case '8': case '9': { 4673447SN/A uintmax_t uprec; 4683447SN/A set_errno(0); 4693447SN/A uprec = malloc_strtoumax(f, (char **)&f, 10); 4703447SN/A assert(uprec != UINTMAX_MAX || get_errno() != 4713447SN/A ERANGE); 4723447SN/A prec = (int)uprec; 4733447SN/A break; 4743447SN/A } 4753447SN/A default: break; 4763447SN/A } 4773447SN/A /* Length. */ 4783447SN/A label_length: 4793447SN/A switch (*f) { 4803447SN/A case 'l': 4813447SN/A f++; 4823447SN/A if (*f == 'l') { 4833447SN/A len = 'q'; 4843447SN/A f++; 4853447SN/A } else 4863447SN/A len = 'l'; 4873447SN/A break; 4883447SN/A case 'j': 4893447SN/A len = 'j'; 4903447SN/A f++; 4913447SN/A break; 4923447SN/A case 't': 4933447SN/A len = 't'; 4943447SN/A f++; 4953447SN/A break; 4963447SN/A case 'z': 4973447SN/A len = 'z'; 4983447SN/A f++; 4993447SN/A break; 5003447SN/A default: break; 5013447SN/A } 5023447SN/A /* Conversion specifier. */ 5033447SN/A switch (*f) { 5043447SN/A char *s; 5053447SN/A size_t slen; 5063447SN/A case 'd': case 'i': { 5073447SN/A intmax_t val JEMALLOC_CC_SILENCE_INIT(0); 5083447SN/A char buf[D2S_BUFSIZE]; 5093447SN/A 5103447SN/A GET_ARG_NUMERIC(val, len); 5113447SN/A s = d2s(val, (plus_plus ? '+' : (plus_space ? 5123447SN/A ' ' : '-')), buf, &slen); 5133447SN/A APPEND_PADDED_S(s, slen, width, left_justify); 5143447SN/A f++; 5153447SN/A break; 5163447SN/A } case 'o': { 5173447SN/A uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 5183447SN/A char buf[O2S_BUFSIZE]; 5193447SN/A 5203447SN/A GET_ARG_NUMERIC(val, len | 0x80); 5213447SN/A s = o2s(val, alt_form, buf, &slen); 5223447SN/A APPEND_PADDED_S(s, slen, width, left_justify); 5233447SN/A f++; 5243447SN/A break; 5253447SN/A } case 'u': { 5263447SN/A uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 5273447SN/A char buf[U2S_BUFSIZE]; 5283447SN/A 5293447SN/A GET_ARG_NUMERIC(val, len | 0x80); 5303447SN/A s = u2s(val, 10, false, buf, &slen); 5313447SN/A APPEND_PADDED_S(s, slen, width, left_justify); 5323447SN/A f++; 5333447SN/A break; 5343447SN/A } case 'x': case 'X': { 5353447SN/A uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); 5363447SN/A char buf[X2S_BUFSIZE]; 5373447SN/A 5383447SN/A GET_ARG_NUMERIC(val, len | 0x80); 5393447SN/A s = x2s(val, alt_form, *f == 'X', buf, &slen); 5403447SN/A APPEND_PADDED_S(s, slen, width, left_justify); 5413447SN/A f++; 5423447SN/A break; 5433447SN/A } case 'c': { 5443447SN/A unsigned char val; 5453447SN/A char buf[2]; 5463447SN/A 5473447SN/A assert(len == '?' || len == 'l'); 5483447SN/A assert_not_implemented(len != 'l'); 5493447SN/A val = va_arg(ap, int); 5503447SN/A buf[0] = val; 5513447SN/A buf[1] = '\0'; 5523447SN/A APPEND_PADDED_S(buf, 1, width, left_justify); 5533447SN/A f++; 5543447SN/A break; 5553447SN/A } case 's': 5563447SN/A assert(len == '?' || len == 'l'); 5573447SN/A assert_not_implemented(len != 'l'); 5583447SN/A s = va_arg(ap, char *); 5593447SN/A slen = (prec == -1) ? strlen(s) : prec; 5603447SN/A APPEND_PADDED_S(s, slen, width, left_justify); 5613447SN/A f++; 5623447SN/A break; 5633447SN/A case 'p': { 5643447SN/A uintmax_t val; 5653447SN/A char buf[X2S_BUFSIZE]; 5663447SN/A 5673447SN/A GET_ARG_NUMERIC(val, 'p'); 5683447SN/A s = x2s(val, true, false, buf, &slen); 5693447SN/A APPEND_PADDED_S(s, slen, width, left_justify); 5703447SN/A f++; 5713447SN/A break; 5723447SN/A } 5733447SN/A default: not_implemented(); 5743447SN/A } 575 break; 576 } default: { 577 APPEND_C(*f); 578 f++; 579 break; 580 }} 581 } 582 label_out: 583 if (i < size) 584 str[i] = '\0'; 585 else 586 str[size - 1] = '\0'; 587 ret = i; 588 589#undef APPEND_C 590#undef APPEND_S 591#undef APPEND_PADDED_S 592#undef GET_ARG_NUMERIC 593 return (ret); 594} 595 596JEMALLOC_ATTR(format(printf, 3, 4)) 597int 598malloc_snprintf(char *str, size_t size, const char *format, ...) 599{ 600 int 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 610void 611malloc_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 */ 635JEMALLOC_ATTR(format(printf, 3, 4)) 636void 637malloc_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. */ 648JEMALLOC_ATTR(format(printf, 1, 2)) 649void 650malloc_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