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
);
62 * Wrapper around malloc_message() that avoids the need for
63 * je_malloc_message(...) throughout the code.
66 malloc_write(const char *s
)
69 if (je_malloc_message
!= NULL
)
70 je_malloc_message(NULL
, s
);
76 * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so
80 buferror(char *buf
, size_t buflen
)
84 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(), 0,
85 (LPSTR
)buf
, buflen
, NULL
);
87 #elif defined(_GNU_SOURCE)
88 char *b
= strerror_r(errno
, buf
, buflen
);
90 strncpy(buf
, b
, buflen
);
95 return (strerror_r(errno
, buf
, buflen
));
100 malloc_strtoumax(const char *nptr
, char **endptr
, int base
)
102 uintmax_t ret
, digit
;
107 if (base
< 0 || base
== 1 || base
> 36) {
109 return (UINTMAX_MAX
);
113 /* Swallow leading whitespace and get sign, if any. */
118 case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
132 /* Get prefix, if any. */
135 * Note where the first non-whitespace/sign character is so that it is
136 * possible to tell whether any digits are consumed (e.g., " 0" vs.
142 case '0': case '1': case '2': case '3': case '4': case '5':
151 case '0': case '1': case '2': case '3': case '4':
152 case '5': case '6': case '7': case '8': case '9':
153 case 'A': case 'B': case 'C': case 'D': case 'E':
155 case 'a': case 'b': case 'c': case 'd': case 'e':
175 while ((*p
>= '0' && *p
<= '9' && (digit
= *p
- '0') < b
)
176 || (*p
>= 'A' && *p
<= 'Z' && (digit
= 10 + *p
- 'A') < b
)
177 || (*p
>= 'a' && *p
<= 'z' && (digit
= 10 + *p
- 'a') < b
)) {
178 uintmax_t pret
= ret
;
184 return (UINTMAX_MAX
);
191 if (endptr
!= NULL
) {
193 /* No characters were converted. */
194 *endptr
= (char *)nptr
;
203 u2s(uintmax_t x
, unsigned base
, bool uppercase
, char *s
, size_t *slen_p
)
213 s
[i
] = "0123456789"[x
% (uint64_t)10];
218 const char *digits
= (uppercase
)
220 : "0123456789abcdef";
224 s
[i
] = digits
[x
& 0xf];
229 const char *digits
= (uppercase
)
230 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
231 : "0123456789abcdefghijklmnopqrstuvwxyz";
233 assert(base
>= 2 && base
<= 36);
236 s
[i
] = digits
[x
% (uint64_t)base
];
241 *slen_p
= U2S_BUFSIZE
- 1 - i
;
246 d2s(intmax_t x
, char sign
, char *s
, size_t *slen_p
)
252 s
= u2s(x
, 10, false, s
, slen_p
);
266 default: not_reached();
272 o2s(uintmax_t x
, bool alt_form
, char *s
, size_t *slen_p
)
275 s
= u2s(x
, 8, false, s
, slen_p
);
276 if (alt_form
&& *s
!= '0') {
285 x2s(uintmax_t x
, bool alt_form
, bool uppercase
, char *s
, size_t *slen_p
)
288 s
= u2s(x
, 16, uppercase
, s
, slen_p
);
292 memcpy(s
, uppercase
? "0X" : "0x", 2);
298 malloc_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
)
304 #define APPEND_C(c) do { \
309 #define APPEND_S(s, slen) do { \
311 size_t cpylen = (slen <= size - i) ? slen : size - i; \
312 memcpy(&str[i], s, cpylen); \
316 #define APPEND_PADDED_S(s, slen, width, left_justify) do { \
317 /* Left padding. */ \
318 size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \
319 (size_t)width - slen : 0); \
320 if (left_justify == false && pad_len != 0) { \
322 for (j = 0; j < pad_len; j++) \
327 /* Right padding. */ \
328 if (left_justify && pad_len != 0) { \
330 for (j = 0; j < pad_len; j++) \
334 #define GET_ARG_NUMERIC(val, len) do { \
337 val = va_arg(ap, int); \
340 val = va_arg(ap, unsigned int); \
343 val = va_arg(ap, long); \
346 val = va_arg(ap, unsigned long); \
349 val = va_arg(ap, long long); \
352 val = va_arg(ap, unsigned long long); \
355 val = va_arg(ap, intmax_t); \
358 val = va_arg(ap, ptrdiff_t); \
361 val = va_arg(ap, ssize_t); \
364 val = va_arg(ap, size_t); \
366 case 'p': /* Synthetic; used for %p. */ \
367 val = va_arg(ap, uintptr_t); \
369 default: not_reached(); \
377 case '\0': goto label_out
;
379 bool alt_form
= false;
380 bool zero_pad
= false;
381 bool left_justify
= false;
382 bool plus_space
= false;
383 bool plus_plus
= false;
386 unsigned char len
= '?';
398 assert(alt_form
== false);
402 assert(zero_pad
== false);
406 assert(left_justify
== false);
410 assert(plus_space
== false);
414 assert(plus_plus
== false);
417 default: goto label_width
;
425 width
= va_arg(ap
, int);
428 case '0': case '1': case '2': case '3': case '4':
429 case '5': case '6': case '7': case '8': case '9': {
432 uwidth
= malloc_strtoumax(f
, (char **)&f
, 10);
433 assert(uwidth
!= UINTMAX_MAX
|| get_errno() !=
438 goto label_precision
;
444 goto label_precision
;
445 default: goto label_length
;
451 prec
= va_arg(ap
, int);
454 case '0': case '1': case '2': case '3': case '4':
455 case '5': case '6': case '7': case '8': case '9': {
458 uprec
= malloc_strtoumax(f
, (char **)&f
, 10);
459 assert(uprec
!= UINTMAX_MAX
|| get_errno() !=
491 /* Conversion specifier. */
495 case 'd': case 'i': {
496 intmax_t val
JEMALLOC_CC_SILENCE_INIT(0);
497 char buf
[D2S_BUFSIZE
];
499 GET_ARG_NUMERIC(val
, len
);
500 s
= d2s(val
, (plus_plus
? '+' : (plus_space
?
501 ' ' : '-')), buf
, &slen
);
502 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
506 uintmax_t val
JEMALLOC_CC_SILENCE_INIT(0);
507 char buf
[O2S_BUFSIZE
];
509 GET_ARG_NUMERIC(val
, len
| 0x80);
510 s
= o2s(val
, alt_form
, buf
, &slen
);
511 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
515 uintmax_t val
JEMALLOC_CC_SILENCE_INIT(0);
516 char buf
[U2S_BUFSIZE
];
518 GET_ARG_NUMERIC(val
, len
| 0x80);
519 s
= u2s(val
, 10, false, buf
, &slen
);
520 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
523 } case 'x': case 'X': {
524 uintmax_t val
JEMALLOC_CC_SILENCE_INIT(0);
525 char buf
[X2S_BUFSIZE
];
527 GET_ARG_NUMERIC(val
, len
| 0x80);
528 s
= x2s(val
, alt_form
, *f
== 'X', buf
, &slen
);
529 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
536 assert(len
== '?' || len
== 'l');
537 assert_not_implemented(len
!= 'l');
538 val
= va_arg(ap
, int);
541 APPEND_PADDED_S(buf
, 1, width
, left_justify
);
545 assert(len
== '?' || len
== 'l');
546 assert_not_implemented(len
!= 'l');
547 s
= va_arg(ap
, char *);
548 slen
= (prec
== -1) ? strlen(s
) : prec
;
549 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
554 char buf
[X2S_BUFSIZE
];
556 GET_ARG_NUMERIC(val
, 'p');
557 s
= x2s(val
, true, false, buf
, &slen
);
558 APPEND_PADDED_S(s
, slen
, width
, left_justify
);
562 default: not_implemented();
575 str
[size
- 1] = '\0';
580 #undef APPEND_PADDED_S
581 #undef GET_ARG_NUMERIC
585 JEMALLOC_ATTR(format(printf
, 3, 4))
587 malloc_snprintf(char *str
, size_t size
, const char *format
, ...)
592 va_start(ap
, format
);
593 ret
= malloc_vsnprintf(str
, size
, format
, ap
);
600 malloc_vcprintf(void (*write_cb
)(void *, const char *), void *cbopaque
,
601 const char *format
, va_list ap
)
603 char buf
[MALLOC_PRINTF_BUFSIZE
];
605 if (write_cb
== NULL
) {
607 * The caller did not provide an alternate write_cb callback
608 * function, so use the default one. malloc_write() is an
609 * inline function, so use malloc_message() directly here.
611 write_cb
= (je_malloc_message
!= NULL
) ? je_malloc_message
:
616 malloc_vsnprintf(buf
, sizeof(buf
), format
, ap
);
617 write_cb(cbopaque
, buf
);
621 * Print to a callback function in such a way as to (hopefully) avoid memory
624 JEMALLOC_ATTR(format(printf
, 3, 4))
626 malloc_cprintf(void (*write_cb
)(void *, const char *), void *cbopaque
,
627 const char *format
, ...)
631 va_start(ap
, format
);
632 malloc_vcprintf(write_cb
, cbopaque
, format
, ap
);
636 /* Print to stderr in such a way as to avoid memory allocation. */
637 JEMALLOC_ATTR(format(printf
, 1, 2))
639 malloc_printf(const char *format
, ...)
643 va_start(ap
, format
);
644 malloc_vcprintf(NULL
, NULL
, format
, ap
);