PageRenderTime 34ms CodeModel.GetById 13ms app.highlight 17ms RepoModel.GetById 0ms app.codeStats 0ms

/jemalloc-3.0.0/src/util.c

#
C | 646 lines | 548 code | 52 blank | 46 comment | 114 complexity | cd9da5437dfe6c8f2cad1afb62388cd2 MD5 | raw file
Possible License(s): BSD-2-Clause
  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
 28static void	wrtmessage(void *cbopaque, const char *s);
 29#define	U2S_BUFSIZE	((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1)
 30static char	*u2s(uintmax_t x, unsigned base, bool uppercase, char *s,
 31    size_t *slen_p);
 32#define	D2S_BUFSIZE	(1 + U2S_BUFSIZE)
 33static char	*d2s(intmax_t x, char sign, char *s, size_t *slen_p);
 34#define	O2S_BUFSIZE	(1 + U2S_BUFSIZE)
 35static char	*o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p);
 36#define	X2S_BUFSIZE	(2 + U2S_BUFSIZE)
 37static char	*x2s(uintmax_t x, bool alt_form, bool uppercase, char *s,
 38    size_t *slen_p);
 39
 40/******************************************************************************/
 41
 42/* malloc_message() setup. */
 43static void
 44wrtmessage(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
 59JEMALLOC_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 */
 65void
 66malloc_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 */
 79int
 80buferror(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(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}
 98
 99uintmax_t
100malloc_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;
106
107	if (base < 0 || base == 1 || base > 36) {
108		set_errno(EINVAL);
109		return (UINTMAX_MAX);
110	}
111	b = base;
112
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	}
131
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;
172
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;
190
191	if (endptr != NULL) {
192		if (p == ns) {
193			/* No characters were converted. */
194			*endptr = (char *)nptr;
195		} else
196			*endptr = (char *)p;
197	}
198
199	return (ret);
200}
201
202static char *
203u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p)
204{
205	unsigned i;
206
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";
221
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";
232
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	}}
240
241	*slen_p = U2S_BUFSIZE - 1 - i;
242	return (&s[i]);
243}
244
245static char *
246d2s(intmax_t x, char sign, char *s, size_t *slen_p)
247{
248	bool neg;
249
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}
270
271static char *
272o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p)
273{
274
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}
283
284static char *
285x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p)
286{
287
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}
296
297int
298malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
299{
300	int ret;
301	size_t i;
302	const char *f;
303
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)
372
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 zero_pad = false;
381			bool left_justify = false;
382			bool plus_space = false;
383			bool plus_plus = false;
384			int prec = -1;
385			int width = -1;
386			unsigned char len = '?';
387
388			f++;
389			if (*f == '%') {
390				/* %% */
391				APPEND_C(*f);
392				break;
393			}
394			/* Flags. */
395			while (true) {
396				switch (*f) {
397				case '#':
398					assert(alt_form == false);
399					alt_form = true;
400					break;
401				case '0':
402					assert(zero_pad == false);
403					zero_pad = true;
404					break;
405				case '-':
406					assert(left_justify == false);
407					left_justify = true;
408					break;
409				case ' ':
410					assert(plus_space == false);
411					plus_space = true;
412					break;
413				case '+':
414					assert(plus_plus == false);
415					plus_plus = true;
416					break;
417				default: goto label_width;
418				}
419				f++;
420			}
421			/* Width. */
422			label_width:
423			switch (*f) {
424			case '*':
425				width = va_arg(ap, int);
426				f++;
427				break;
428			case '0': case '1': case '2': case '3': case '4':
429			case '5': case '6': case '7': case '8': case '9': {
430				uintmax_t uwidth;
431				set_errno(0);
432				uwidth = malloc_strtoumax(f, (char **)&f, 10);
433				assert(uwidth != UINTMAX_MAX || get_errno() !=
434				    ERANGE);
435				width = (int)uwidth;
436				if (*f == '.') {
437					f++;
438					goto label_precision;
439				} else
440					goto label_length;
441				break;
442			} case '.':
443				f++;
444				goto label_precision;
445			default: goto label_length;
446			}
447			/* Precision. */
448			label_precision:
449			switch (*f) {
450			case '*':
451				prec = va_arg(ap, int);
452				f++;
453				break;
454			case '0': case '1': case '2': case '3': case '4':
455			case '5': case '6': case '7': case '8': case '9': {
456				uintmax_t uprec;
457				set_errno(0);
458				uprec = malloc_strtoumax(f, (char **)&f, 10);
459				assert(uprec != UINTMAX_MAX || get_errno() !=
460				    ERANGE);
461				prec = (int)uprec;
462				break;
463			}
464			default: break;
465			}
466			/* Length. */
467			label_length:
468			switch (*f) {
469			case 'l':
470				f++;
471				if (*f == 'l') {
472					len = 'q';
473					f++;
474				} else
475					len = 'l';
476				break;
477			case 'j':
478				len = 'j';
479				f++;
480				break;
481			case 't':
482				len = 't';
483				f++;
484				break;
485			case 'z':
486				len = 'z';
487				f++;
488				break;
489			default: break;
490			}
491			/* Conversion specifier. */
492			switch (*f) {
493				char *s;
494				size_t slen;
495			case 'd': case 'i': {
496				intmax_t val JEMALLOC_CC_SILENCE_INIT(0);
497				char buf[D2S_BUFSIZE];
498
499				GET_ARG_NUMERIC(val, len);
500				s = d2s(val, (plus_plus ? '+' : (plus_space ?
501				    ' ' : '-')), buf, &slen);
502				APPEND_PADDED_S(s, slen, width, left_justify);
503				f++;
504				break;
505			} case 'o': {
506				uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
507				char buf[O2S_BUFSIZE];
508
509				GET_ARG_NUMERIC(val, len | 0x80);
510				s = o2s(val, alt_form, buf, &slen);
511				APPEND_PADDED_S(s, slen, width, left_justify);
512				f++;
513				break;
514			} case 'u': {
515				uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
516				char buf[U2S_BUFSIZE];
517
518				GET_ARG_NUMERIC(val, len | 0x80);
519				s = u2s(val, 10, false, buf, &slen);
520				APPEND_PADDED_S(s, slen, width, left_justify);
521				f++;
522				break;
523			} case 'x': case 'X': {
524				uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
525				char buf[X2S_BUFSIZE];
526
527				GET_ARG_NUMERIC(val, len | 0x80);
528				s = x2s(val, alt_form, *f == 'X', buf, &slen);
529				APPEND_PADDED_S(s, slen, width, left_justify);
530				f++;
531				break;
532			} case 'c': {
533				unsigned char val;
534				char buf[2];
535
536				assert(len == '?' || len == 'l');
537				assert_not_implemented(len != 'l');
538				val = va_arg(ap, int);
539				buf[0] = val;
540				buf[1] = '\0';
541				APPEND_PADDED_S(buf, 1, width, left_justify);
542				f++;
543				break;
544			} case 's':
545				assert(len == '?' || len == 'l');
546				assert_not_implemented(len != 'l');
547				s = va_arg(ap, char *);
548				slen = (prec == -1) ? strlen(s) : prec;
549				APPEND_PADDED_S(s, slen, width, left_justify);
550				f++;
551				break;
552			case 'p': {
553				uintmax_t val;
554				char buf[X2S_BUFSIZE];
555
556				GET_ARG_NUMERIC(val, 'p');
557				s = x2s(val, true, false, buf, &slen);
558				APPEND_PADDED_S(s, slen, width, left_justify);
559				f++;
560				break;
561			}
562			default: not_implemented();
563			}
564			break;
565		} default: {
566			APPEND_C(*f);
567			f++;
568			break;
569		}}
570	}
571	label_out:
572	if (i < size)
573		str[i] = '\0';
574	else
575		str[size - 1] = '\0';
576	ret = i;
577
578#undef APPEND_C
579#undef APPEND_S
580#undef APPEND_PADDED_S
581#undef GET_ARG_NUMERIC
582	return (ret);
583}
584
585JEMALLOC_ATTR(format(printf, 3, 4))
586int
587malloc_snprintf(char *str, size_t size, const char *format, ...)
588{
589	int ret;
590	va_list ap;
591
592	va_start(ap, format);
593	ret = malloc_vsnprintf(str, size, format, ap);
594	va_end(ap);
595
596	return (ret);
597}
598
599void
600malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
601    const char *format, va_list ap)
602{
603	char buf[MALLOC_PRINTF_BUFSIZE];
604
605	if (write_cb == NULL) {
606		/*
607		 * The caller did not provide an alternate write_cb callback
608		 * function, so use the default one.  malloc_write() is an
609		 * inline function, so use malloc_message() directly here.
610		 */
611		write_cb = (je_malloc_message != NULL) ? je_malloc_message :
612		    wrtmessage;
613		cbopaque = NULL;
614	}
615
616	malloc_vsnprintf(buf, sizeof(buf), format, ap);
617	write_cb(cbopaque, buf);
618}
619
620/*
621 * Print to a callback function in such a way as to (hopefully) avoid memory
622 * allocation.
623 */
624JEMALLOC_ATTR(format(printf, 3, 4))
625void
626malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque,
627    const char *format, ...)
628{
629	va_list ap;
630
631	va_start(ap, format);
632	malloc_vcprintf(write_cb, cbopaque, format, ap);
633	va_end(ap);
634}
635
636/* Print to stderr in such a way as to avoid memory allocation. */
637JEMALLOC_ATTR(format(printf, 1, 2))
638void
639malloc_printf(const char *format, ...)
640{
641	va_list ap;
642
643	va_start(ap, format);
644	malloc_vcprintf(NULL, NULL, format, ap);
645	va_end(ap);
646}