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