1 #define JEMALLOC_MALLOC_IO_C_
2 #include "jemalloc/internal/jemalloc_preamble.h"
3 #include "jemalloc/internal/jemalloc_internal_includes.h"
5 #include "jemalloc/internal/malloc_io.h"
6 #include "jemalloc/internal/util.h"
14 #ifdef not_implemented
15 # undef not_implemented
17 #ifdef assert_not_implemented
18 # undef assert_not_implemented
22 * Define simple versions of assertion macros that won't recurse in case
23 * of assertion failures in malloc_*printf().
25 #define assert(e) do { \
26 if (config_debug && !(e)) { \
27 malloc_write("<jemalloc>: Failed assertion\n"); \
32 #define not_reached() do { \
34 malloc_write("<jemalloc>: Unreachable code reached\n"); \
40 #define not_implemented() do { \
42 malloc_write("<jemalloc>: Not implemented\n"); \
47 #define assert_not_implemented(e) do { \
48 if (unlikely(config_debug && !(e))) { \
53 /******************************************************************************/
54 /* Function prototypes for non-inline static functions. */
56 static void wrtmessage(void *cbopaque, const char *s);
57 #define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1)
58 static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s,
60 #define D2S_BUFSIZE (1 + U2S_BUFSIZE)
61 static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p);
62 #define O2S_BUFSIZE (1 + U2S_BUFSIZE)
63 static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p);
64 #define X2S_BUFSIZE (2 + U2S_BUFSIZE)
65 static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s,
68 /******************************************************************************/
70 /* malloc_message() setup. */
72 wrtmessage(void *cbopaque, const char *s) {
73 #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_write)
75 * Use syscall(2) rather than write(2) when possible in order to avoid
76 * the possibility of memory allocation within libc. This is necessary
77 * on FreeBSD; most operating systems do not have this problem though.
79 * syscall() returns long or int, depending on platform, so capture the
80 * unused result in the widest plausible type to avoid compiler
83 UNUSED long result = syscall(SYS_write, STDERR_FILENO, s, strlen(s));
85 UNUSED ssize_t result = write(STDERR_FILENO, s, strlen(s));
89 JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s);
91 JEMALLOC_ATTR(visibility("hidden"))
93 wrtmessage_1_0(const char *s1, const char *s2, const char *s3, const char *s4) {
101 void (*__malloc_message_1_0)(const char *s1, const char *s2, const char *s3,
102 const char *s4) = wrtmessage_1_0;
103 __sym_compat(_malloc_message, __malloc_message_1_0, FBSD_1.0);
106 * Wrapper around malloc_message() that avoids the need for
107 * je_malloc_message(...) throughout the code.
110 malloc_write(const char *s) {
111 if (je_malloc_message != NULL) {
112 je_malloc_message(NULL, s);
119 * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so
123 buferror(int err, char *buf, size_t buflen) {
125 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0,
126 (LPSTR)buf, (DWORD)buflen, NULL);
128 #elif defined(__GLIBC__) && defined(_GNU_SOURCE)
129 char *b = strerror_r(err, buf, buflen);
131 strncpy(buf, b, buflen);
132 buf[buflen-1] = '\0';
136 return strerror_r(err, buf, buflen);
141 malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) {
142 uintmax_t ret, digit;
148 if (base < 0 || base == 1 || base > 36) {
156 /* Swallow leading whitespace and get sign, if any. */
160 case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
174 /* Get prefix, if any. */
177 * Note where the first non-whitespace/sign character is so that it is
178 * possible to tell whether any digits are consumed (e.g., " 0" vs.
184 case '0': case '1': case '2': case '3': case '4': case '5':
195 case '0': case '1': case '2': case '3': case '4':
196 case '5': case '6': case '7': case '8': case '9':
197 case 'A': case 'B': case 'C': case 'D': case 'E':
199 case 'a': case 'b': case 'c': case 'd': case 'e':
224 while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b)
225 || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b)
226 || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) {
227 uintmax_t pret = ret;
239 ret = (uintmax_t)(-((intmax_t)ret));
243 /* No conversion performed. */
250 if (endptr != NULL) {
252 /* No characters were converted. */
253 *endptr = (char *)nptr;
262 u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) {
271 s[i] = "0123456789"[x % (uint64_t)10];
276 const char *digits = (uppercase)
278 : "0123456789abcdef";
282 s[i] = digits[x & 0xf];
287 const char *digits = (uppercase)
288 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
289 : "0123456789abcdefghijklmnopqrstuvwxyz";
291 assert(base >= 2 && base <= 36);
294 s[i] = digits[x % (uint64_t)base];
299 *slen_p = U2S_BUFSIZE - 1 - i;
304 d2s(intmax_t x, char sign, char *s, size_t *slen_p) {
307 if ((neg = (x < 0))) {
310 s = u2s(x, 10, false, s, slen_p);
326 default: not_reached();
332 o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) {
333 s = u2s(x, 8, false, s, slen_p);
334 if (alt_form && *s != '0') {
343 x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) {
344 s = u2s(x, 16, uppercase, s, slen_p);
348 memcpy(s, uppercase ? "0X" : "0x", 2);
354 malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
358 #define APPEND_C(c) do { \
364 #define APPEND_S(s, slen) do { \
366 size_t cpylen = (slen <= size - i) ? slen : size - i; \
367 memcpy(&str[i], s, cpylen); \
371 #define APPEND_PADDED_S(s, slen, width, left_justify) do { \
372 /* Left padding. */ \
373 size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \
374 (size_t)width - slen : 0); \
375 if (!left_justify && pad_len != 0) { \
377 for (j = 0; j < pad_len; j++) { \
383 /* Right padding. */ \
384 if (left_justify && pad_len != 0) { \
386 for (j = 0; j < pad_len; j++) { \
391 #define GET_ARG_NUMERIC(val, len) do { \
394 val = va_arg(ap, int); \
397 val = va_arg(ap, unsigned int); \
400 val = va_arg(ap, long); \
403 val = va_arg(ap, unsigned long); \
406 val = va_arg(ap, long long); \
409 val = va_arg(ap, unsigned long long); \
412 val = va_arg(ap, intmax_t); \
415 val = va_arg(ap, uintmax_t); \
418 val = va_arg(ap, ptrdiff_t); \
421 val = va_arg(ap, ssize_t); \
424 val = va_arg(ap, size_t); \
426 case 'p': /* Synthetic; used for %p. */ \
427 val = va_arg(ap, uintptr_t); \
439 case '\0': goto label_out;
441 bool alt_form = false;
442 bool left_justify = false;
443 bool plus_space = false;
444 bool plus_plus = false;
447 unsigned char len = '?';
460 assert(!left_justify);
471 default: goto label_width;
479 width = va_arg(ap, int);
486 case '0': case '1': case '2': case '3': case '4':
487 case '5': case '6': case '7': case '8': case '9': {
490 uwidth = malloc_strtoumax(f, (char **)&f, 10);
491 assert(uwidth != UINTMAX_MAX || get_errno() !=
498 /* Width/precision separator. */
507 prec = va_arg(ap, int);
510 case '0': case '1': case '2': case '3': case '4':
511 case '5': case '6': case '7': case '8': case '9': {
514 uprec = malloc_strtoumax(f, (char **)&f, 10);
515 assert(uprec != UINTMAX_MAX || get_errno() !=
534 case 'q': case 'j': case 't': case 'z':
540 /* Conversion specifier. */
547 case 'd': case 'i': {
548 intmax_t val JEMALLOC_CC_SILENCE_INIT(0);
549 char buf[D2S_BUFSIZE];
551 GET_ARG_NUMERIC(val, len);
552 s = d2s(val, (plus_plus ? '+' : (plus_space ?
553 ' ' : '-')), buf, &slen);
554 APPEND_PADDED_S(s, slen, width, left_justify);
558 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
559 char buf[O2S_BUFSIZE];
561 GET_ARG_NUMERIC(val, len | 0x80);
562 s = o2s(val, alt_form, buf, &slen);
563 APPEND_PADDED_S(s, slen, width, left_justify);
567 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
568 char buf[U2S_BUFSIZE];
570 GET_ARG_NUMERIC(val, len | 0x80);
571 s = u2s(val, 10, false, buf, &slen);
572 APPEND_PADDED_S(s, slen, width, left_justify);
575 } case 'x': case 'X': {
576 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
577 char buf[X2S_BUFSIZE];
579 GET_ARG_NUMERIC(val, len | 0x80);
580 s = x2s(val, alt_form, *f == 'X', buf, &slen);
581 APPEND_PADDED_S(s, slen, width, left_justify);
588 assert(len == '?' || len == 'l');
589 assert_not_implemented(len != 'l');
590 val = va_arg(ap, int);
593 APPEND_PADDED_S(buf, 1, width, left_justify);
597 assert(len == '?' || len == 'l');
598 assert_not_implemented(len != 'l');
599 s = va_arg(ap, char *);
600 slen = (prec < 0) ? strlen(s) : (size_t)prec;
601 APPEND_PADDED_S(s, slen, width, left_justify);
606 char buf[X2S_BUFSIZE];
608 GET_ARG_NUMERIC(val, 'p');
609 s = x2s(val, true, false, buf, &slen);
610 APPEND_PADDED_S(s, slen, width, left_justify);
613 } default: not_reached();
626 str[size - 1] = '\0';
631 #undef APPEND_PADDED_S
632 #undef GET_ARG_NUMERIC
636 JEMALLOC_FORMAT_PRINTF(3, 4)
638 malloc_snprintf(char *str, size_t size, const char *format, ...) {
642 va_start(ap, format);
643 ret = malloc_vsnprintf(str, size, format, ap);
650 malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
651 const char *format, va_list ap) {
652 char buf[MALLOC_PRINTF_BUFSIZE];
654 if (write_cb == NULL) {
656 * The caller did not provide an alternate write_cb callback
657 * function, so use the default one. malloc_write() is an
658 * inline function, so use malloc_message() directly here.
660 write_cb = (je_malloc_message != NULL) ? je_malloc_message :
665 malloc_vsnprintf(buf, sizeof(buf), format, ap);
666 write_cb(cbopaque, buf);
670 * Print to a callback function in such a way as to (hopefully) avoid memory
673 JEMALLOC_FORMAT_PRINTF(3, 4)
675 malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque,
676 const char *format, ...) {
679 va_start(ap, format);
680 malloc_vcprintf(write_cb, cbopaque, format, ap);
684 /* Print to stderr in such a way as to avoid memory allocation. */
685 JEMALLOC_FORMAT_PRINTF(1, 2)
687 malloc_printf(const char *format, ...) {
690 va_start(ap, format);
691 malloc_vcprintf(NULL, NULL, format, ap);
696 * Restore normal assertion macros, in order to make it possible to compile all
697 * C files as a single concatenation.
701 #undef not_implemented
702 #undef assert_not_implemented
703 #include "jemalloc/internal/assert.h"