1 // Debugging support -*- C++ -*- 2 3 // Copyright (C) 2013-2021 Free Software Foundation, Inc. 4 // 5 // This file is part of GCC. 6 // 7 // GCC is free software; you can redistribute it and/or modify 8 // it under the terms of the GNU General Public License as published by 9 // the Free Software Foundation; either version 3, or (at your option) 10 // any later version. 11 // 12 // GCC is distributed in the hope that it will be useful, 13 // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 // GNU General Public License for more details. 16 // 17 // Under Section 7 of GPL version 3, you are granted additional 18 // permissions described in the GCC Runtime Library Exception, version 19 // 3.1, as published by the Free Software Foundation. 20 21 // You should have received a copy of the GNU General Public License and 22 // a copy of the GCC Runtime Library Exception along with this program; 23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 // <http://www.gnu.org/licenses/>. 25 26 #include <stdarg.h> 27 #include <bits/functexcept.h> 28 #include <bits/locale_facets.h> 29 30 namespace std { 31 _GLIBCXX_BEGIN_NAMESPACE_VERSION 32 template<typename _CharT, typename _ValueT> 33 int 34 __int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit, 35 ios_base::fmtflags __flags, bool __dec); 36 _GLIBCXX_END_NAMESPACE_VERSION 37 } 38 39 namespace __gnu_cxx { 40 41 // Private helper to throw logic error if snprintf_lite runs out 42 // of space (which is not expected to ever happen). 43 // NUL-terminates __buf. 44 void 45 __throw_insufficient_space(const char *__buf, const char *__bufend) 46 __attribute__((__noreturn__)); 47 48 void __throw_insufficient_space(const char * __buf,const char * __bufend)49 __throw_insufficient_space(const char *__buf, const char *__bufend) 50 { 51 // Include space for trailing NUL. 52 const size_t __len = __bufend - __buf + 1; 53 54 const char __err[] = "not enough space for format expansion " 55 "(Please submit full bug report at https://gcc.gnu.org/bugs/):\n "; 56 const size_t __errlen = sizeof(__err) - 1; 57 58 char *const __e 59 = static_cast<char*>(__builtin_alloca(__errlen + __len)); 60 61 __builtin_memcpy(__e, __err, __errlen); 62 __builtin_memcpy(__e + __errlen, __buf, __len - 1); 63 __e[__errlen + __len - 1] = '\0'; 64 std::__throw_logic_error(__e); 65 } 66 67 68 // Private routine to append decimal representation of VAL to the given 69 // BUFFER, but not more than BUFSIZE characters. 70 // Does not NUL-terminate the output buffer. 71 // Returns number of characters appended, or -1 if BUFSIZE is too small. __concat_size_t(char * __buf,size_t __bufsize,size_t __val)72 int __concat_size_t(char *__buf, size_t __bufsize, size_t __val) 73 { 74 // Long enough for decimal representation. 75 int __ilen = 3 * sizeof(__val); 76 char *__cs = static_cast<char*>(__builtin_alloca(__ilen)); 77 char* __out = __cs + __ilen; 78 do 79 { 80 *--__out = "0123456789"[__val % 10]; 81 __val /= 10; 82 } 83 while (__val != 0); 84 size_t __len = __cs + __ilen - __out; 85 if (__bufsize < __len) 86 return -1; 87 88 __builtin_memcpy(__buf, __cs + __ilen - __len, __len); 89 return __len; 90 } 91 92 93 // Private routine to print into __buf arguments according to format, 94 // not to exceed __bufsize. 95 // Only '%%', '%s' and '%zu' format specifiers are understood. 96 // Returns number of characters printed (excluding terminating NUL). 97 // Always NUL-terminates __buf. 98 // Throws logic_error on insufficient space. __snprintf_lite(char * __buf,size_t __bufsize,const char * __fmt,va_list __ap)99 int __snprintf_lite(char *__buf, size_t __bufsize, const char *__fmt, 100 va_list __ap) 101 { 102 char *__d = __buf; 103 const char *__s = __fmt; 104 const char *const __limit = __d + __bufsize - 1; // Leave space for NUL. 105 106 while (__s[0] != '\0' && __d < __limit) 107 { 108 if (__s[0] == '%') 109 switch (__s[1]) 110 { 111 default: // Stray '%'. Just print it. 112 break; 113 case '%': // '%%' 114 __s += 1; 115 break; 116 case 's': // '%s'. 117 { 118 const char *__v = va_arg(__ap, const char *); 119 120 while (__v[0] != '\0' && __d < __limit) 121 *__d++ = *__v++; 122 123 if (__v[0] != '\0') 124 // Not enough space for __fmt expansion. 125 __throw_insufficient_space(__buf, __d); 126 127 __s += 2; // Step over %s. 128 continue; 129 } 130 break; 131 case 'z': 132 if (__s[2] == 'u') // '%zu' -- expand next size_t arg. 133 { 134 const int __len = __concat_size_t(__d, __limit - __d, 135 va_arg(__ap, size_t)); 136 if (__len > 0) 137 __d += __len; 138 else 139 // Not enough space for __fmt expansion. 140 __throw_insufficient_space(__buf, __d); 141 142 __s += 3; // Step over %zu 143 continue; 144 } 145 // Stray '%zX'. Just print it. 146 break; 147 } 148 *__d++ = *__s++; 149 } 150 151 if (__s[0] != '\0') 152 // Not enough space for __fmt expansion. 153 __throw_insufficient_space(__buf, __d); 154 155 *__d = '\0'; 156 return __d - __buf; 157 } 158 159 } // __gnu_cxx 160