2 * Define simple versions of assertion macros that won't recurse in case
3 * of assertion failures in malloc_*printf().
5 #define assert(e) do { \
6 if (config_debug && !(e)) { \
7 malloc_write("<jemalloc>: Failed assertion\n"); \
12 #define not_reached() do { \
14 malloc_write("<jemalloc>: Unreachable code reached\n"); \
19 #define not_implemented() do { \
21 malloc_write("<jemalloc>: Not implemented\n"); \
26 #define JEMALLOC_UTIL_C_
27 #include "jemalloc/internal/jemalloc_internal.h"
29 /******************************************************************************/
30 /* Function prototypes for non-inline static functions. */
32 static void wrtmessage(void *cbopaque
, const char *s
);
33 #define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1)
34 static char *u2s(uintmax_t x
, unsigned base
, bool uppercase
, char *s
,
36 #define D2S_BUFSIZE (1 + U2S_BUFSIZE)
37 static char *d2s(intmax_t x
, char sign
, char *s
, size_t *slen_p
);
38 #define O2S_BUFSIZE (1 + U2S_BUFSIZE)
39 static char *o2s(uintmax_t x
, bool alt_form
, char *s
, size_t *slen_p
);
40 #define X2S_BUFSIZE (2 + U2S_BUFSIZE)
41 static char *x2s(uintmax_t x
, bool alt_form
, bool uppercase
, char *s
,
44 /******************************************************************************/
46 /* malloc_message() setup. */
48 wrtmessage(void *cbopaque
, const char *s
)
53 * Use syscall(2) rather than write(2) when possible in order to avoid
54 * the possibility of memory allocation within libc. This is necessary
55 * on FreeBSD; most operating systems do not have this problem though.
57 * syscall() returns long or int, depending on platform, so capture the
58 * unused result in the widest plausible type to avoid compiler
61 UNUSED
long result
= syscall(SYS_write
, STDERR_FILENO
, s
, strlen(s
));
63 UNUSED ssize_t result
= write(STDERR_FILENO
, s
, strlen(s
));
67 JEMALLOC_EXPORT
void (*je_malloc_message
)(void *, const char *s
);
70 * Wrapper around malloc_message() that avoids the need for
71 * je_malloc_message(...) throughout the code.
74 malloc_write(const char *s
)
77 if (je_malloc_message
!= NULL
)
78 je_malloc_message(NULL
, s
);
84 * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so
88 buferror(int err
, char *buf
, size_t buflen
)
92 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, err
, 0,
93 (LPSTR
)buf
, (DWORD
)buflen
, NULL
);
95 #elif defined(__GLIBC__) && defined(_GNU_SOURCE)
96 char *b
= strerror_r(err
, buf
, buflen
);
98 strncpy(buf
, b
, buflen
);
103 return (strerror_r(err
, buf
, buflen
));
108 malloc_strtoumax(const char *restrict nptr
, char **restrict endptr
, int base
)
110 uintmax_t ret
, digit
;
116 if (base
< 0 || base
== 1 || base
> 36) {
124 /* Swallow leading whitespace and get sign, if any. */
128 case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
142 /* Get prefix, if any. */
145 * Note where the first non-whitespace/sign character is so that it is
146 * possible to tell whether any digits are consumed (e.g., " 0" vs.
152 case '0': case '1': case '2': case '3': case '4': case '5':
161 case '0': case '1': case '2': case '3': case '4':
162 case '5': case '6': case '7': case '8': case '9':
163 case 'A': case 'B': case 'C': case 'D': case 'E':
165 case 'a': case 'b': case 'c': case 'd': case 'e':
187 while ((*p
>= '0' && *p
<= '9' && (digit
= *p
- '0') < b
)
188 || (*p
>= 'A' && *p
<= 'Z' && (digit
= 10 + *p
- 'A') < b
)
189 || (*p
>= 'a' && *p
<= 'z' && (digit
= 10 + *p
- 'a') < b
)) {
190 uintmax_t pret
= ret
;
205 /* No conversion performed. */
212 if (endptr
!= NULL
) {
214 /* No characters were converted. */
215 *endptr
= (char *)nptr
;
223 u2s(uintmax_t x
, unsigned base
, bool uppercase
, char *s
, size_t *slen_p
)
233 s
[i
] = "0123456789"[x
% (uint64_t)10];
238 const char *digits
= (uppercase
)
240 : "0123456789abcdef";
244 s
[i
] = digits
[x
& 0xf];
249 const char *digits
= (uppercase
)
250 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
251 : "0123456789abcdefghijklmnopqrstuvwxyz";
253 assert(base
>= 2 && base
<= 36);
256 s
[i
] = digits
[x
% (uint64_t)base
];
261 *slen_p
= U2S_BUFSIZE
- 1 - i
;
266 d2s(intmax_t x
, char sign
, char *s
, size_t *slen_p
)
272 s
= u2s(x
, 10, false, s
, slen_p
);
286 default: not_reached();
292 o2s(uintmax_t x
, bool alt_form
, char *s
, size_t *slen_p
)
295 s
= u2s(x
, 8, false, s
, slen_p
);
296 if (alt_form
&& *s
!= '0') {
305 x2s(uintmax_t x
, bool alt_form
, bool uppercase
, char *s
, size_t *slen_p
)
308 s
= u2s(x
, 16, uppercase
, s
, slen_p
);
312 memcpy(s
, uppercase
? "0X" : "0x", 2);
318 malloc_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
)
324 #define APPEND_C(c) do { \
329 #define APPEND_S(s, slen) do { \
331 size_t cpylen = (slen <= size - i) ? slen : size - i; \
332 memcpy(&str[i], s, cpylen); \
336 #define APPEND_PADDED_S(s, slen, width, left_justify) do { \
337 /* Left padding. */ \
338 size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \
339 (size_t)width - slen : 0); \
340 if (!left_justify && pad_len != 0) { \
342 for (j = 0; j < pad_len; j++) \
347 /* Right padding. */ \
348 if (left_justify && pad_len != 0) { \
350 for (j = 0; j < pad_len; j++) \
354 #define GET_ARG_NUMERIC(val, len) do { \
357 val = va_arg(ap, int); \
360 val = va_arg(ap, unsigned int); \
363 val = va_arg(ap, long); \
366 val = va_arg(ap, unsigned long); \
369 val = va_arg(ap, long long); \
372 val = va_arg(ap, unsigned long long); \
375 val = va_arg(ap, intmax_t); \
378 val = va_arg(ap, uintmax_t); \
381 val = va_arg(ap, ptrdiff_t); \
384 val = va_arg(ap, ssize_t); \
387 val = va_arg(ap, size_t); \
389 case 'p': /* Synthetic; used for %p. */ \
390 val = va_arg(ap, uintptr_t); \
402 case '\0': goto label_out
;
404 bool alt_form
= false;
405 bool left_justify
= false;
406 bool plus_space
= false;
407 bool plus_plus
= false;
410 unsigned char len
= '?';
421 assert(!left_justify
);
432 default: goto label_width
;
440 width
= va_arg(ap
, int);
447 case '0': case '1': case '2': case '3': case '4':
448 case '5': case '6': case '7': case '8': case '9': {
451 uwidth
= malloc_strtoumax(f
, (char **)&f
, 10);
452 assert(uwidth
!= UINTMAX_MAX
|| get_errno() !=
459 /* Width/precision separator. */
467 prec
= va_arg(ap
, int);
470 case '0': case '1': case '2': case '3': case '4':
471 case '5': case '6': case '7': case '8': case '9': {
474 uprec
= malloc_strtoumax(f
, (char **)&f
, 10);
475 assert(uprec
!= UINTMAX_MAX
|| get_errno() !=
493 case 'q': case 'j': case 't': case 'z':
499 /* Conversion specifier. */
508 case 'd': case 'i': {
509 intmax_t val
JEMALLOC_CC_SILENCE_INIT(0);
510 char buf
[D2S_BUFSIZE
];
512 GET_ARG_NUMERIC(val
, len
);
513 s
= d2s(val
, (plus_plus
? '+' : (plus_space
?
514 ' ' : '-')), buf
, &slen
);
515 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
519 uintmax_t val
JEMALLOC_CC_SILENCE_INIT(0);
520 char buf
[O2S_BUFSIZE
];
522 GET_ARG_NUMERIC(val
, len
| 0x80);
523 s
= o2s(val
, alt_form
, buf
, &slen
);
524 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
528 uintmax_t val
JEMALLOC_CC_SILENCE_INIT(0);
529 char buf
[U2S_BUFSIZE
];
531 GET_ARG_NUMERIC(val
, len
| 0x80);
532 s
= u2s(val
, 10, false, buf
, &slen
);
533 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
536 } case 'x': case 'X': {
537 uintmax_t val
JEMALLOC_CC_SILENCE_INIT(0);
538 char buf
[X2S_BUFSIZE
];
540 GET_ARG_NUMERIC(val
, len
| 0x80);
541 s
= x2s(val
, alt_form
, *f
== 'X', buf
, &slen
);
542 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
549 assert(len
== '?' || len
== 'l');
550 assert_not_implemented(len
!= 'l');
551 val
= va_arg(ap
, int);
554 APPEND_PADDED_S(buf
, 1, width
, left_justify
);
558 assert(len
== '?' || len
== 'l');
559 assert_not_implemented(len
!= 'l');
560 s
= va_arg(ap
, char *);
561 slen
= (prec
< 0) ? strlen(s
) : (size_t)prec
;
562 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
567 char buf
[X2S_BUFSIZE
];
569 GET_ARG_NUMERIC(val
, 'p');
570 s
= x2s(val
, true, false, buf
, &slen
);
571 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
574 } default: not_reached();
587 str
[size
- 1] = '\0';
593 #undef APPEND_PADDED_S
594 #undef GET_ARG_NUMERIC
598 JEMALLOC_FORMAT_PRINTF(3, 4)
600 malloc_snprintf(char *str
, size_t size
, const char *format
, ...)
605 va_start(ap
, format
);
606 ret
= malloc_vsnprintf(str
, size
, format
, ap
);
613 malloc_vcprintf(void (*write_cb
)(void *, const char *), void *cbopaque
,
614 const char *format
, va_list ap
)
616 char buf
[MALLOC_PRINTF_BUFSIZE
];
618 if (write_cb
== NULL
) {
620 * The caller did not provide an alternate write_cb callback
621 * function, so use the default one. malloc_write() is an
622 * inline function, so use malloc_message() directly here.
624 write_cb
= (je_malloc_message
!= NULL
) ? je_malloc_message
:
629 malloc_vsnprintf(buf
, sizeof(buf
), format
, ap
);
630 write_cb(cbopaque
, buf
);
634 * Print to a callback function in such a way as to (hopefully) avoid memory
637 JEMALLOC_FORMAT_PRINTF(3, 4)
639 malloc_cprintf(void (*write_cb
)(void *, const char *), void *cbopaque
,
640 const char *format
, ...)
644 va_start(ap
, format
);
645 malloc_vcprintf(write_cb
, cbopaque
, format
, ap
);
649 /* Print to stderr in such a way as to avoid memory allocation. */
650 JEMALLOC_FORMAT_PRINTF(1, 2)
652 malloc_printf(const char *format
, ...)
656 va_start(ap
, format
);
657 malloc_vcprintf(NULL
, NULL
, format
, ap
);
662 * Restore normal assertion macros, in order to make it possible to compile all
663 * C files as a single concatenation.
667 #undef not_implemented
668 #include "jemalloc/internal/assert.h"