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