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