1 #define assert(e) do { \
2 if (config_debug && !(e)) { \
3 malloc_write("<jemalloc>: Failed assertion\n"); \
8 #define not_reached() do { \
10 malloc_write("<jemalloc>: Unreachable code reached\n"); \
15 #define not_implemented() do { \
17 malloc_write("<jemalloc>: Not implemented\n"); \
22 #define JEMALLOC_UTIL_C_
23 #include "jemalloc/internal/jemalloc_internal.h"
25 /******************************************************************************/
26 /* Function prototypes for non-inline static functions. */
28 static void wrtmessage(void *cbopaque, const char *s);
29 #define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1)
30 static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s,
32 #define D2S_BUFSIZE (1 + U2S_BUFSIZE)
33 static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p);
34 #define O2S_BUFSIZE (1 + U2S_BUFSIZE)
35 static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p);
36 #define X2S_BUFSIZE (2 + U2S_BUFSIZE)
37 static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s,
40 /******************************************************************************/
42 /* malloc_message() setup. */
44 wrtmessage(void *cbopaque, const char *s)
49 * Use syscall(2) rather than write(2) when possible in order to avoid
50 * the possibility of memory allocation within libc. This is necessary
51 * on FreeBSD; most operating systems do not have this problem though.
53 UNUSED int result = syscall(SYS_write, STDERR_FILENO, s, strlen(s));
55 UNUSED int result = write(STDERR_FILENO, s, strlen(s));
59 JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s);
61 JEMALLOC_ATTR(visibility("hidden"))
63 wrtmessage_1_0(const char *s1, const char *s2, const char *s3,
73 void (*__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);
78 * Wrapper around malloc_message() that avoids the need for
79 * je_malloc_message(...) throughout the code.
82 malloc_write(const char *s)
85 if (je_malloc_message != NULL)
86 je_malloc_message(NULL, s);
92 * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so
96 buferror(int err, char *buf, size_t buflen)
100 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
101 (LPSTR)buf, buflen, NULL);
103 #elif defined(_GNU_SOURCE)
104 char *b = strerror_r(err, buf, buflen);
106 strncpy(buf, b, buflen);
107 buf[buflen-1] = '\0';
111 return (strerror_r(err, buf, buflen));
116 malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base)
118 uintmax_t ret, digit;
124 if (base < 0 || base == 1 || base > 36) {
132 /* Swallow leading whitespace and get sign, if any. */
136 case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
150 /* Get prefix, if any. */
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.
160 case '0': case '1': case '2': case '3': case '4': case '5':
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':
173 case 'a': case 'b': case 'c': case 'd': case 'e':
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;
213 /* No conversion performed. */
220 if (endptr != NULL) {
222 /* No characters were converted. */
223 *endptr = (char *)nptr;
231 u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p)
241 s[i] = "0123456789"[x % (uint64_t)10];
246 const char *digits = (uppercase)
248 : "0123456789abcdef";
252 s[i] = digits[x & 0xf];
257 const char *digits = (uppercase)
258 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
259 : "0123456789abcdefghijklmnopqrstuvwxyz";
261 assert(base >= 2 && base <= 36);
264 s[i] = digits[x % (uint64_t)base];
269 *slen_p = U2S_BUFSIZE - 1 - i;
274 d2s(intmax_t x, char sign, char *s, size_t *slen_p)
280 s = u2s(x, 10, false, s, slen_p);
294 default: not_reached();
300 o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p)
303 s = u2s(x, 8, false, s, slen_p);
304 if (alt_form && *s != '0') {
313 x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p)
316 s = u2s(x, 16, uppercase, s, slen_p);
320 memcpy(s, uppercase ? "0X" : "0x", 2);
326 malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
332 #define APPEND_C(c) do { \
337 #define APPEND_S(s, slen) do { \
339 size_t cpylen = (slen <= size - i) ? slen : size - i; \
340 memcpy(&str[i], s, cpylen); \
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 == false && pad_len != 0) { \
350 for (j = 0; j < pad_len; j++) \
355 /* Right padding. */ \
356 if (left_justify && pad_len != 0) { \
358 for (j = 0; j < pad_len; j++) \
362 #define GET_ARG_NUMERIC(val, len) do { \
365 val = va_arg(ap, int); \
368 val = va_arg(ap, unsigned int); \
371 val = va_arg(ap, long); \
374 val = va_arg(ap, unsigned long); \
377 val = va_arg(ap, long long); \
380 val = va_arg(ap, unsigned long long); \
383 val = va_arg(ap, intmax_t); \
386 val = va_arg(ap, uintmax_t); \
389 val = va_arg(ap, ptrdiff_t); \
392 val = va_arg(ap, ssize_t); \
395 val = va_arg(ap, size_t); \
397 case 'p': /* Synthetic; used for %p. */ \
398 val = va_arg(ap, uintptr_t); \
400 default: not_reached(); \
408 case '\0': goto label_out;
410 bool alt_form = false;
411 bool left_justify = false;
412 bool plus_space = false;
413 bool plus_plus = false;
416 unsigned char len = '?';
423 assert(alt_form == false);
427 assert(left_justify == false);
431 assert(plus_space == false);
435 assert(plus_plus == false);
438 default: goto label_width;
446 width = va_arg(ap, int);
453 case '0': case '1': case '2': case '3': case '4':
454 case '5': case '6': case '7': case '8': case '9': {
457 uwidth = malloc_strtoumax(f, (char **)&f, 10);
458 assert(uwidth != UINTMAX_MAX || get_errno() !=
465 /* Width/precision separator. */
473 prec = va_arg(ap, int);
476 case '0': case '1': case '2': case '3': case '4':
477 case '5': case '6': case '7': case '8': case '9': {
480 uprec = malloc_strtoumax(f, (char **)&f, 10);
481 assert(uprec != UINTMAX_MAX || get_errno() !=
499 case 'q': case 'j': case 't': case 'z':
505 /* Conversion specifier. */
514 case 'd': case 'i': {
515 intmax_t val JEMALLOC_CC_SILENCE_INIT(0);
516 char buf[D2S_BUFSIZE];
518 GET_ARG_NUMERIC(val, len);
519 s = d2s(val, (plus_plus ? '+' : (plus_space ?
520 ' ' : '-')), buf, &slen);
521 APPEND_PADDED_S(s, slen, width, left_justify);
525 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
526 char buf[O2S_BUFSIZE];
528 GET_ARG_NUMERIC(val, len | 0x80);
529 s = o2s(val, alt_form, buf, &slen);
530 APPEND_PADDED_S(s, slen, width, left_justify);
534 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
535 char buf[U2S_BUFSIZE];
537 GET_ARG_NUMERIC(val, len | 0x80);
538 s = u2s(val, 10, false, buf, &slen);
539 APPEND_PADDED_S(s, slen, width, left_justify);
542 } case 'x': case 'X': {
543 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
544 char buf[X2S_BUFSIZE];
546 GET_ARG_NUMERIC(val, len | 0x80);
547 s = x2s(val, alt_form, *f == 'X', buf, &slen);
548 APPEND_PADDED_S(s, slen, width, left_justify);
555 assert(len == '?' || len == 'l');
556 assert_not_implemented(len != 'l');
557 val = va_arg(ap, int);
560 APPEND_PADDED_S(buf, 1, width, left_justify);
564 assert(len == '?' || len == 'l');
565 assert_not_implemented(len != 'l');
566 s = va_arg(ap, char *);
567 slen = (prec < 0) ? strlen(s) : prec;
568 APPEND_PADDED_S(s, slen, width, left_justify);
573 char buf[X2S_BUFSIZE];
575 GET_ARG_NUMERIC(val, 'p');
576 s = x2s(val, true, false, buf, &slen);
577 APPEND_PADDED_S(s, slen, width, left_justify);
580 } default: not_reached();
593 str[size - 1] = '\0';
598 #undef APPEND_PADDED_S
599 #undef GET_ARG_NUMERIC
603 JEMALLOC_ATTR(format(printf, 3, 4))
605 malloc_snprintf(char *str, size_t size, const char *format, ...)
610 va_start(ap, format);
611 ret = malloc_vsnprintf(str, size, format, ap);
618 malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
619 const char *format, va_list ap)
621 char buf[MALLOC_PRINTF_BUFSIZE];
623 if (write_cb == NULL) {
625 * The caller did not provide an alternate write_cb callback
626 * function, so use the default one. malloc_write() is an
627 * inline function, so use malloc_message() directly here.
629 write_cb = (je_malloc_message != NULL) ? je_malloc_message :
634 malloc_vsnprintf(buf, sizeof(buf), format, ap);
635 write_cb(cbopaque, buf);
639 * Print to a callback function in such a way as to (hopefully) avoid memory
642 JEMALLOC_ATTR(format(printf, 3, 4))
644 malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque,
645 const char *format, ...)
649 va_start(ap, format);
650 malloc_vcprintf(write_cb, cbopaque, format, ap);
654 /* Print to stderr in such a way as to avoid memory allocation. */
655 JEMALLOC_ATTR(format(printf, 1, 2))
657 malloc_printf(const char *format, ...)
661 va_start(ap, format);
662 malloc_vcprintf(NULL, NULL, format, ap);