1b7eaed25SJason Evans #define JEMALLOC_MALLOC_IO_C_
2b7eaed25SJason Evans #include "jemalloc/internal/jemalloc_preamble.h"
3b7eaed25SJason Evans #include "jemalloc/internal/jemalloc_internal_includes.h"
4b7eaed25SJason Evans
5b7eaed25SJason Evans #include "jemalloc/internal/malloc_io.h"
6b7eaed25SJason Evans #include "jemalloc/internal/util.h"
7b7eaed25SJason Evans
8b7eaed25SJason Evans #ifdef assert
9b7eaed25SJason Evans # undef assert
10b7eaed25SJason Evans #endif
11b7eaed25SJason Evans #ifdef not_reached
12b7eaed25SJason Evans # undef not_reached
13b7eaed25SJason Evans #endif
14b7eaed25SJason Evans #ifdef not_implemented
15b7eaed25SJason Evans # undef not_implemented
16b7eaed25SJason Evans #endif
17b7eaed25SJason Evans #ifdef assert_not_implemented
18b7eaed25SJason Evans # undef assert_not_implemented
19b7eaed25SJason Evans #endif
20b7eaed25SJason Evans
21b7eaed25SJason Evans /*
22b7eaed25SJason Evans * Define simple versions of assertion macros that won't recurse in case
23b7eaed25SJason Evans * of assertion failures in malloc_*printf().
24b7eaed25SJason Evans */
25b7eaed25SJason Evans #define assert(e) do { \
26b7eaed25SJason Evans if (config_debug && !(e)) { \
27b7eaed25SJason Evans malloc_write("<jemalloc>: Failed assertion\n"); \
28b7eaed25SJason Evans abort(); \
29b7eaed25SJason Evans } \
30b7eaed25SJason Evans } while (0)
31b7eaed25SJason Evans
32b7eaed25SJason Evans #define not_reached() do { \
33b7eaed25SJason Evans if (config_debug) { \
34b7eaed25SJason Evans malloc_write("<jemalloc>: Unreachable code reached\n"); \
35b7eaed25SJason Evans abort(); \
36b7eaed25SJason Evans } \
37b7eaed25SJason Evans unreachable(); \
38b7eaed25SJason Evans } while (0)
39b7eaed25SJason Evans
40b7eaed25SJason Evans #define not_implemented() do { \
41b7eaed25SJason Evans if (config_debug) { \
42b7eaed25SJason Evans malloc_write("<jemalloc>: Not implemented\n"); \
43b7eaed25SJason Evans abort(); \
44b7eaed25SJason Evans } \
45b7eaed25SJason Evans } while (0)
46b7eaed25SJason Evans
47b7eaed25SJason Evans #define assert_not_implemented(e) do { \
48b7eaed25SJason Evans if (unlikely(config_debug && !(e))) { \
49b7eaed25SJason Evans not_implemented(); \
50b7eaed25SJason Evans } \
51b7eaed25SJason Evans } while (0)
52b7eaed25SJason Evans
53b7eaed25SJason Evans /******************************************************************************/
54b7eaed25SJason Evans /* Function prototypes for non-inline static functions. */
55b7eaed25SJason Evans
56b7eaed25SJason Evans static void wrtmessage(void *cbopaque, const char *s);
57b7eaed25SJason Evans #define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1)
58b7eaed25SJason Evans static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s,
59b7eaed25SJason Evans size_t *slen_p);
60b7eaed25SJason Evans #define D2S_BUFSIZE (1 + U2S_BUFSIZE)
61b7eaed25SJason Evans static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p);
62b7eaed25SJason Evans #define O2S_BUFSIZE (1 + U2S_BUFSIZE)
63b7eaed25SJason Evans static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p);
64b7eaed25SJason Evans #define X2S_BUFSIZE (2 + U2S_BUFSIZE)
65b7eaed25SJason Evans static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s,
66b7eaed25SJason Evans size_t *slen_p);
67b7eaed25SJason Evans
68b7eaed25SJason Evans /******************************************************************************/
69b7eaed25SJason Evans
70b7eaed25SJason Evans /* malloc_message() setup. */
71b7eaed25SJason Evans static void
wrtmessage(void * cbopaque,const char * s)72b7eaed25SJason Evans wrtmessage(void *cbopaque, const char *s) {
730ef50b4eSJason Evans malloc_write_fd(STDERR_FILENO, s, strlen(s));
74b7eaed25SJason Evans }
75b7eaed25SJason Evans
76b7eaed25SJason Evans JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s);
77b7eaed25SJason Evans
78b7eaed25SJason Evans JEMALLOC_ATTR(visibility("hidden"))
79b7eaed25SJason Evans void
wrtmessage_1_0(const char * s1,const char * s2,const char * s3,const char * s4)80b7eaed25SJason Evans wrtmessage_1_0(const char *s1, const char *s2, const char *s3, const char *s4) {
81b7eaed25SJason Evans
82b7eaed25SJason Evans wrtmessage(NULL, s1);
83b7eaed25SJason Evans wrtmessage(NULL, s2);
84b7eaed25SJason Evans wrtmessage(NULL, s3);
85b7eaed25SJason Evans wrtmessage(NULL, s4);
86b7eaed25SJason Evans }
87b7eaed25SJason Evans
88b7eaed25SJason Evans void (*__malloc_message_1_0)(const char *s1, const char *s2, const char *s3,
89b7eaed25SJason Evans const char *s4) = wrtmessage_1_0;
90b7eaed25SJason Evans __sym_compat(_malloc_message, __malloc_message_1_0, FBSD_1.0);
91b7eaed25SJason Evans
92b7eaed25SJason Evans /*
93b7eaed25SJason Evans * Wrapper around malloc_message() that avoids the need for
94b7eaed25SJason Evans * je_malloc_message(...) throughout the code.
95b7eaed25SJason Evans */
96b7eaed25SJason Evans void
malloc_write(const char * s)97b7eaed25SJason Evans malloc_write(const char *s) {
98b7eaed25SJason Evans if (je_malloc_message != NULL) {
99b7eaed25SJason Evans je_malloc_message(NULL, s);
100b7eaed25SJason Evans } else {
101b7eaed25SJason Evans wrtmessage(NULL, s);
102b7eaed25SJason Evans }
103b7eaed25SJason Evans }
104b7eaed25SJason Evans
105b7eaed25SJason Evans /*
106b7eaed25SJason Evans * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so
107b7eaed25SJason Evans * provide a wrapper.
108b7eaed25SJason Evans */
109b7eaed25SJason Evans int
buferror(int err,char * buf,size_t buflen)110b7eaed25SJason Evans buferror(int err, char *buf, size_t buflen) {
111b7eaed25SJason Evans #ifdef _WIN32
112b7eaed25SJason Evans FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0,
113b7eaed25SJason Evans (LPSTR)buf, (DWORD)buflen, NULL);
114b7eaed25SJason Evans return 0;
1150ef50b4eSJason Evans #elif defined(JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE) && defined(_GNU_SOURCE)
116b7eaed25SJason Evans char *b = strerror_r(err, buf, buflen);
117b7eaed25SJason Evans if (b != buf) {
118b7eaed25SJason Evans strncpy(buf, b, buflen);
119b7eaed25SJason Evans buf[buflen-1] = '\0';
120b7eaed25SJason Evans }
121b7eaed25SJason Evans return 0;
122b7eaed25SJason Evans #else
123b7eaed25SJason Evans return strerror_r(err, buf, buflen);
124b7eaed25SJason Evans #endif
125b7eaed25SJason Evans }
126b7eaed25SJason Evans
127b7eaed25SJason Evans uintmax_t
malloc_strtoumax(const char * restrict nptr,char ** restrict endptr,int base)128b7eaed25SJason Evans malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) {
129b7eaed25SJason Evans uintmax_t ret, digit;
130b7eaed25SJason Evans unsigned b;
131b7eaed25SJason Evans bool neg;
132b7eaed25SJason Evans const char *p, *ns;
133b7eaed25SJason Evans
134b7eaed25SJason Evans p = nptr;
135b7eaed25SJason Evans if (base < 0 || base == 1 || base > 36) {
136b7eaed25SJason Evans ns = p;
137b7eaed25SJason Evans set_errno(EINVAL);
138b7eaed25SJason Evans ret = UINTMAX_MAX;
139b7eaed25SJason Evans goto label_return;
140b7eaed25SJason Evans }
141b7eaed25SJason Evans b = base;
142b7eaed25SJason Evans
143b7eaed25SJason Evans /* Swallow leading whitespace and get sign, if any. */
144b7eaed25SJason Evans neg = false;
145b7eaed25SJason Evans while (true) {
146b7eaed25SJason Evans switch (*p) {
147b7eaed25SJason Evans case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
148b7eaed25SJason Evans p++;
149b7eaed25SJason Evans break;
150b7eaed25SJason Evans case '-':
151b7eaed25SJason Evans neg = true;
152b7eaed25SJason Evans /* Fall through. */
153b7eaed25SJason Evans case '+':
154b7eaed25SJason Evans p++;
155b7eaed25SJason Evans /* Fall through. */
156b7eaed25SJason Evans default:
157b7eaed25SJason Evans goto label_prefix;
158b7eaed25SJason Evans }
159b7eaed25SJason Evans }
160b7eaed25SJason Evans
161b7eaed25SJason Evans /* Get prefix, if any. */
162b7eaed25SJason Evans label_prefix:
163b7eaed25SJason Evans /*
164b7eaed25SJason Evans * Note where the first non-whitespace/sign character is so that it is
165b7eaed25SJason Evans * possible to tell whether any digits are consumed (e.g., " 0" vs.
166b7eaed25SJason Evans * " -x").
167b7eaed25SJason Evans */
168b7eaed25SJason Evans ns = p;
169b7eaed25SJason Evans if (*p == '0') {
170b7eaed25SJason Evans switch (p[1]) {
171b7eaed25SJason Evans case '0': case '1': case '2': case '3': case '4': case '5':
172b7eaed25SJason Evans case '6': case '7':
173b7eaed25SJason Evans if (b == 0) {
174b7eaed25SJason Evans b = 8;
175b7eaed25SJason Evans }
176b7eaed25SJason Evans if (b == 8) {
177b7eaed25SJason Evans p++;
178b7eaed25SJason Evans }
179b7eaed25SJason Evans break;
180b7eaed25SJason Evans case 'X': case 'x':
181b7eaed25SJason Evans switch (p[2]) {
182b7eaed25SJason Evans case '0': case '1': case '2': case '3': case '4':
183b7eaed25SJason Evans case '5': case '6': case '7': case '8': case '9':
184b7eaed25SJason Evans case 'A': case 'B': case 'C': case 'D': case 'E':
185b7eaed25SJason Evans case 'F':
186b7eaed25SJason Evans case 'a': case 'b': case 'c': case 'd': case 'e':
187b7eaed25SJason Evans case 'f':
188b7eaed25SJason Evans if (b == 0) {
189b7eaed25SJason Evans b = 16;
190b7eaed25SJason Evans }
191b7eaed25SJason Evans if (b == 16) {
192b7eaed25SJason Evans p += 2;
193b7eaed25SJason Evans }
194b7eaed25SJason Evans break;
195b7eaed25SJason Evans default:
196b7eaed25SJason Evans break;
197b7eaed25SJason Evans }
198b7eaed25SJason Evans break;
199b7eaed25SJason Evans default:
200b7eaed25SJason Evans p++;
201b7eaed25SJason Evans ret = 0;
202b7eaed25SJason Evans goto label_return;
203b7eaed25SJason Evans }
204b7eaed25SJason Evans }
205b7eaed25SJason Evans if (b == 0) {
206b7eaed25SJason Evans b = 10;
207b7eaed25SJason Evans }
208b7eaed25SJason Evans
209b7eaed25SJason Evans /* Convert. */
210b7eaed25SJason Evans ret = 0;
211b7eaed25SJason Evans while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b)
212b7eaed25SJason Evans || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b)
213b7eaed25SJason Evans || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) {
214b7eaed25SJason Evans uintmax_t pret = ret;
215b7eaed25SJason Evans ret *= b;
216b7eaed25SJason Evans ret += digit;
217b7eaed25SJason Evans if (ret < pret) {
218b7eaed25SJason Evans /* Overflow. */
219b7eaed25SJason Evans set_errno(ERANGE);
220b7eaed25SJason Evans ret = UINTMAX_MAX;
221b7eaed25SJason Evans goto label_return;
222b7eaed25SJason Evans }
223b7eaed25SJason Evans p++;
224b7eaed25SJason Evans }
225b7eaed25SJason Evans if (neg) {
226b7eaed25SJason Evans ret = (uintmax_t)(-((intmax_t)ret));
227b7eaed25SJason Evans }
228b7eaed25SJason Evans
229b7eaed25SJason Evans if (p == ns) {
230b7eaed25SJason Evans /* No conversion performed. */
231b7eaed25SJason Evans set_errno(EINVAL);
232b7eaed25SJason Evans ret = UINTMAX_MAX;
233b7eaed25SJason Evans goto label_return;
234b7eaed25SJason Evans }
235b7eaed25SJason Evans
236b7eaed25SJason Evans label_return:
237b7eaed25SJason Evans if (endptr != NULL) {
238b7eaed25SJason Evans if (p == ns) {
239b7eaed25SJason Evans /* No characters were converted. */
240b7eaed25SJason Evans *endptr = (char *)nptr;
241b7eaed25SJason Evans } else {
242b7eaed25SJason Evans *endptr = (char *)p;
243b7eaed25SJason Evans }
244b7eaed25SJason Evans }
245b7eaed25SJason Evans return ret;
246b7eaed25SJason Evans }
247b7eaed25SJason Evans
248b7eaed25SJason Evans static char *
u2s(uintmax_t x,unsigned base,bool uppercase,char * s,size_t * slen_p)249b7eaed25SJason Evans u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) {
250b7eaed25SJason Evans unsigned i;
251b7eaed25SJason Evans
252b7eaed25SJason Evans i = U2S_BUFSIZE - 1;
253b7eaed25SJason Evans s[i] = '\0';
254b7eaed25SJason Evans switch (base) {
255b7eaed25SJason Evans case 10:
256b7eaed25SJason Evans do {
257b7eaed25SJason Evans i--;
258b7eaed25SJason Evans s[i] = "0123456789"[x % (uint64_t)10];
259b7eaed25SJason Evans x /= (uint64_t)10;
260b7eaed25SJason Evans } while (x > 0);
261b7eaed25SJason Evans break;
262b7eaed25SJason Evans case 16: {
263b7eaed25SJason Evans const char *digits = (uppercase)
264b7eaed25SJason Evans ? "0123456789ABCDEF"
265b7eaed25SJason Evans : "0123456789abcdef";
266b7eaed25SJason Evans
267b7eaed25SJason Evans do {
268b7eaed25SJason Evans i--;
269b7eaed25SJason Evans s[i] = digits[x & 0xf];
270b7eaed25SJason Evans x >>= 4;
271b7eaed25SJason Evans } while (x > 0);
272b7eaed25SJason Evans break;
273b7eaed25SJason Evans } default: {
274b7eaed25SJason Evans const char *digits = (uppercase)
275b7eaed25SJason Evans ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
276b7eaed25SJason Evans : "0123456789abcdefghijklmnopqrstuvwxyz";
277b7eaed25SJason Evans
278b7eaed25SJason Evans assert(base >= 2 && base <= 36);
279b7eaed25SJason Evans do {
280b7eaed25SJason Evans i--;
281b7eaed25SJason Evans s[i] = digits[x % (uint64_t)base];
282b7eaed25SJason Evans x /= (uint64_t)base;
283b7eaed25SJason Evans } while (x > 0);
284b7eaed25SJason Evans }}
285b7eaed25SJason Evans
286b7eaed25SJason Evans *slen_p = U2S_BUFSIZE - 1 - i;
287b7eaed25SJason Evans return &s[i];
288b7eaed25SJason Evans }
289b7eaed25SJason Evans
290b7eaed25SJason Evans static char *
d2s(intmax_t x,char sign,char * s,size_t * slen_p)291b7eaed25SJason Evans d2s(intmax_t x, char sign, char *s, size_t *slen_p) {
292b7eaed25SJason Evans bool neg;
293b7eaed25SJason Evans
294b7eaed25SJason Evans if ((neg = (x < 0))) {
295b7eaed25SJason Evans x = -x;
296b7eaed25SJason Evans }
297b7eaed25SJason Evans s = u2s(x, 10, false, s, slen_p);
298b7eaed25SJason Evans if (neg) {
299b7eaed25SJason Evans sign = '-';
300b7eaed25SJason Evans }
301b7eaed25SJason Evans switch (sign) {
302b7eaed25SJason Evans case '-':
303b7eaed25SJason Evans if (!neg) {
304b7eaed25SJason Evans break;
305b7eaed25SJason Evans }
306b7eaed25SJason Evans /* Fall through. */
307b7eaed25SJason Evans case ' ':
308b7eaed25SJason Evans case '+':
309b7eaed25SJason Evans s--;
310b7eaed25SJason Evans (*slen_p)++;
311b7eaed25SJason Evans *s = sign;
312b7eaed25SJason Evans break;
313b7eaed25SJason Evans default: not_reached();
314b7eaed25SJason Evans }
315b7eaed25SJason Evans return s;
316b7eaed25SJason Evans }
317b7eaed25SJason Evans
318b7eaed25SJason Evans static char *
o2s(uintmax_t x,bool alt_form,char * s,size_t * slen_p)319b7eaed25SJason Evans o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) {
320b7eaed25SJason Evans s = u2s(x, 8, false, s, slen_p);
321b7eaed25SJason Evans if (alt_form && *s != '0') {
322b7eaed25SJason Evans s--;
323b7eaed25SJason Evans (*slen_p)++;
324b7eaed25SJason Evans *s = '0';
325b7eaed25SJason Evans }
326b7eaed25SJason Evans return s;
327b7eaed25SJason Evans }
328b7eaed25SJason Evans
329b7eaed25SJason Evans static char *
x2s(uintmax_t x,bool alt_form,bool uppercase,char * s,size_t * slen_p)330b7eaed25SJason Evans x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) {
331b7eaed25SJason Evans s = u2s(x, 16, uppercase, s, slen_p);
332b7eaed25SJason Evans if (alt_form) {
333b7eaed25SJason Evans s -= 2;
334b7eaed25SJason Evans (*slen_p) += 2;
335b7eaed25SJason Evans memcpy(s, uppercase ? "0X" : "0x", 2);
336b7eaed25SJason Evans }
337b7eaed25SJason Evans return s;
338b7eaed25SJason Evans }
339b7eaed25SJason Evans
340b7eaed25SJason Evans size_t
malloc_vsnprintf(char * str,size_t size,const char * format,va_list ap)341b7eaed25SJason Evans malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
342b7eaed25SJason Evans size_t i;
343b7eaed25SJason Evans const char *f;
344b7eaed25SJason Evans
345b7eaed25SJason Evans #define APPEND_C(c) do { \
346b7eaed25SJason Evans if (i < size) { \
347b7eaed25SJason Evans str[i] = (c); \
348b7eaed25SJason Evans } \
349b7eaed25SJason Evans i++; \
350b7eaed25SJason Evans } while (0)
351b7eaed25SJason Evans #define APPEND_S(s, slen) do { \
352b7eaed25SJason Evans if (i < size) { \
353b7eaed25SJason Evans size_t cpylen = (slen <= size - i) ? slen : size - i; \
354b7eaed25SJason Evans memcpy(&str[i], s, cpylen); \
355b7eaed25SJason Evans } \
356b7eaed25SJason Evans i += slen; \
357b7eaed25SJason Evans } while (0)
358b7eaed25SJason Evans #define APPEND_PADDED_S(s, slen, width, left_justify) do { \
359b7eaed25SJason Evans /* Left padding. */ \
360b7eaed25SJason Evans size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \
361b7eaed25SJason Evans (size_t)width - slen : 0); \
362b7eaed25SJason Evans if (!left_justify && pad_len != 0) { \
363b7eaed25SJason Evans size_t j; \
364b7eaed25SJason Evans for (j = 0; j < pad_len; j++) { \
365b7eaed25SJason Evans APPEND_C(' '); \
366b7eaed25SJason Evans } \
367b7eaed25SJason Evans } \
368b7eaed25SJason Evans /* Value. */ \
369b7eaed25SJason Evans APPEND_S(s, slen); \
370b7eaed25SJason Evans /* Right padding. */ \
371b7eaed25SJason Evans if (left_justify && pad_len != 0) { \
372b7eaed25SJason Evans size_t j; \
373b7eaed25SJason Evans for (j = 0; j < pad_len; j++) { \
374b7eaed25SJason Evans APPEND_C(' '); \
375b7eaed25SJason Evans } \
376b7eaed25SJason Evans } \
377b7eaed25SJason Evans } while (0)
378b7eaed25SJason Evans #define GET_ARG_NUMERIC(val, len) do { \
379*79457a8aSRyan Libby switch ((unsigned char)len) { \
380b7eaed25SJason Evans case '?': \
381b7eaed25SJason Evans val = va_arg(ap, int); \
382b7eaed25SJason Evans break; \
383b7eaed25SJason Evans case '?' | 0x80: \
384b7eaed25SJason Evans val = va_arg(ap, unsigned int); \
385b7eaed25SJason Evans break; \
386b7eaed25SJason Evans case 'l': \
387b7eaed25SJason Evans val = va_arg(ap, long); \
388b7eaed25SJason Evans break; \
389b7eaed25SJason Evans case 'l' | 0x80: \
390b7eaed25SJason Evans val = va_arg(ap, unsigned long); \
391b7eaed25SJason Evans break; \
392b7eaed25SJason Evans case 'q': \
393b7eaed25SJason Evans val = va_arg(ap, long long); \
394b7eaed25SJason Evans break; \
395b7eaed25SJason Evans case 'q' | 0x80: \
396b7eaed25SJason Evans val = va_arg(ap, unsigned long long); \
397b7eaed25SJason Evans break; \
398b7eaed25SJason Evans case 'j': \
399b7eaed25SJason Evans val = va_arg(ap, intmax_t); \
400b7eaed25SJason Evans break; \
401b7eaed25SJason Evans case 'j' | 0x80: \
402b7eaed25SJason Evans val = va_arg(ap, uintmax_t); \
403b7eaed25SJason Evans break; \
404b7eaed25SJason Evans case 't': \
405b7eaed25SJason Evans val = va_arg(ap, ptrdiff_t); \
406b7eaed25SJason Evans break; \
407b7eaed25SJason Evans case 'z': \
408b7eaed25SJason Evans val = va_arg(ap, ssize_t); \
409b7eaed25SJason Evans break; \
410b7eaed25SJason Evans case 'z' | 0x80: \
411b7eaed25SJason Evans val = va_arg(ap, size_t); \
412b7eaed25SJason Evans break; \
413b7eaed25SJason Evans case 'p': /* Synthetic; used for %p. */ \
414b7eaed25SJason Evans val = va_arg(ap, uintptr_t); \
415b7eaed25SJason Evans break; \
416b7eaed25SJason Evans default: \
417b7eaed25SJason Evans not_reached(); \
418b7eaed25SJason Evans val = 0; \
419b7eaed25SJason Evans } \
420b7eaed25SJason Evans } while (0)
421b7eaed25SJason Evans
422b7eaed25SJason Evans i = 0;
423b7eaed25SJason Evans f = format;
424b7eaed25SJason Evans while (true) {
425b7eaed25SJason Evans switch (*f) {
426b7eaed25SJason Evans case '\0': goto label_out;
427b7eaed25SJason Evans case '%': {
428b7eaed25SJason Evans bool alt_form = false;
429b7eaed25SJason Evans bool left_justify = false;
430b7eaed25SJason Evans bool plus_space = false;
431b7eaed25SJason Evans bool plus_plus = false;
432b7eaed25SJason Evans int prec = -1;
433b7eaed25SJason Evans int width = -1;
434b7eaed25SJason Evans unsigned char len = '?';
435b7eaed25SJason Evans char *s;
436b7eaed25SJason Evans size_t slen;
437b7eaed25SJason Evans
438b7eaed25SJason Evans f++;
439b7eaed25SJason Evans /* Flags. */
440b7eaed25SJason Evans while (true) {
441b7eaed25SJason Evans switch (*f) {
442b7eaed25SJason Evans case '#':
443b7eaed25SJason Evans assert(!alt_form);
444b7eaed25SJason Evans alt_form = true;
445b7eaed25SJason Evans break;
446b7eaed25SJason Evans case '-':
447b7eaed25SJason Evans assert(!left_justify);
448b7eaed25SJason Evans left_justify = true;
449b7eaed25SJason Evans break;
450b7eaed25SJason Evans case ' ':
451b7eaed25SJason Evans assert(!plus_space);
452b7eaed25SJason Evans plus_space = true;
453b7eaed25SJason Evans break;
454b7eaed25SJason Evans case '+':
455b7eaed25SJason Evans assert(!plus_plus);
456b7eaed25SJason Evans plus_plus = true;
457b7eaed25SJason Evans break;
458b7eaed25SJason Evans default: goto label_width;
459b7eaed25SJason Evans }
460b7eaed25SJason Evans f++;
461b7eaed25SJason Evans }
462b7eaed25SJason Evans /* Width. */
463b7eaed25SJason Evans label_width:
464b7eaed25SJason Evans switch (*f) {
465b7eaed25SJason Evans case '*':
466b7eaed25SJason Evans width = va_arg(ap, int);
467b7eaed25SJason Evans f++;
468b7eaed25SJason Evans if (width < 0) {
469b7eaed25SJason Evans left_justify = true;
470b7eaed25SJason Evans width = -width;
471b7eaed25SJason Evans }
472b7eaed25SJason Evans break;
473b7eaed25SJason Evans case '0': case '1': case '2': case '3': case '4':
474b7eaed25SJason Evans case '5': case '6': case '7': case '8': case '9': {
475b7eaed25SJason Evans uintmax_t uwidth;
476b7eaed25SJason Evans set_errno(0);
477b7eaed25SJason Evans uwidth = malloc_strtoumax(f, (char **)&f, 10);
478b7eaed25SJason Evans assert(uwidth != UINTMAX_MAX || get_errno() !=
479b7eaed25SJason Evans ERANGE);
480b7eaed25SJason Evans width = (int)uwidth;
481b7eaed25SJason Evans break;
482b7eaed25SJason Evans } default:
483b7eaed25SJason Evans break;
484b7eaed25SJason Evans }
485b7eaed25SJason Evans /* Width/precision separator. */
486b7eaed25SJason Evans if (*f == '.') {
487b7eaed25SJason Evans f++;
488b7eaed25SJason Evans } else {
489b7eaed25SJason Evans goto label_length;
490b7eaed25SJason Evans }
491b7eaed25SJason Evans /* Precision. */
492b7eaed25SJason Evans switch (*f) {
493b7eaed25SJason Evans case '*':
494b7eaed25SJason Evans prec = va_arg(ap, int);
495b7eaed25SJason Evans f++;
496b7eaed25SJason Evans break;
497b7eaed25SJason Evans case '0': case '1': case '2': case '3': case '4':
498b7eaed25SJason Evans case '5': case '6': case '7': case '8': case '9': {
499b7eaed25SJason Evans uintmax_t uprec;
500b7eaed25SJason Evans set_errno(0);
501b7eaed25SJason Evans uprec = malloc_strtoumax(f, (char **)&f, 10);
502b7eaed25SJason Evans assert(uprec != UINTMAX_MAX || get_errno() !=
503b7eaed25SJason Evans ERANGE);
504b7eaed25SJason Evans prec = (int)uprec;
505b7eaed25SJason Evans break;
506b7eaed25SJason Evans }
507b7eaed25SJason Evans default: break;
508b7eaed25SJason Evans }
509b7eaed25SJason Evans /* Length. */
510b7eaed25SJason Evans label_length:
511b7eaed25SJason Evans switch (*f) {
512b7eaed25SJason Evans case 'l':
513b7eaed25SJason Evans f++;
514b7eaed25SJason Evans if (*f == 'l') {
515b7eaed25SJason Evans len = 'q';
516b7eaed25SJason Evans f++;
517b7eaed25SJason Evans } else {
518b7eaed25SJason Evans len = 'l';
519b7eaed25SJason Evans }
520b7eaed25SJason Evans break;
521b7eaed25SJason Evans case 'q': case 'j': case 't': case 'z':
522b7eaed25SJason Evans len = *f;
523b7eaed25SJason Evans f++;
524b7eaed25SJason Evans break;
525b7eaed25SJason Evans default: break;
526b7eaed25SJason Evans }
527b7eaed25SJason Evans /* Conversion specifier. */
528b7eaed25SJason Evans switch (*f) {
529b7eaed25SJason Evans case '%':
530b7eaed25SJason Evans /* %% */
531b7eaed25SJason Evans APPEND_C(*f);
532b7eaed25SJason Evans f++;
533b7eaed25SJason Evans break;
534b7eaed25SJason Evans case 'd': case 'i': {
535b7eaed25SJason Evans intmax_t val JEMALLOC_CC_SILENCE_INIT(0);
536b7eaed25SJason Evans char buf[D2S_BUFSIZE];
537b7eaed25SJason Evans
538b7eaed25SJason Evans GET_ARG_NUMERIC(val, len);
539b7eaed25SJason Evans s = d2s(val, (plus_plus ? '+' : (plus_space ?
540b7eaed25SJason Evans ' ' : '-')), buf, &slen);
541b7eaed25SJason Evans APPEND_PADDED_S(s, slen, width, left_justify);
542b7eaed25SJason Evans f++;
543b7eaed25SJason Evans break;
544b7eaed25SJason Evans } case 'o': {
545b7eaed25SJason Evans uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
546b7eaed25SJason Evans char buf[O2S_BUFSIZE];
547b7eaed25SJason Evans
548b7eaed25SJason Evans GET_ARG_NUMERIC(val, len | 0x80);
549b7eaed25SJason Evans s = o2s(val, alt_form, buf, &slen);
550b7eaed25SJason Evans APPEND_PADDED_S(s, slen, width, left_justify);
551b7eaed25SJason Evans f++;
552b7eaed25SJason Evans break;
553b7eaed25SJason Evans } case 'u': {
554b7eaed25SJason Evans uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
555b7eaed25SJason Evans char buf[U2S_BUFSIZE];
556b7eaed25SJason Evans
557b7eaed25SJason Evans GET_ARG_NUMERIC(val, len | 0x80);
558b7eaed25SJason Evans s = u2s(val, 10, false, buf, &slen);
559b7eaed25SJason Evans APPEND_PADDED_S(s, slen, width, left_justify);
560b7eaed25SJason Evans f++;
561b7eaed25SJason Evans break;
562b7eaed25SJason Evans } case 'x': case 'X': {
563b7eaed25SJason Evans uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
564b7eaed25SJason Evans char buf[X2S_BUFSIZE];
565b7eaed25SJason Evans
566b7eaed25SJason Evans GET_ARG_NUMERIC(val, len | 0x80);
567b7eaed25SJason Evans s = x2s(val, alt_form, *f == 'X', buf, &slen);
568b7eaed25SJason Evans APPEND_PADDED_S(s, slen, width, left_justify);
569b7eaed25SJason Evans f++;
570b7eaed25SJason Evans break;
571b7eaed25SJason Evans } case 'c': {
572b7eaed25SJason Evans unsigned char val;
573b7eaed25SJason Evans char buf[2];
574b7eaed25SJason Evans
575b7eaed25SJason Evans assert(len == '?' || len == 'l');
576b7eaed25SJason Evans assert_not_implemented(len != 'l');
577b7eaed25SJason Evans val = va_arg(ap, int);
578b7eaed25SJason Evans buf[0] = val;
579b7eaed25SJason Evans buf[1] = '\0';
580b7eaed25SJason Evans APPEND_PADDED_S(buf, 1, width, left_justify);
581b7eaed25SJason Evans f++;
582b7eaed25SJason Evans break;
583b7eaed25SJason Evans } case 's':
584b7eaed25SJason Evans assert(len == '?' || len == 'l');
585b7eaed25SJason Evans assert_not_implemented(len != 'l');
586b7eaed25SJason Evans s = va_arg(ap, char *);
587b7eaed25SJason Evans slen = (prec < 0) ? strlen(s) : (size_t)prec;
588b7eaed25SJason Evans APPEND_PADDED_S(s, slen, width, left_justify);
589b7eaed25SJason Evans f++;
590b7eaed25SJason Evans break;
591b7eaed25SJason Evans case 'p': {
592b7eaed25SJason Evans uintmax_t val;
593b7eaed25SJason Evans char buf[X2S_BUFSIZE];
594b7eaed25SJason Evans
595b7eaed25SJason Evans GET_ARG_NUMERIC(val, 'p');
596b7eaed25SJason Evans s = x2s(val, true, false, buf, &slen);
597b7eaed25SJason Evans APPEND_PADDED_S(s, slen, width, left_justify);
598b7eaed25SJason Evans f++;
599b7eaed25SJason Evans break;
600b7eaed25SJason Evans } default: not_reached();
601b7eaed25SJason Evans }
602b7eaed25SJason Evans break;
603b7eaed25SJason Evans } default: {
604b7eaed25SJason Evans APPEND_C(*f);
605b7eaed25SJason Evans f++;
606b7eaed25SJason Evans break;
607b7eaed25SJason Evans }}
608b7eaed25SJason Evans }
609b7eaed25SJason Evans label_out:
610b7eaed25SJason Evans if (i < size) {
611b7eaed25SJason Evans str[i] = '\0';
612b7eaed25SJason Evans } else {
613b7eaed25SJason Evans str[size - 1] = '\0';
614b7eaed25SJason Evans }
615b7eaed25SJason Evans
616b7eaed25SJason Evans #undef APPEND_C
617b7eaed25SJason Evans #undef APPEND_S
618b7eaed25SJason Evans #undef APPEND_PADDED_S
619b7eaed25SJason Evans #undef GET_ARG_NUMERIC
620b7eaed25SJason Evans return i;
621b7eaed25SJason Evans }
622b7eaed25SJason Evans
623b7eaed25SJason Evans JEMALLOC_FORMAT_PRINTF(3, 4)
624b7eaed25SJason Evans size_t
malloc_snprintf(char * str,size_t size,const char * format,...)625b7eaed25SJason Evans malloc_snprintf(char *str, size_t size, const char *format, ...) {
626b7eaed25SJason Evans size_t ret;
627b7eaed25SJason Evans va_list ap;
628b7eaed25SJason Evans
629b7eaed25SJason Evans va_start(ap, format);
630b7eaed25SJason Evans ret = malloc_vsnprintf(str, size, format, ap);
631b7eaed25SJason Evans va_end(ap);
632b7eaed25SJason Evans
633b7eaed25SJason Evans return ret;
634b7eaed25SJason Evans }
635b7eaed25SJason Evans
636b7eaed25SJason Evans void
malloc_vcprintf(void (* write_cb)(void *,const char *),void * cbopaque,const char * format,va_list ap)637b7eaed25SJason Evans malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
638b7eaed25SJason Evans const char *format, va_list ap) {
639b7eaed25SJason Evans char buf[MALLOC_PRINTF_BUFSIZE];
640b7eaed25SJason Evans
641b7eaed25SJason Evans if (write_cb == NULL) {
642b7eaed25SJason Evans /*
643b7eaed25SJason Evans * The caller did not provide an alternate write_cb callback
644b7eaed25SJason Evans * function, so use the default one. malloc_write() is an
645b7eaed25SJason Evans * inline function, so use malloc_message() directly here.
646b7eaed25SJason Evans */
647b7eaed25SJason Evans write_cb = (je_malloc_message != NULL) ? je_malloc_message :
648b7eaed25SJason Evans wrtmessage;
649b7eaed25SJason Evans }
650b7eaed25SJason Evans
651b7eaed25SJason Evans malloc_vsnprintf(buf, sizeof(buf), format, ap);
652b7eaed25SJason Evans write_cb(cbopaque, buf);
653b7eaed25SJason Evans }
654b7eaed25SJason Evans
655b7eaed25SJason Evans /*
656b7eaed25SJason Evans * Print to a callback function in such a way as to (hopefully) avoid memory
657b7eaed25SJason Evans * allocation.
658b7eaed25SJason Evans */
659b7eaed25SJason Evans JEMALLOC_FORMAT_PRINTF(3, 4)
660b7eaed25SJason Evans void
malloc_cprintf(void (* write_cb)(void *,const char *),void * cbopaque,const char * format,...)661b7eaed25SJason Evans malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque,
662b7eaed25SJason Evans const char *format, ...) {
663b7eaed25SJason Evans va_list ap;
664b7eaed25SJason Evans
665b7eaed25SJason Evans va_start(ap, format);
666b7eaed25SJason Evans malloc_vcprintf(write_cb, cbopaque, format, ap);
667b7eaed25SJason Evans va_end(ap);
668b7eaed25SJason Evans }
669b7eaed25SJason Evans
670b7eaed25SJason Evans /* Print to stderr in such a way as to avoid memory allocation. */
671b7eaed25SJason Evans JEMALLOC_FORMAT_PRINTF(1, 2)
672b7eaed25SJason Evans void
malloc_printf(const char * format,...)673b7eaed25SJason Evans malloc_printf(const char *format, ...) {
674b7eaed25SJason Evans va_list ap;
675b7eaed25SJason Evans
676b7eaed25SJason Evans va_start(ap, format);
677b7eaed25SJason Evans malloc_vcprintf(NULL, NULL, format, ap);
678b7eaed25SJason Evans va_end(ap);
679b7eaed25SJason Evans }
680b7eaed25SJason Evans
681b7eaed25SJason Evans /*
682b7eaed25SJason Evans * Restore normal assertion macros, in order to make it possible to compile all
683b7eaed25SJason Evans * C files as a single concatenation.
684b7eaed25SJason Evans */
685b7eaed25SJason Evans #undef assert
686b7eaed25SJason Evans #undef not_reached
687b7eaed25SJason Evans #undef not_implemented
688b7eaed25SJason Evans #undef assert_not_implemented
689b7eaed25SJason Evans #include "jemalloc/internal/assert.h"
690