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