xref: /aosp_15_r20/bionic/libc/stdio/printf_common.h (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/mman.h>
34 #include <sys/types.h>
35 
36 #include <errno.h>
37 #include <float.h>
38 #include <langinfo.h>
39 #include <limits.h>
40 #include <locale.h>
41 #include <math.h>
42 #include <stdarg.h>
43 #include <stddef.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include <wchar.h>
50 
51 #include <platform/bionic/macros.h>
52 
53 #include "fvwrite.h"
54 #include "gdtoa.h"
55 #include "local.h"
56 
57 union arg {
58   int intarg;
59   unsigned int uintarg;
60   long longarg;
61   unsigned long ulongarg;
62   long long longlongarg;
63   unsigned long long ulonglongarg;
64   ptrdiff_t ptrdiffarg;
65   size_t sizearg;
66   ssize_t ssizearg;
67   intmax_t intmaxarg;
68   uintmax_t uintmaxarg;
69   void* pvoidarg;
70   char* pchararg;
71   signed char* pschararg;
72   short* pshortarg;
73   int* pintarg;
74   long* plongarg;
75   long long* plonglongarg;
76   ptrdiff_t* pptrdiffarg;
77   ssize_t* pssizearg;
78   intmax_t* pintmaxarg;
79   double doublearg;
80   long double longdoublearg;
81   wint_t wintarg;
82   wchar_t* pwchararg;
83 };
84 
85 // Helper function for `fprintf to unbuffered unix file': creates a
86 // temporary buffer.  We only work on write-only files; this avoids
87 // worries about ungetc buffers and so forth.
88 //
89 // We prevent inlining because this massively increases the printf()
90 // family's stack usage to support a rare case.
91 __attribute__((__noinline__))
__sbprintf(FILE * fp,const CHAR_TYPE * fmt,va_list ap)92 static int __sbprintf(FILE* fp, const CHAR_TYPE* fmt, va_list ap) {
93   FILE fake;
94   struct __sfileext fakeext;
95   unsigned char buf[BUFSIZ];
96 
97   _FILEEXT_SETUP(&fake, &fakeext);
98   /* copy the important variables */
99   fake._flags = fp->_flags & ~__SNBF;
100   fake._file = fp->_file;
101   fake._cookie = fp->_cookie;
102   fake._write = fp->_write;
103 
104   /* set up the buffer */
105   fake._bf._base = fake._p = buf;
106   fake._bf._size = fake._w = sizeof(buf);
107   fake._lbfsize = 0; /* not actually used, but Just In Case */
108 
109   /* do the work, then copy any error status */
110   int ret = FUNCTION_NAME(&fake, fmt, ap);
111   if (ret >= 0 && __sflush(&fake)) ret = EOF;
112   if (fake._flags & __SERR) fp->_flags |= __SERR;
113   return ret;
114 }
115 
116 static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable, size_t* argtablesiz);
117 static int __grow_type_table(unsigned char** typetable, int* tablesize);
118 
119 #define DEFPREC 6
120 
121 #define to_digit(c) ((c) - '0')
122 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
123 #define to_char(n) ((CHAR_TYPE)((n) + '0'))
124 
125 template <typename CharT>
exponent(CharT * p0,int exp,int fmtch)126 static int exponent(CharT* p0, int exp, int fmtch) {
127   CharT* p = p0;
128   *p++ = fmtch;
129   if (exp < 0) {
130     exp = -exp;
131     *p++ = '-';
132   } else {
133     *p++ = '+';
134   }
135 
136   CharT expbuf[MAXEXPDIG];
137   CharT* t = expbuf + MAXEXPDIG;
138   if (exp > 9) {
139     do {
140       *--t = to_char(exp % 10);
141     } while ((exp /= 10) > 9);
142     *--t = to_char(exp);
143     for (; t < expbuf + MAXEXPDIG; *p++ = *t++) /* nothing */;
144   } else {
145     /*
146      * Exponents for decimal floating point conversions
147      * (%[eEgG]) must be at least two characters long,
148      * whereas exponents for hexadecimal conversions can
149      * be only one character long.
150      */
151     if (fmtch == 'e' || fmtch == 'E') *p++ = '0';
152     *p++ = to_char(exp);
153   }
154   return (p - p0);
155 }
156 
157 #define PAD(howmany, with)     \
158   do {                         \
159     if ((n = (howmany)) > 0) { \
160       while (n > PADSIZE) {    \
161         PRINT(with, PADSIZE);  \
162         n -= PADSIZE;          \
163       }                        \
164       PRINT(with, n);          \
165     }                          \
166   } while (0)
167 
168 #define PRINTANDPAD(p, ep, len, with)       \
169   do {                                      \
170     n2 = (ep) - (p);                        \
171     if (n2 > (len)) n2 = (len);             \
172     if (n2 > 0) PRINT((p), n2);             \
173     PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
174   } while (0)
175 
176 /*
177  * The size of the buffer we use as scratch space for integer
178  * conversions, among other things.  Technically, we would need the
179  * most space for base 10 conversions with thousands' grouping
180  * characters between each pair of digits.  100 bytes is a
181  * conservative overestimate even for a 128-bit uintmax_t.
182  */
183 #define BUF 100
184 
185 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
186 
187 /*
188  * Flags used during conversion.
189  */
190 #define ALT 0x0001      /* alternate form */
191 #define LADJUST 0x0004  /* left adjustment */
192 #define LONGDBL 0x0008  /* long double */
193 #define LONGINT 0x0010  /* long integer */
194 #define LLONGINT 0x0020 /* long long integer */
195 #define SHORTINT 0x0040 /* short integer */
196 #define ZEROPAD 0x0080  /* zero (as opposed to blank) pad */
197 #define FPT 0x0100      /* Floating point number */
198 #define PTRINT 0x0200   /* (unsigned) ptrdiff_t */
199 #define SIZEINT 0x0400  /* (signed) size_t */
200 #define CHARINT 0x0800  /* 8 bit integer */
201 #define MAXINT 0x1000   /* largest integer size (intmax_t) */
202 
203 /*
204  * Type ids for argument type table.
205  */
206 #define T_UNUSED 0
207 #define T_SHORT 1
208 #define T_U_SHORT 2
209 #define TP_SHORT 3
210 #define T_INT 4
211 #define T_U_INT 5
212 #define TP_INT 6
213 #define T_LONG 7
214 #define T_U_LONG 8
215 #define TP_LONG 9
216 #define T_LLONG 10
217 #define T_U_LLONG 11
218 #define TP_LLONG 12
219 #define T_DOUBLE 13
220 #define T_LONG_DOUBLE 14
221 #define TP_CHAR 15
222 #define TP_VOID 16
223 #define T_PTRINT 17
224 #define TP_PTRINT 18
225 #define T_SIZEINT 19
226 #define T_SSIZEINT 20
227 #define TP_SSIZEINT 21
228 #define T_MAXINT 22
229 #define T_MAXUINT 23
230 #define TP_MAXINT 24
231 #define T_CHAR 25
232 #define T_U_CHAR 26
233 #define T_WINT 27
234 #define TP_WCHAR 28
235 
236 // To extend shorts properly, we need both signed and unsigned
237 // argument extraction methods.
238 #define SARG()                                                                               \
239   ((intmax_t)(flags & MAXINT                                                                 \
240                   ? GETARG(intmax_t)                                                         \
241                   : flags & LLONGINT                                                         \
242                         ? GETARG(long long)                                                  \
243                         : flags & LONGINT                                                    \
244                               ? GETARG(long)                                                 \
245                               : flags & PTRINT                                               \
246                                     ? GETARG(ptrdiff_t)                                      \
247                                     : flags & SIZEINT                                        \
248                                           ? GETARG(ssize_t)                                  \
249                                           : flags & SHORTINT                                 \
250                                                 ? (short)GETARG(int)                         \
251                                                 : flags & CHARINT ? (signed char)GETARG(int) \
252                                                                   : GETARG(int)))
253 #define UARG()                                                                                \
254   ((uintmax_t)(flags & MAXINT                                                                 \
255                    ? GETARG(uintmax_t)                                                        \
256                    : flags & LLONGINT                                                         \
257                          ? GETARG(unsigned long long)                                         \
258                          : flags & LONGINT                                                    \
259                                ? GETARG(unsigned long)                                        \
260                                : flags & PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */    \
261                                      flags & SIZEINT                                          \
262                                          ? GETARG(size_t)                                     \
263                                          : flags & SHORTINT                                   \
264                                                ? (unsigned short)GETARG(int)                  \
265                                                : flags & CHARINT ? (unsigned char)GETARG(int) \
266                                                                  : GETARG(unsigned int)))
267 
268 // Append a digit to a value and check for overflow.
269 #define APPEND_DIGIT(val, dig)                            \
270   do {                                                    \
271     if ((val) > INT_MAX / 10) goto overflow;              \
272     (val) *= 10;                                          \
273     if ((val) > INT_MAX - to_digit((dig))) goto overflow; \
274     (val) += to_digit((dig));                             \
275   } while (0)
276 
277 // Get * arguments, including the form *nn$.  Preserve the nextarg
278 // that the argument can be gotten once the type is determined.
279 #define GETASTER(val)                                                     \
280   n2 = 0;                                                                 \
281   cp = fmt;                                                               \
282   while (is_digit(*cp)) {                                                 \
283     APPEND_DIGIT(n2, *cp);                                                \
284     cp++;                                                                 \
285   }                                                                       \
286   if (*cp == '$') {                                                       \
287     int hold = nextarg;                                                   \
288     if (argtable == NULL) {                                               \
289       argtable = statargtable;                                            \
290       if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) { \
291         ret = -1;                                                         \
292         goto error;                                                       \
293       }                                                                   \
294     }                                                                     \
295     nextarg = n2;                                                         \
296     val = GETARG(int);                                                    \
297     nextarg = hold;                                                       \
298     fmt = ++cp;                                                           \
299   } else {                                                                \
300     val = GETARG(int);                                                    \
301   }
302 
303 // Get the argument indexed by nextarg.   If the argument table is
304 // built, use it to get the argument.  If its not, get the next
305 // argument (and arguments must be gotten sequentially).
306 #define GETARG(type) \
307   ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : (nextarg++, va_arg(ap, type)))
308 
309 /*
310  * Find all arguments when a positional parameter is encountered.  Returns a
311  * table, indexed by argument number, of pointers to each arguments.  The
312  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
313  * It will be replaced with a mmap-ed one if it overflows (malloc cannot be
314  * used since we are attempting to make snprintf thread safe, and alloca is
315  * problematic since we have nested functions..)
316  */
__find_arguments(const CHAR_TYPE * fmt0,va_list ap,union arg ** argtable,size_t * argtablesiz)317 static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable,
318                             size_t* argtablesiz) {
319   int ch;                   /* character from fmt */
320   int n, n2;                /* handy integer (short term usage) */
321   int flags;                /* flags as above */
322   unsigned char* typetable; /* table of types */
323   unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
324   int tablesize; /* current size of type table */
325   int tablemax;  /* largest used index in table */
326   int nextarg;   /* 1-based argument index */
327   int ret = 0;   /* return value */
328 
329   /*
330    * Add an argument type to the table, expanding if necessary.
331    */
332 #define ADDTYPE(type)                                                      \
333   ((nextarg >= tablesize) ? __grow_type_table(&typetable, &tablesize) : 0, \
334    (nextarg > tablemax) ? tablemax = nextarg : 0, typetable[nextarg++] = type)
335 
336 #define ADDSARG()                                                                             \
337   ((flags & MAXINT)                                                                           \
338        ? ADDTYPE(T_MAXINT)                                                                    \
339        : ((flags & PTRINT) ? ADDTYPE(T_PTRINT)                                                \
340                            : ((flags & SIZEINT)                                               \
341                                   ? ADDTYPE(T_SSIZEINT)                                       \
342                                   : ((flags & LLONGINT)                                       \
343                                          ? ADDTYPE(T_LLONG)                                   \
344                                          : ((flags & LONGINT)                                 \
345                                                 ? ADDTYPE(T_LONG)                             \
346                                                 : ((flags & SHORTINT)                         \
347                                                        ? ADDTYPE(T_SHORT)                     \
348                                                        : ((flags & CHARINT) ? ADDTYPE(T_CHAR) \
349                                                                             : ADDTYPE(T_INT))))))))
350 
351 #define ADDUARG()                                                                  \
352   ((flags & MAXINT)                                                                \
353        ? ADDTYPE(T_MAXUINT)                                                        \
354        : ((flags & PTRINT)                                                         \
355               ? ADDTYPE(T_PTRINT)                                                  \
356               : ((flags & SIZEINT)                                                 \
357                      ? ADDTYPE(T_SIZEINT)                                          \
358                      : ((flags & LLONGINT)                                         \
359                             ? ADDTYPE(T_U_LLONG)                                   \
360                             : ((flags & LONGINT)                                   \
361                                    ? ADDTYPE(T_U_LONG)                             \
362                                    : ((flags & SHORTINT)                           \
363                                           ? ADDTYPE(T_U_SHORT)                     \
364                                           : ((flags & CHARINT) ? ADDTYPE(T_U_CHAR) \
365                                                                : ADDTYPE(T_U_INT))))))))
366 
367   /*
368    * Add * arguments to the type array.
369    */
370 #define ADDASTER()         \
371   n2 = 0;                  \
372   cp = fmt;                \
373   while (is_digit(*cp)) {  \
374     APPEND_DIGIT(n2, *cp); \
375     cp++;                  \
376   }                        \
377   if (*cp == '$') {        \
378     int hold = nextarg;    \
379     nextarg = n2;          \
380     ADDTYPE(T_INT);        \
381     nextarg = hold;        \
382     fmt = ++cp;            \
383   } else {                 \
384     ADDTYPE(T_INT);        \
385   }
386   CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0);
387   CHAR_TYPE* cp;
388   typetable = stattypetable;
389   tablesize = STATIC_ARG_TBL_SIZE;
390   tablemax = 0;
391   nextarg = 1;
392   memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
393 
394   /*
395    * Scan the format for conversions (`%' character).
396    */
397   for (;;) {
398     for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) continue;
399     if (ch == '\0') goto done;
400     fmt++; /* skip over '%' */
401 
402     flags = 0;
403 
404   rflag:
405     ch = *fmt++;
406   reswitch:
407     switch (ch) {
408       case ' ':
409       case '#':
410       case '\'':
411         goto rflag;
412       case '*':
413         ADDASTER();
414         goto rflag;
415       case '-':
416       case '+':
417         goto rflag;
418       case '.':
419         if ((ch = *fmt++) == '*') {
420           ADDASTER();
421           goto rflag;
422         }
423         while (is_digit(ch)) {
424           ch = *fmt++;
425         }
426         goto reswitch;
427       case '0':
428         goto rflag;
429       case '1':
430       case '2':
431       case '3':
432       case '4':
433       case '5':
434       case '6':
435       case '7':
436       case '8':
437       case '9':
438         n = 0;
439         do {
440           APPEND_DIGIT(n, ch);
441           ch = *fmt++;
442         } while (is_digit(ch));
443         if (ch == '$') {
444           nextarg = n;
445           goto rflag;
446         }
447         goto reswitch;
448       case 'L':
449         flags |= LONGDBL;
450         goto rflag;
451       case 'h':
452         if (*fmt == 'h') {
453           fmt++;
454           flags |= CHARINT;
455         } else {
456           flags |= SHORTINT;
457         }
458         goto rflag;
459       case 'j':
460         flags |= MAXINT;
461         goto rflag;
462       case 'l':
463         if (*fmt == 'l') {
464           fmt++;
465           flags |= LLONGINT;
466         } else {
467           flags |= LONGINT;
468         }
469         goto rflag;
470       case 'q':
471         flags |= LLONGINT;
472         goto rflag;
473       case 't':
474         flags |= PTRINT;
475         goto rflag;
476       case 'z':
477         flags |= SIZEINT;
478         goto rflag;
479       case 'C':
480         flags |= LONGINT;
481         __BIONIC_FALLTHROUGH;
482       case 'c':
483         if (flags & LONGINT)
484           ADDTYPE(T_WINT);
485         else
486           ADDTYPE(T_INT);
487         break;
488       case 'D':
489         flags |= LONGINT;
490         __BIONIC_FALLTHROUGH;
491       case 'd':
492       case 'i':
493         ADDSARG();
494         break;
495       case 'a':
496       case 'A':
497       case 'e':
498       case 'E':
499       case 'f':
500       case 'F':
501       case 'g':
502       case 'G':
503         if (flags & LONGDBL)
504           ADDTYPE(T_LONG_DOUBLE);
505         else
506           ADDTYPE(T_DOUBLE);
507         break;
508       case 'n':
509         __fortify_fatal("%%n not allowed on Android");
510       case 'O':
511         flags |= LONGINT;
512         __BIONIC_FALLTHROUGH;
513       case 'o':
514         ADDUARG();
515         break;
516       case 'p':
517         ADDTYPE(TP_VOID);
518         break;
519       case 'S':
520         flags |= LONGINT;
521         __BIONIC_FALLTHROUGH;
522       case 's':
523         ADDTYPE((flags & LONGINT) ? TP_WCHAR : TP_CHAR);
524         break;
525       case 'U':
526         flags |= LONGINT;
527         __BIONIC_FALLTHROUGH;
528       case 'u':
529       case 'X':
530       case 'x':
531       case 'B':
532       case 'b':
533         ADDUARG();
534         break;
535       case 'w': {
536         n = 0;
537         bool fast = false;
538         ch = *fmt++;
539         if (ch == 'f') {
540           fast = true;
541           ch = *fmt++;
542         }
543         while (is_digit(ch)) {
544           APPEND_DIGIT(n, ch);
545           ch = *fmt++;
546         }
547         if (n == 64) {
548           flags |= LLONGINT;
549         } else {
550           if (n != 8 && fast) {
551 #if defined(__LP64__)
552             flags |= LLONGINT;
553 #endif
554           }
555         }
556         goto reswitch;
557       }
558       default: /* "%?" prints ?, unless ? is NUL */
559         if (ch == '\0') goto done;
560         break;
561     }
562   }
563 done:
564   /*
565    * Build the argument table.
566    */
567   if (tablemax >= STATIC_ARG_TBL_SIZE) {
568     *argtablesiz = sizeof(union arg) * (tablemax + 1);
569     *argtable = static_cast<arg*>(mmap(nullptr, *argtablesiz,
570                                        PROT_WRITE | PROT_READ,
571                                        MAP_ANON | MAP_PRIVATE, -1, 0));
572     if (*argtable == MAP_FAILED) return -1;
573   }
574 
575   for (n = 1; n <= tablemax; n++) {
576     switch (typetable[n]) {
577       case T_UNUSED:
578       case T_CHAR:
579       case T_U_CHAR:
580       case T_SHORT:
581       case T_U_SHORT:
582       case T_INT:
583         (*argtable)[n].intarg = va_arg(ap, int);
584         break;
585       case TP_SHORT:
586         (*argtable)[n].pshortarg = va_arg(ap, short*);
587         break;
588       case T_U_INT:
589         (*argtable)[n].uintarg = va_arg(ap, unsigned int);
590         break;
591       case TP_INT:
592         (*argtable)[n].pintarg = va_arg(ap, int*);
593         break;
594       case T_LONG:
595         (*argtable)[n].longarg = va_arg(ap, long);
596         break;
597       case T_U_LONG:
598         (*argtable)[n].ulongarg = va_arg(ap, unsigned long);
599         break;
600       case TP_LONG:
601         (*argtable)[n].plongarg = va_arg(ap, long*);
602         break;
603       case T_LLONG:
604         (*argtable)[n].longlongarg = va_arg(ap, long long);
605         break;
606       case T_U_LLONG:
607         (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
608         break;
609       case TP_LLONG:
610         (*argtable)[n].plonglongarg = va_arg(ap, long long*);
611         break;
612       case T_DOUBLE:
613         (*argtable)[n].doublearg = va_arg(ap, double);
614         break;
615       case T_LONG_DOUBLE:
616         (*argtable)[n].longdoublearg = va_arg(ap, long double);
617         break;
618       case TP_CHAR:
619         (*argtable)[n].pchararg = va_arg(ap, char*);
620         break;
621       case TP_VOID:
622         (*argtable)[n].pvoidarg = va_arg(ap, void*);
623         break;
624       case T_PTRINT:
625         (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
626         break;
627       case TP_PTRINT:
628         (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t*);
629         break;
630       case T_SIZEINT:
631         (*argtable)[n].sizearg = va_arg(ap, size_t);
632         break;
633       case T_SSIZEINT:
634         (*argtable)[n].ssizearg = va_arg(ap, ssize_t);
635         break;
636       case TP_SSIZEINT:
637         (*argtable)[n].pssizearg = va_arg(ap, ssize_t*);
638         break;
639       case T_MAXINT:
640         (*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
641         break;
642       case T_MAXUINT:
643         (*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t);
644         break;
645       case TP_MAXINT:
646         (*argtable)[n].pintmaxarg = va_arg(ap, intmax_t*);
647         break;
648       case T_WINT:
649         (*argtable)[n].wintarg = va_arg(ap, wint_t);
650         break;
651       case TP_WCHAR:
652         (*argtable)[n].pwchararg = va_arg(ap, wchar_t*);
653         break;
654     }
655   }
656   goto finish;
657 
658 overflow:
659   errno = ENOMEM;
660   ret = -1;
661 
662 finish:
663   if (typetable != nullptr && typetable != stattypetable) {
664     munmap(typetable, *argtablesiz);
665     typetable = nullptr;
666   }
667   return (ret);
668 }
669 
670 /*
671  * Increase the size of the type table.
672  */
__grow_type_table(unsigned char ** typetable,int * tablesize)673 static int __grow_type_table(unsigned char** typetable, int* tablesize) {
674   unsigned char* old_table = *typetable;
675   int new_size = *tablesize * 2;
676 
677   if (new_size < getpagesize()) new_size = getpagesize();
678 
679   if (*tablesize == STATIC_ARG_TBL_SIZE) {
680     *typetable = static_cast<unsigned char*>(mmap(nullptr, new_size,
681                                                   PROT_WRITE | PROT_READ,
682                                                   MAP_ANON | MAP_PRIVATE, -1, 0));
683     if (*typetable == MAP_FAILED) return -1;
684     bcopy(old_table, *typetable, *tablesize);
685   } else {
686     unsigned char* new_table = static_cast<unsigned char*>(mmap(nullptr, new_size,
687                                                                 PROT_WRITE | PROT_READ,
688                                                                 MAP_ANON | MAP_PRIVATE, -1, 0));
689     if (new_table == MAP_FAILED) return -1;
690     memmove(new_table, *typetable, *tablesize);
691     munmap(*typetable, *tablesize);
692     *typetable = new_table;
693   }
694   memset(*typetable + *tablesize, T_UNUSED, (new_size - *tablesize));
695 
696   *tablesize = new_size;
697   return 0;
698 }
699 
700 struct helpers {
701   // Flush out all the vectors defined by the given uio,
702   // then reset it so that it can be reused.
sprinthelpers703   static int sprint(FILE* fp, struct __suio* uio) {
704     if (uio->uio_resid == 0) {
705       uio->uio_iovcnt = 0;
706       return 0;
707     }
708     int result = __sfvwrite(fp, uio);
709     uio->uio_resid = 0;
710     uio->uio_iovcnt = 0;
711     return result;
712   }
713 
714   // Convert a wide character string argument for the %ls format to a multibyte
715   // string representation. If not -1, prec specifies the maximum number of
716   // bytes to output, and also means that we can't assume that the wide char
717   // string is null-terminated.
wcsconvhelpers718   static char* wcsconv(wchar_t* wcsarg, int prec) {
719     mbstate_t mbs;
720     char buf[MB_LEN_MAX];
721     wchar_t* p;
722     char* convbuf;
723     size_t clen, nbytes;
724 
725     // Allocate space for the maximum number of bytes we could output.
726     if (prec < 0) {
727       memset(&mbs, 0, sizeof(mbs));
728       p = wcsarg;
729       nbytes = wcsrtombs(nullptr, (const wchar_t**)&p, 0, &mbs);
730       if (nbytes == (size_t)-1) return nullptr;
731     } else {
732       // Optimisation: if the output precision is small enough,
733       // just allocate enough memory for the maximum instead of
734       // scanning the string.
735       if (prec < 128) {
736         nbytes = prec;
737       } else {
738         nbytes = 0;
739         p = wcsarg;
740         memset(&mbs, 0, sizeof(mbs));
741         for (;;) {
742           clen = wcrtomb(buf, *p++, &mbs);
743           if (clen == 0 || clen == (size_t)-1 || nbytes + clen > (size_t)prec) break;
744           nbytes += clen;
745         }
746         if (clen == (size_t)-1) return nullptr;
747       }
748     }
749     if ((convbuf = static_cast<char*>(malloc(nbytes + 1))) == nullptr) return nullptr;
750 
751     // Fill the output buffer.
752     p = wcsarg;
753     memset(&mbs, 0, sizeof(mbs));
754     if ((nbytes = wcsrtombs(convbuf, (const wchar_t**)&p, nbytes, &mbs)) == (size_t)-1) {
755       free(convbuf);
756       return nullptr;
757     }
758     convbuf[nbytes] = '\0';
759     return convbuf;
760   }
761 
762   // Like __fputwc_unlock, but handles fake string (__SSTR) files properly.
763   // File must already be locked.
xfputwchelpers764   static wint_t xfputwc(wchar_t wc, FILE* fp) {
765     if ((fp->_flags & __SSTR) == 0) return __fputwc_unlock(wc, fp);
766 
767     char buf[MB_LEN_MAX];
768     mbstate_t mbs = {};
769     size_t len = wcrtomb(buf, wc, &mbs);
770     if (len == (size_t)-1) {
771       fp->_flags |= __SERR;
772       errno = EILSEQ;
773       return WEOF;
774     }
775 
776     struct __siov iov;
777     iov.iov_base = buf;
778     iov.iov_len = len;
779     struct __suio uio;
780     uio.uio_iov = &iov;
781     uio.uio_resid = len;
782     uio.uio_iovcnt = 1;
783     return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF);
784   }
785 
786   // Convert a multibyte character string argument for the %s format to a wide
787   // string representation. ``prec'' specifies the maximum number of bytes
788   // to output. If ``prec'' is greater than or equal to zero, we can't assume
789   // that the multibyte character string ends in a null character.
790   //
791   // Returns NULL on failure.
792   // To find out what happened check errno for ENOMEM, EILSEQ and EINVAL.
mbsconvhelpers793   static wchar_t* mbsconv(const char* mbsarg, int prec) {
794     mbstate_t mbs;
795     const char* p;
796     size_t insize, nchars, nconv;
797 
798     if (mbsarg == nullptr) return nullptr;
799 
800     // Supplied argument is a multibyte string; convert it to wide characters first.
801     if (prec >= 0) {
802       // String is not guaranteed to be NUL-terminated. Find the number of characters to print.
803       p = mbsarg;
804       insize = nchars = nconv = 0;
805       bzero(&mbs, sizeof(mbs));
806       while (nchars != (size_t)prec) {
807         nconv = mbrlen(p, MB_CUR_MAX, &mbs);
808         if (nconv == (size_t)0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
809         p += nconv;
810         nchars++;
811         insize += nconv;
812       }
813       if (nconv == (size_t)-1 || nconv == (size_t)-2) return (nullptr);
814     } else {
815       insize = strlen(mbsarg);
816     }
817 
818     // Allocate buffer for the result and perform the conversion,
819     // converting at most `size' bytes of the input multibyte string to
820     // wide characters for printing.
821     wchar_t* convbuf = static_cast<wchar_t*>(calloc(insize + 1, sizeof(*convbuf)));
822     if (convbuf == nullptr) return nullptr;
823     wchar_t* wcp = convbuf;
824     p = mbsarg;
825     bzero(&mbs, sizeof(mbs));
826     nconv = 0;
827     while (insize != 0) {
828       nconv = mbrtowc(wcp, p, insize, &mbs);
829       if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
830       wcp++;
831       p += nconv;
832       insize -= nconv;
833     }
834     if (nconv == (size_t)-1 || nconv == (size_t)-2) {
835       free(convbuf);
836       return nullptr;
837     }
838     *wcp = '\0';
839 
840     return convbuf;
841   }
842 
843   // Trasnlate a fixed size integer argument for the %w/%wf format to a
844   // flag representation. Supported sizes are 8, 16, 32, and 64 so far.
845   // See details in bionic/libc/include/stdint.h
w_to_flaghelpers846   static int w_to_flag(int size, bool fast) {
847     static constexpr int fast_size = sizeof(void*) == 8 ? LLONGINT : 0;
848     if (size == 8) return CHARINT;
849     if (size == 16) return fast ? fast_size : SHORTINT;
850     if (size == 32) return fast ? fast_size : 0;
851     if (size == 64) return LLONGINT;
852     __fortify_fatal("%%w%s%d is unsupported", fast ? "f" : "", size);
853   }
854 };
855