blob: 02673c70d9cb0c08db70aa3f2b367a7dd1e28e37 [file] [log] [blame]
Jason Evansf9e34592015-11-12 11:06:41 -08001/*
2 * Define simple versions of assertion macros that won't recurse in case
3 * of assertion failures in malloc_*printf().
4 */
Jason Evansd81e4bd2012-03-06 14:57:45 -08005#define assert(e) do { \
6 if (config_debug && !(e)) { \
7 malloc_write("<jemalloc>: Failed assertion\n"); \
8 abort(); \
9 } \
10} while (0)
11
12#define not_reached() do { \
13 if (config_debug) { \
14 malloc_write("<jemalloc>: Unreachable code reached\n"); \
15 abort(); \
16 } \
17} while (0)
18
19#define not_implemented() do { \
20 if (config_debug) { \
21 malloc_write("<jemalloc>: Not implemented\n"); \
22 abort(); \
23 } \
24} while (0)
25
26#define JEMALLOC_UTIL_C_
27#include "jemalloc/internal/jemalloc_internal.h"
28
29/******************************************************************************/
30/* Function prototypes for non-inline static functions. */
31
32static void wrtmessage(void *cbopaque, const char *s);
33#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1)
34static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s,
35 size_t *slen_p);
36#define D2S_BUFSIZE (1 + U2S_BUFSIZE)
37static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p);
38#define O2S_BUFSIZE (1 + U2S_BUFSIZE)
39static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p);
40#define X2S_BUFSIZE (2 + U2S_BUFSIZE)
41static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s,
42 size_t *slen_p);
43
44/******************************************************************************/
45
46/* malloc_message() setup. */
Mike Hommeyda99e312012-04-30 12:38:29 +020047static void
Jason Evansd81e4bd2012-03-06 14:57:45 -080048wrtmessage(void *cbopaque, const char *s)
49{
Mike Hommey1a0e7772012-03-27 14:48:58 +020050
51#ifdef SYS_write
52 /*
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.
Christopher Ferrise4294032016-03-02 14:33:02 -080056 *
57 * syscall() returns long or int, depending on platform, so capture the
58 * unused result in the widest plausible type to avoid compiler
59 * warnings.
Mike Hommey1a0e7772012-03-27 14:48:58 +020060 */
Christopher Ferrise4294032016-03-02 14:33:02 -080061 UNUSED long result = syscall(SYS_write, STDERR_FILENO, s, strlen(s));
Mike Hommey1a0e7772012-03-27 14:48:58 +020062#else
Christopher Ferrise4294032016-03-02 14:33:02 -080063 UNUSED ssize_t result = write(STDERR_FILENO, s, strlen(s));
Mike Hommey1a0e7772012-03-27 14:48:58 +020064#endif
Jason Evansd81e4bd2012-03-06 14:57:45 -080065}
66
Mike Hommey3597e912012-05-02 13:15:00 +020067JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s);
Jason Evansd81e4bd2012-03-06 14:57:45 -080068
69/*
Jason Evans889ec592012-05-02 02:08:03 -070070 * Wrapper around malloc_message() that avoids the need for
71 * je_malloc_message(...) throughout the code.
72 */
73void
74malloc_write(const char *s)
75{
76
Mike Hommey3597e912012-05-02 13:15:00 +020077 if (je_malloc_message != NULL)
78 je_malloc_message(NULL, s);
79 else
80 wrtmessage(NULL, s);
Jason Evans889ec592012-05-02 02:08:03 -070081}
82
83/*
Jason Evansd81e4bd2012-03-06 14:57:45 -080084 * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so
85 * provide a wrapper.
86 */
87int
Jason Evans2a83ed02013-12-08 20:52:21 -080088buferror(int err, char *buf, size_t buflen)
Jason Evansd81e4bd2012-03-06 14:57:45 -080089{
Mike Hommeya19e87f2012-04-21 21:27:46 -070090
91#ifdef _WIN32
Mike Hommeyf69e2f62015-03-12 08:51:05 +090092 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0,
Christopher Ferrise4294032016-03-02 14:33:02 -080093 (LPSTR)buf, (DWORD)buflen, NULL);
Mike Hommeya19e87f2012-04-21 21:27:46 -070094 return (0);
Felix Janda008267b2015-02-03 18:58:02 +010095#elif defined(__GLIBC__) && defined(_GNU_SOURCE)
Jason Evans2a83ed02013-12-08 20:52:21 -080096 char *b = strerror_r(err, buf, buflen);
Jason Evansd81e4bd2012-03-06 14:57:45 -080097 if (b != buf) {
98 strncpy(buf, b, buflen);
99 buf[buflen-1] = '\0';
100 }
101 return (0);
102#else
Jason Evans2a83ed02013-12-08 20:52:21 -0800103 return (strerror_r(err, buf, buflen));
Jason Evansd81e4bd2012-03-06 14:57:45 -0800104#endif
105}
106
Jason Evans41b6afb2012-02-02 22:04:57 -0800107uintmax_t
Jason Evanse18c25d2014-01-06 20:33:48 -0800108malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base)
Jason Evans41b6afb2012-02-02 22:04:57 -0800109{
110 uintmax_t ret, digit;
Chris Peterson3e310b32014-05-28 19:04:06 -0700111 unsigned b;
Jason Evans41b6afb2012-02-02 22:04:57 -0800112 bool neg;
113 const char *p, *ns;
114
Jason Evanse18c25d2014-01-06 20:33:48 -0800115 p = nptr;
Jason Evans41b6afb2012-02-02 22:04:57 -0800116 if (base < 0 || base == 1 || base > 36) {
Jason Evanse18c25d2014-01-06 20:33:48 -0800117 ns = p;
Mike Hommeya14bce82012-04-30 12:38:26 +0200118 set_errno(EINVAL);
Jason Evanse18c25d2014-01-06 20:33:48 -0800119 ret = UINTMAX_MAX;
120 goto label_return;
Jason Evans41b6afb2012-02-02 22:04:57 -0800121 }
122 b = base;
123
124 /* Swallow leading whitespace and get sign, if any. */
125 neg = false;
Jason Evans41b6afb2012-02-02 22:04:57 -0800126 while (true) {
127 switch (*p) {
128 case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
129 p++;
130 break;
131 case '-':
132 neg = true;
133 /* Fall through. */
134 case '+':
135 p++;
136 /* Fall through. */
137 default:
Jason Evansa1ee7832012-04-10 15:07:44 -0700138 goto label_prefix;
Jason Evans41b6afb2012-02-02 22:04:57 -0800139 }
140 }
141
142 /* Get prefix, if any. */
Jason Evansa1ee7832012-04-10 15:07:44 -0700143 label_prefix:
Jason Evans41b6afb2012-02-02 22:04:57 -0800144 /*
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.
147 * " -x").
148 */
149 ns = p;
150 if (*p == '0') {
151 switch (p[1]) {
152 case '0': case '1': case '2': case '3': case '4': case '5':
153 case '6': case '7':
154 if (b == 0)
155 b = 8;
156 if (b == 8)
157 p++;
158 break;
Jason Evanse18c25d2014-01-06 20:33:48 -0800159 case 'X': case 'x':
Jason Evans41b6afb2012-02-02 22:04:57 -0800160 switch (p[2]) {
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':
164 case 'F':
165 case 'a': case 'b': case 'c': case 'd': case 'e':
166 case 'f':
167 if (b == 0)
168 b = 16;
169 if (b == 16)
170 p += 2;
171 break;
172 default:
173 break;
174 }
175 break;
176 default:
Jason Evanse18c25d2014-01-06 20:33:48 -0800177 p++;
178 ret = 0;
179 goto label_return;
Jason Evans41b6afb2012-02-02 22:04:57 -0800180 }
181 }
182 if (b == 0)
183 b = 10;
184
185 /* Convert. */
186 ret = 0;
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;
191 ret *= b;
192 ret += digit;
193 if (ret < pret) {
194 /* Overflow. */
Mike Hommeya14bce82012-04-30 12:38:26 +0200195 set_errno(ERANGE);
Jason Evanse18c25d2014-01-06 20:33:48 -0800196 ret = UINTMAX_MAX;
197 goto label_return;
Jason Evans41b6afb2012-02-02 22:04:57 -0800198 }
199 p++;
200 }
201 if (neg)
202 ret = -ret;
203
Jason Evanse18c25d2014-01-06 20:33:48 -0800204 if (p == ns) {
205 /* No conversion performed. */
206 set_errno(EINVAL);
207 ret = UINTMAX_MAX;
208 goto label_return;
209 }
210
211label_return:
Jason Evans41b6afb2012-02-02 22:04:57 -0800212 if (endptr != NULL) {
213 if (p == ns) {
214 /* No characters were converted. */
215 *endptr = (char *)nptr;
216 } else
217 *endptr = (char *)p;
218 }
Jason Evans41b6afb2012-02-02 22:04:57 -0800219 return (ret);
220}
221
Jason Evansd81e4bd2012-03-06 14:57:45 -0800222static char *
223u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p)
224{
225 unsigned i;
226
227 i = U2S_BUFSIZE - 1;
228 s[i] = '\0';
229 switch (base) {
230 case 10:
231 do {
232 i--;
233 s[i] = "0123456789"[x % (uint64_t)10];
234 x /= (uint64_t)10;
235 } while (x > 0);
236 break;
237 case 16: {
238 const char *digits = (uppercase)
239 ? "0123456789ABCDEF"
240 : "0123456789abcdef";
241
242 do {
243 i--;
244 s[i] = digits[x & 0xf];
245 x >>= 4;
246 } while (x > 0);
247 break;
248 } default: {
249 const char *digits = (uppercase)
250 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
251 : "0123456789abcdefghijklmnopqrstuvwxyz";
252
253 assert(base >= 2 && base <= 36);
254 do {
255 i--;
256 s[i] = digits[x % (uint64_t)base];
257 x /= (uint64_t)base;
258 } while (x > 0);
259 }}
260
261 *slen_p = U2S_BUFSIZE - 1 - i;
262 return (&s[i]);
263}
264
265static char *
266d2s(intmax_t x, char sign, char *s, size_t *slen_p)
267{
268 bool neg;
269
270 if ((neg = (x < 0)))
271 x = -x;
272 s = u2s(x, 10, false, s, slen_p);
273 if (neg)
274 sign = '-';
275 switch (sign) {
276 case '-':
Jason Evans551ebc42014-10-03 10:16:09 -0700277 if (!neg)
Jason Evansd81e4bd2012-03-06 14:57:45 -0800278 break;
279 /* Fall through. */
280 case ' ':
281 case '+':
282 s--;
283 (*slen_p)++;
284 *s = sign;
285 break;
286 default: not_reached();
287 }
288 return (s);
289}
290
291static char *
292o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p)
293{
294
295 s = u2s(x, 8, false, s, slen_p);
296 if (alt_form && *s != '0') {
297 s--;
298 (*slen_p)++;
299 *s = '0';
300 }
301 return (s);
302}
303
304static char *
305x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p)
306{
307
308 s = u2s(x, 16, uppercase, s, slen_p);
309 if (alt_form) {
310 s -= 2;
311 (*slen_p) += 2;
312 memcpy(s, uppercase ? "0X" : "0x", 2);
313 }
314 return (s);
315}
316
317int
318malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
319{
320 int ret;
321 size_t i;
322 const char *f;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800323
324#define APPEND_C(c) do { \
325 if (i < size) \
326 str[i] = (c); \
327 i++; \
328} while (0)
329#define APPEND_S(s, slen) do { \
330 if (i < size) { \
331 size_t cpylen = (slen <= size - i) ? slen : size - i; \
332 memcpy(&str[i], s, cpylen); \
333 } \
334 i += slen; \
335} while (0)
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); \
Jason Evans551ebc42014-10-03 10:16:09 -0700340 if (!left_justify && pad_len != 0) { \
Jason Evansd81e4bd2012-03-06 14:57:45 -0800341 size_t j; \
342 for (j = 0; j < pad_len; j++) \
343 APPEND_C(' '); \
344 } \
345 /* Value. */ \
346 APPEND_S(s, slen); \
347 /* Right padding. */ \
348 if (left_justify && pad_len != 0) { \
349 size_t j; \
350 for (j = 0; j < pad_len; j++) \
351 APPEND_C(' '); \
352 } \
353} while (0)
Jason Evansa4f124f2013-12-08 22:28:27 -0800354#define GET_ARG_NUMERIC(val, len) do { \
Jason Evansd81e4bd2012-03-06 14:57:45 -0800355 switch (len) { \
356 case '?': \
357 val = va_arg(ap, int); \
358 break; \
Mike Hommey1ad56382012-04-18 18:29:44 +0200359 case '?' | 0x80: \
360 val = va_arg(ap, unsigned int); \
361 break; \
Jason Evansd81e4bd2012-03-06 14:57:45 -0800362 case 'l': \
363 val = va_arg(ap, long); \
364 break; \
Mike Hommey1ad56382012-04-18 18:29:44 +0200365 case 'l' | 0x80: \
366 val = va_arg(ap, unsigned long); \
367 break; \
Jason Evansd81e4bd2012-03-06 14:57:45 -0800368 case 'q': \
369 val = va_arg(ap, long long); \
370 break; \
Mike Hommey1ad56382012-04-18 18:29:44 +0200371 case 'q' | 0x80: \
372 val = va_arg(ap, unsigned long long); \
373 break; \
Jason Evansd81e4bd2012-03-06 14:57:45 -0800374 case 'j': \
375 val = va_arg(ap, intmax_t); \
376 break; \
Jason Evanse18c25d2014-01-06 20:33:48 -0800377 case 'j' | 0x80: \
378 val = va_arg(ap, uintmax_t); \
379 break; \
Jason Evansd81e4bd2012-03-06 14:57:45 -0800380 case 't': \
381 val = va_arg(ap, ptrdiff_t); \
382 break; \
383 case 'z': \
Jason Evans41b6afb2012-02-02 22:04:57 -0800384 val = va_arg(ap, ssize_t); \
Jason Evansd81e4bd2012-03-06 14:57:45 -0800385 break; \
Mike Hommey1ad56382012-04-18 18:29:44 +0200386 case 'z' | 0x80: \
387 val = va_arg(ap, size_t); \
388 break; \
Jason Evanscd9a1342012-03-21 18:33:03 -0700389 case 'p': /* Synthetic; used for %p. */ \
390 val = va_arg(ap, uintptr_t); \
391 break; \
Chris Peterson70807bc2014-05-28 19:04:33 -0700392 default: \
393 not_reached(); \
394 val = 0; \
Jason Evansd81e4bd2012-03-06 14:57:45 -0800395 } \
396} while (0)
397
Jason Evansd81e4bd2012-03-06 14:57:45 -0800398 i = 0;
399 f = format;
400 while (true) {
401 switch (*f) {
Jason Evansa1ee7832012-04-10 15:07:44 -0700402 case '\0': goto label_out;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800403 case '%': {
404 bool alt_form = false;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800405 bool left_justify = false;
406 bool plus_space = false;
407 bool plus_plus = false;
408 int prec = -1;
409 int width = -1;
Mike Hommey1ad56382012-04-18 18:29:44 +0200410 unsigned char len = '?';
Jason Evansd81e4bd2012-03-06 14:57:45 -0800411
412 f++;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800413 /* Flags. */
414 while (true) {
415 switch (*f) {
416 case '#':
Jason Evans551ebc42014-10-03 10:16:09 -0700417 assert(!alt_form);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800418 alt_form = true;
419 break;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800420 case '-':
Jason Evans551ebc42014-10-03 10:16:09 -0700421 assert(!left_justify);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800422 left_justify = true;
423 break;
424 case ' ':
Jason Evans551ebc42014-10-03 10:16:09 -0700425 assert(!plus_space);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800426 plus_space = true;
427 break;
428 case '+':
Jason Evans551ebc42014-10-03 10:16:09 -0700429 assert(!plus_plus);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800430 plus_plus = true;
431 break;
Jason Evansa1ee7832012-04-10 15:07:44 -0700432 default: goto label_width;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800433 }
434 f++;
435 }
436 /* Width. */
Jason Evansa1ee7832012-04-10 15:07:44 -0700437 label_width:
Jason Evansd81e4bd2012-03-06 14:57:45 -0800438 switch (*f) {
439 case '*':
440 width = va_arg(ap, int);
441 f++;
Jason Evanse18c25d2014-01-06 20:33:48 -0800442 if (width < 0) {
443 left_justify = true;
444 width = -width;
445 }
Jason Evansd81e4bd2012-03-06 14:57:45 -0800446 break;
447 case '0': case '1': case '2': case '3': case '4':
448 case '5': case '6': case '7': case '8': case '9': {
Jason Evans41b6afb2012-02-02 22:04:57 -0800449 uintmax_t uwidth;
Mike Hommeya14bce82012-04-30 12:38:26 +0200450 set_errno(0);
Jason Evans41b6afb2012-02-02 22:04:57 -0800451 uwidth = malloc_strtoumax(f, (char **)&f, 10);
Mike Hommeya14bce82012-04-30 12:38:26 +0200452 assert(uwidth != UINTMAX_MAX || get_errno() !=
Jason Evans41b6afb2012-02-02 22:04:57 -0800453 ERANGE);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800454 width = (int)uwidth;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800455 break;
Jason Evanse18c25d2014-01-06 20:33:48 -0800456 } default:
457 break;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800458 }
Jason Evanse18c25d2014-01-06 20:33:48 -0800459 /* Width/precision separator. */
460 if (*f == '.')
461 f++;
462 else
463 goto label_length;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800464 /* Precision. */
Jason Evansd81e4bd2012-03-06 14:57:45 -0800465 switch (*f) {
466 case '*':
467 prec = va_arg(ap, int);
468 f++;
469 break;
470 case '0': case '1': case '2': case '3': case '4':
471 case '5': case '6': case '7': case '8': case '9': {
Jason Evans41b6afb2012-02-02 22:04:57 -0800472 uintmax_t uprec;
Mike Hommeya14bce82012-04-30 12:38:26 +0200473 set_errno(0);
Jason Evans41b6afb2012-02-02 22:04:57 -0800474 uprec = malloc_strtoumax(f, (char **)&f, 10);
Mike Hommeya14bce82012-04-30 12:38:26 +0200475 assert(uprec != UINTMAX_MAX || get_errno() !=
476 ERANGE);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800477 prec = (int)uprec;
478 break;
479 }
480 default: break;
481 }
482 /* Length. */
Jason Evansa1ee7832012-04-10 15:07:44 -0700483 label_length:
Jason Evansd81e4bd2012-03-06 14:57:45 -0800484 switch (*f) {
485 case 'l':
486 f++;
487 if (*f == 'l') {
488 len = 'q';
489 f++;
490 } else
491 len = 'l';
492 break;
Jason Evanse18c25d2014-01-06 20:33:48 -0800493 case 'q': case 'j': case 't': case 'z':
494 len = *f;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800495 f++;
496 break;
497 default: break;
498 }
499 /* Conversion specifier. */
500 switch (*f) {
501 char *s;
502 size_t slen;
Jason Evans0c4e7432014-01-22 09:00:27 -0800503 case '%':
504 /* %% */
505 APPEND_C(*f);
506 f++;
507 break;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800508 case 'd': case 'i': {
Jason Evans9225a192012-03-23 15:39:07 -0700509 intmax_t val JEMALLOC_CC_SILENCE_INIT(0);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800510 char buf[D2S_BUFSIZE];
511
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);
516 f++;
517 break;
518 } case 'o': {
Jason Evans9225a192012-03-23 15:39:07 -0700519 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800520 char buf[O2S_BUFSIZE];
521
Mike Hommey1ad56382012-04-18 18:29:44 +0200522 GET_ARG_NUMERIC(val, len | 0x80);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800523 s = o2s(val, alt_form, buf, &slen);
524 APPEND_PADDED_S(s, slen, width, left_justify);
525 f++;
526 break;
527 } case 'u': {
Jason Evans9225a192012-03-23 15:39:07 -0700528 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800529 char buf[U2S_BUFSIZE];
530
Mike Hommey1ad56382012-04-18 18:29:44 +0200531 GET_ARG_NUMERIC(val, len | 0x80);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800532 s = u2s(val, 10, false, buf, &slen);
533 APPEND_PADDED_S(s, slen, width, left_justify);
534 f++;
535 break;
536 } case 'x': case 'X': {
Jason Evans9225a192012-03-23 15:39:07 -0700537 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800538 char buf[X2S_BUFSIZE];
539
Mike Hommey1ad56382012-04-18 18:29:44 +0200540 GET_ARG_NUMERIC(val, len | 0x80);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800541 s = x2s(val, alt_form, *f == 'X', buf, &slen);
542 APPEND_PADDED_S(s, slen, width, left_justify);
543 f++;
544 break;
545 } case 'c': {
546 unsigned char val;
547 char buf[2];
548
549 assert(len == '?' || len == 'l');
550 assert_not_implemented(len != 'l');
551 val = va_arg(ap, int);
552 buf[0] = val;
553 buf[1] = '\0';
554 APPEND_PADDED_S(buf, 1, width, left_justify);
555 f++;
556 break;
557 } case 's':
558 assert(len == '?' || len == 'l');
559 assert_not_implemented(len != 'l');
560 s = va_arg(ap, char *);
Chris Peterson3e310b32014-05-28 19:04:06 -0700561 slen = (prec < 0) ? strlen(s) : (size_t)prec;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800562 APPEND_PADDED_S(s, slen, width, left_justify);
563 f++;
564 break;
565 case 'p': {
566 uintmax_t val;
567 char buf[X2S_BUFSIZE];
568
Jason Evanscd9a1342012-03-21 18:33:03 -0700569 GET_ARG_NUMERIC(val, 'p');
Jason Evansd81e4bd2012-03-06 14:57:45 -0800570 s = x2s(val, true, false, buf, &slen);
571 APPEND_PADDED_S(s, slen, width, left_justify);
572 f++;
573 break;
Jason Evans0c4e7432014-01-22 09:00:27 -0800574 } default: not_reached();
Jason Evansd81e4bd2012-03-06 14:57:45 -0800575 }
576 break;
577 } default: {
578 APPEND_C(*f);
579 f++;
580 break;
581 }}
582 }
Jason Evansa1ee7832012-04-10 15:07:44 -0700583 label_out:
Jason Evansd81e4bd2012-03-06 14:57:45 -0800584 if (i < size)
585 str[i] = '\0';
586 else
587 str[size - 1] = '\0';
Christopher Ferrise4294032016-03-02 14:33:02 -0800588 assert(i < INT_MAX);
589 ret = (int)i;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800590
Jason Evansd81e4bd2012-03-06 14:57:45 -0800591#undef APPEND_C
592#undef APPEND_S
593#undef APPEND_PADDED_S
594#undef GET_ARG_NUMERIC
595 return (ret);
596}
597
Jason Evanse42c3092015-07-22 15:44:47 -0700598JEMALLOC_FORMAT_PRINTF(3, 4)
Jason Evansd81e4bd2012-03-06 14:57:45 -0800599int
600malloc_snprintf(char *str, size_t size, const char *format, ...)
601{
602 int ret;
603 va_list ap;
604
605 va_start(ap, format);
606 ret = malloc_vsnprintf(str, size, format, ap);
607 va_end(ap);
608
609 return (ret);
610}
611
Jason Evansd81e4bd2012-03-06 14:57:45 -0800612void
613malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
614 const char *format, va_list ap)
615{
Jason Evanscd9a1342012-03-21 18:33:03 -0700616 char buf[MALLOC_PRINTF_BUFSIZE];
Jason Evansd81e4bd2012-03-06 14:57:45 -0800617
618 if (write_cb == NULL) {
619 /*
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.
623 */
Mike Hommey3597e912012-05-02 13:15:00 +0200624 write_cb = (je_malloc_message != NULL) ? je_malloc_message :
625 wrtmessage;
Jason Evansd81e4bd2012-03-06 14:57:45 -0800626 cbopaque = NULL;
627 }
628
Jason Evanscd9a1342012-03-21 18:33:03 -0700629 malloc_vsnprintf(buf, sizeof(buf), format, ap);
630 write_cb(cbopaque, buf);
Jason Evansd81e4bd2012-03-06 14:57:45 -0800631}
632
633/*
634 * Print to a callback function in such a way as to (hopefully) avoid memory
635 * allocation.
636 */
Jason Evanse42c3092015-07-22 15:44:47 -0700637JEMALLOC_FORMAT_PRINTF(3, 4)
Jason Evansd81e4bd2012-03-06 14:57:45 -0800638void
639malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque,
640 const char *format, ...)
641{
642 va_list ap;
643
644 va_start(ap, format);
645 malloc_vcprintf(write_cb, cbopaque, format, ap);
646 va_end(ap);
647}
648
649/* Print to stderr in such a way as to avoid memory allocation. */
Jason Evanse42c3092015-07-22 15:44:47 -0700650JEMALLOC_FORMAT_PRINTF(1, 2)
Jason Evansd81e4bd2012-03-06 14:57:45 -0800651void
652malloc_printf(const char *format, ...)
653{
654 va_list ap;
655
656 va_start(ap, format);
657 malloc_vcprintf(NULL, NULL, format, ap);
658 va_end(ap);
659}
Jason Evansf9e34592015-11-12 11:06:41 -0800660
661/*
662 * Restore normal assertion macros, in order to make it possible to compile all
663 * C files as a single concatenation.
664 */
665#undef assert
666#undef not_reached
667#undef not_implemented
668#include "jemalloc/internal/assert.h"