memory/jemalloc/src/src/util.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial