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