xref: /aosp_15_r20/external/compiler-rt/lib/sanitizer_common/sanitizer_printf.cc (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //===-- sanitizer_printf.cc -----------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot //                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is shared between AddressSanitizer and ThreadSanitizer.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot // Internal printf function, used inside run-time libraries.
13*7c3d14c8STreehugger Robot // We can't use libc printf because we intercept some of the functions used
14*7c3d14c8STreehugger Robot // inside it.
15*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
16*7c3d14c8STreehugger Robot 
17*7c3d14c8STreehugger Robot #include "sanitizer_common.h"
18*7c3d14c8STreehugger Robot #include "sanitizer_flags.h"
19*7c3d14c8STreehugger Robot #include "sanitizer_libc.h"
20*7c3d14c8STreehugger Robot 
21*7c3d14c8STreehugger Robot #include <stdio.h>
22*7c3d14c8STreehugger Robot #include <stdarg.h>
23*7c3d14c8STreehugger Robot 
24*7c3d14c8STreehugger Robot #if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 &&               \
25*7c3d14c8STreehugger Robot       !defined(va_copy)
26*7c3d14c8STreehugger Robot # define va_copy(dst, src) ((dst) = (src))
27*7c3d14c8STreehugger Robot #endif
28*7c3d14c8STreehugger Robot 
29*7c3d14c8STreehugger Robot namespace __sanitizer {
30*7c3d14c8STreehugger Robot 
31*7c3d14c8STreehugger Robot StaticSpinMutex CommonSanitizerReportMutex;
32*7c3d14c8STreehugger Robot 
AppendChar(char ** buff,const char * buff_end,char c)33*7c3d14c8STreehugger Robot static int AppendChar(char **buff, const char *buff_end, char c) {
34*7c3d14c8STreehugger Robot   if (*buff < buff_end) {
35*7c3d14c8STreehugger Robot     **buff = c;
36*7c3d14c8STreehugger Robot     (*buff)++;
37*7c3d14c8STreehugger Robot   }
38*7c3d14c8STreehugger Robot   return 1;
39*7c3d14c8STreehugger Robot }
40*7c3d14c8STreehugger Robot 
41*7c3d14c8STreehugger Robot // Appends number in a given base to buffer. If its length is less than
42*7c3d14c8STreehugger Robot // |minimal_num_length|, it is padded with leading zeroes or spaces, depending
43*7c3d14c8STreehugger Robot // on the value of |pad_with_zero|.
AppendNumber(char ** buff,const char * buff_end,u64 absolute_value,u8 base,u8 minimal_num_length,bool pad_with_zero,bool negative)44*7c3d14c8STreehugger Robot static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
45*7c3d14c8STreehugger Robot                         u8 base, u8 minimal_num_length, bool pad_with_zero,
46*7c3d14c8STreehugger Robot                         bool negative) {
47*7c3d14c8STreehugger Robot   uptr const kMaxLen = 30;
48*7c3d14c8STreehugger Robot   RAW_CHECK(base == 10 || base == 16);
49*7c3d14c8STreehugger Robot   RAW_CHECK(base == 10 || !negative);
50*7c3d14c8STreehugger Robot   RAW_CHECK(absolute_value || !negative);
51*7c3d14c8STreehugger Robot   RAW_CHECK(minimal_num_length < kMaxLen);
52*7c3d14c8STreehugger Robot   int result = 0;
53*7c3d14c8STreehugger Robot   if (negative && minimal_num_length)
54*7c3d14c8STreehugger Robot     --minimal_num_length;
55*7c3d14c8STreehugger Robot   if (negative && pad_with_zero)
56*7c3d14c8STreehugger Robot     result += AppendChar(buff, buff_end, '-');
57*7c3d14c8STreehugger Robot   uptr num_buffer[kMaxLen];
58*7c3d14c8STreehugger Robot   int pos = 0;
59*7c3d14c8STreehugger Robot   do {
60*7c3d14c8STreehugger Robot     RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow");
61*7c3d14c8STreehugger Robot     num_buffer[pos++] = absolute_value % base;
62*7c3d14c8STreehugger Robot     absolute_value /= base;
63*7c3d14c8STreehugger Robot   } while (absolute_value > 0);
64*7c3d14c8STreehugger Robot   if (pos < minimal_num_length) {
65*7c3d14c8STreehugger Robot     // Make sure compiler doesn't insert call to memset here.
66*7c3d14c8STreehugger Robot     internal_memset(&num_buffer[pos], 0,
67*7c3d14c8STreehugger Robot                     sizeof(num_buffer[0]) * (minimal_num_length - pos));
68*7c3d14c8STreehugger Robot     pos = minimal_num_length;
69*7c3d14c8STreehugger Robot   }
70*7c3d14c8STreehugger Robot   RAW_CHECK(pos > 0);
71*7c3d14c8STreehugger Robot   pos--;
72*7c3d14c8STreehugger Robot   for (; pos >= 0 && num_buffer[pos] == 0; pos--) {
73*7c3d14c8STreehugger Robot     char c = (pad_with_zero || pos == 0) ? '0' : ' ';
74*7c3d14c8STreehugger Robot     result += AppendChar(buff, buff_end, c);
75*7c3d14c8STreehugger Robot   }
76*7c3d14c8STreehugger Robot   if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-');
77*7c3d14c8STreehugger Robot   for (; pos >= 0; pos--) {
78*7c3d14c8STreehugger Robot     char digit = static_cast<char>(num_buffer[pos]);
79*7c3d14c8STreehugger Robot     result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
80*7c3d14c8STreehugger Robot                                                       : 'a' + digit - 10);
81*7c3d14c8STreehugger Robot   }
82*7c3d14c8STreehugger Robot   return result;
83*7c3d14c8STreehugger Robot }
84*7c3d14c8STreehugger Robot 
AppendUnsigned(char ** buff,const char * buff_end,u64 num,u8 base,u8 minimal_num_length,bool pad_with_zero)85*7c3d14c8STreehugger Robot static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base,
86*7c3d14c8STreehugger Robot                           u8 minimal_num_length, bool pad_with_zero) {
87*7c3d14c8STreehugger Robot   return AppendNumber(buff, buff_end, num, base, minimal_num_length,
88*7c3d14c8STreehugger Robot                       pad_with_zero, false /* negative */);
89*7c3d14c8STreehugger Robot }
90*7c3d14c8STreehugger Robot 
AppendSignedDecimal(char ** buff,const char * buff_end,s64 num,u8 minimal_num_length,bool pad_with_zero)91*7c3d14c8STreehugger Robot static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
92*7c3d14c8STreehugger Robot                                u8 minimal_num_length, bool pad_with_zero) {
93*7c3d14c8STreehugger Robot   bool negative = (num < 0);
94*7c3d14c8STreehugger Robot   return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10,
95*7c3d14c8STreehugger Robot                       minimal_num_length, pad_with_zero, negative);
96*7c3d14c8STreehugger Robot }
97*7c3d14c8STreehugger Robot 
AppendString(char ** buff,const char * buff_end,int precision,const char * s)98*7c3d14c8STreehugger Robot static int AppendString(char **buff, const char *buff_end, int precision,
99*7c3d14c8STreehugger Robot                         const char *s) {
100*7c3d14c8STreehugger Robot   if (!s)
101*7c3d14c8STreehugger Robot     s = "<null>";
102*7c3d14c8STreehugger Robot   int result = 0;
103*7c3d14c8STreehugger Robot   for (; *s; s++) {
104*7c3d14c8STreehugger Robot     if (precision >= 0 && result >= precision)
105*7c3d14c8STreehugger Robot       break;
106*7c3d14c8STreehugger Robot     result += AppendChar(buff, buff_end, *s);
107*7c3d14c8STreehugger Robot   }
108*7c3d14c8STreehugger Robot   return result;
109*7c3d14c8STreehugger Robot }
110*7c3d14c8STreehugger Robot 
AppendPointer(char ** buff,const char * buff_end,u64 ptr_value)111*7c3d14c8STreehugger Robot static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
112*7c3d14c8STreehugger Robot   int result = 0;
113*7c3d14c8STreehugger Robot   result += AppendString(buff, buff_end, -1, "0x");
114*7c3d14c8STreehugger Robot   result += AppendUnsigned(buff, buff_end, ptr_value, 16,
115*7c3d14c8STreehugger Robot                            SANITIZER_POINTER_FORMAT_LENGTH, true);
116*7c3d14c8STreehugger Robot   return result;
117*7c3d14c8STreehugger Robot }
118*7c3d14c8STreehugger Robot 
VSNPrintf(char * buff,int buff_length,const char * format,va_list args)119*7c3d14c8STreehugger Robot int VSNPrintf(char *buff, int buff_length,
120*7c3d14c8STreehugger Robot               const char *format, va_list args) {
121*7c3d14c8STreehugger Robot   static const char *kPrintfFormatsHelp =
122*7c3d14c8STreehugger Robot     "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %(\\.\\*)?s; %c\n";
123*7c3d14c8STreehugger Robot   RAW_CHECK(format);
124*7c3d14c8STreehugger Robot   RAW_CHECK(buff_length > 0);
125*7c3d14c8STreehugger Robot   const char *buff_end = &buff[buff_length - 1];
126*7c3d14c8STreehugger Robot   const char *cur = format;
127*7c3d14c8STreehugger Robot   int result = 0;
128*7c3d14c8STreehugger Robot   for (; *cur; cur++) {
129*7c3d14c8STreehugger Robot     if (*cur != '%') {
130*7c3d14c8STreehugger Robot       result += AppendChar(&buff, buff_end, *cur);
131*7c3d14c8STreehugger Robot       continue;
132*7c3d14c8STreehugger Robot     }
133*7c3d14c8STreehugger Robot     cur++;
134*7c3d14c8STreehugger Robot     bool have_width = (*cur >= '0' && *cur <= '9');
135*7c3d14c8STreehugger Robot     bool pad_with_zero = (*cur == '0');
136*7c3d14c8STreehugger Robot     int width = 0;
137*7c3d14c8STreehugger Robot     if (have_width) {
138*7c3d14c8STreehugger Robot       while (*cur >= '0' && *cur <= '9') {
139*7c3d14c8STreehugger Robot         width = width * 10 + *cur++ - '0';
140*7c3d14c8STreehugger Robot       }
141*7c3d14c8STreehugger Robot     }
142*7c3d14c8STreehugger Robot     bool have_precision = (cur[0] == '.' && cur[1] == '*');
143*7c3d14c8STreehugger Robot     int precision = -1;
144*7c3d14c8STreehugger Robot     if (have_precision) {
145*7c3d14c8STreehugger Robot       cur += 2;
146*7c3d14c8STreehugger Robot       precision = va_arg(args, int);
147*7c3d14c8STreehugger Robot     }
148*7c3d14c8STreehugger Robot     bool have_z = (*cur == 'z');
149*7c3d14c8STreehugger Robot     cur += have_z;
150*7c3d14c8STreehugger Robot     bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l');
151*7c3d14c8STreehugger Robot     cur += have_ll * 2;
152*7c3d14c8STreehugger Robot     s64 dval;
153*7c3d14c8STreehugger Robot     u64 uval;
154*7c3d14c8STreehugger Robot     bool have_flags = have_width | have_z | have_ll;
155*7c3d14c8STreehugger Robot     // Only %s supports precision for now
156*7c3d14c8STreehugger Robot     CHECK(!(precision >= 0 && *cur != 's'));
157*7c3d14c8STreehugger Robot     switch (*cur) {
158*7c3d14c8STreehugger Robot       case 'd': {
159*7c3d14c8STreehugger Robot         dval = have_ll ? va_arg(args, s64)
160*7c3d14c8STreehugger Robot              : have_z ? va_arg(args, sptr)
161*7c3d14c8STreehugger Robot              : va_arg(args, int);
162*7c3d14c8STreehugger Robot         result += AppendSignedDecimal(&buff, buff_end, dval, width,
163*7c3d14c8STreehugger Robot                                       pad_with_zero);
164*7c3d14c8STreehugger Robot         break;
165*7c3d14c8STreehugger Robot       }
166*7c3d14c8STreehugger Robot       case 'u':
167*7c3d14c8STreehugger Robot       case 'x': {
168*7c3d14c8STreehugger Robot         uval = have_ll ? va_arg(args, u64)
169*7c3d14c8STreehugger Robot              : have_z ? va_arg(args, uptr)
170*7c3d14c8STreehugger Robot              : va_arg(args, unsigned);
171*7c3d14c8STreehugger Robot         result += AppendUnsigned(&buff, buff_end, uval,
172*7c3d14c8STreehugger Robot                                  (*cur == 'u') ? 10 : 16, width, pad_with_zero);
173*7c3d14c8STreehugger Robot         break;
174*7c3d14c8STreehugger Robot       }
175*7c3d14c8STreehugger Robot       case 'p': {
176*7c3d14c8STreehugger Robot         RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
177*7c3d14c8STreehugger Robot         result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
178*7c3d14c8STreehugger Robot         break;
179*7c3d14c8STreehugger Robot       }
180*7c3d14c8STreehugger Robot       case 's': {
181*7c3d14c8STreehugger Robot         RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
182*7c3d14c8STreehugger Robot         result += AppendString(&buff, buff_end, precision, va_arg(args, char*));
183*7c3d14c8STreehugger Robot         break;
184*7c3d14c8STreehugger Robot       }
185*7c3d14c8STreehugger Robot       case 'c': {
186*7c3d14c8STreehugger Robot         RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
187*7c3d14c8STreehugger Robot         result += AppendChar(&buff, buff_end, va_arg(args, int));
188*7c3d14c8STreehugger Robot         break;
189*7c3d14c8STreehugger Robot       }
190*7c3d14c8STreehugger Robot       case '%' : {
191*7c3d14c8STreehugger Robot         RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
192*7c3d14c8STreehugger Robot         result += AppendChar(&buff, buff_end, '%');
193*7c3d14c8STreehugger Robot         break;
194*7c3d14c8STreehugger Robot       }
195*7c3d14c8STreehugger Robot       default: {
196*7c3d14c8STreehugger Robot         RAW_CHECK_MSG(false, kPrintfFormatsHelp);
197*7c3d14c8STreehugger Robot       }
198*7c3d14c8STreehugger Robot     }
199*7c3d14c8STreehugger Robot   }
200*7c3d14c8STreehugger Robot   RAW_CHECK(buff <= buff_end);
201*7c3d14c8STreehugger Robot   AppendChar(&buff, buff_end + 1, '\0');
202*7c3d14c8STreehugger Robot   return result;
203*7c3d14c8STreehugger Robot }
204*7c3d14c8STreehugger Robot 
205*7c3d14c8STreehugger Robot static void (*PrintfAndReportCallback)(const char *);
SetPrintfAndReportCallback(void (* callback)(const char *))206*7c3d14c8STreehugger Robot void SetPrintfAndReportCallback(void (*callback)(const char *)) {
207*7c3d14c8STreehugger Robot   PrintfAndReportCallback = callback;
208*7c3d14c8STreehugger Robot }
209*7c3d14c8STreehugger Robot 
210*7c3d14c8STreehugger Robot // Can be overriden in frontend.
211*7c3d14c8STreehugger Robot #if SANITIZER_SUPPORTS_WEAK_HOOKS
212*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
OnPrint(const char * str)213*7c3d14c8STreehugger Robot void OnPrint(const char *str) {
214*7c3d14c8STreehugger Robot   (void)str;
215*7c3d14c8STreehugger Robot }
216*7c3d14c8STreehugger Robot #elif defined(SANITIZER_GO) && defined(TSAN_EXTERNAL_HOOKS)
217*7c3d14c8STreehugger Robot void OnPrint(const char *str);
218*7c3d14c8STreehugger Robot #else
OnPrint(const char * str)219*7c3d14c8STreehugger Robot void OnPrint(const char *str) {
220*7c3d14c8STreehugger Robot   (void)str;
221*7c3d14c8STreehugger Robot }
222*7c3d14c8STreehugger Robot #endif
223*7c3d14c8STreehugger Robot 
CallPrintfAndReportCallback(const char * str)224*7c3d14c8STreehugger Robot static void CallPrintfAndReportCallback(const char *str) {
225*7c3d14c8STreehugger Robot   OnPrint(str);
226*7c3d14c8STreehugger Robot   if (PrintfAndReportCallback)
227*7c3d14c8STreehugger Robot     PrintfAndReportCallback(str);
228*7c3d14c8STreehugger Robot }
229*7c3d14c8STreehugger Robot 
SharedPrintfCode(bool append_pid,const char * format,va_list args)230*7c3d14c8STreehugger Robot static void SharedPrintfCode(bool append_pid, const char *format,
231*7c3d14c8STreehugger Robot                              va_list args) {
232*7c3d14c8STreehugger Robot   va_list args2;
233*7c3d14c8STreehugger Robot   va_copy(args2, args);
234*7c3d14c8STreehugger Robot   const int kLen = 16 * 1024;
235*7c3d14c8STreehugger Robot   // |local_buffer| is small enough not to overflow the stack and/or violate
236*7c3d14c8STreehugger Robot   // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other
237*7c3d14c8STreehugger Robot   // hand, the bigger the buffer is, the more the chance the error report will
238*7c3d14c8STreehugger Robot   // fit into it.
239*7c3d14c8STreehugger Robot   char local_buffer[400];
240*7c3d14c8STreehugger Robot   int needed_length;
241*7c3d14c8STreehugger Robot   char *buffer = local_buffer;
242*7c3d14c8STreehugger Robot   int buffer_size = ARRAY_SIZE(local_buffer);
243*7c3d14c8STreehugger Robot   // First try to print a message using a local buffer, and then fall back to
244*7c3d14c8STreehugger Robot   // mmaped buffer.
245*7c3d14c8STreehugger Robot   for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
246*7c3d14c8STreehugger Robot     if (use_mmap) {
247*7c3d14c8STreehugger Robot       va_end(args);
248*7c3d14c8STreehugger Robot       va_copy(args, args2);
249*7c3d14c8STreehugger Robot       buffer = (char*)MmapOrDie(kLen, "Report");
250*7c3d14c8STreehugger Robot       buffer_size = kLen;
251*7c3d14c8STreehugger Robot     }
252*7c3d14c8STreehugger Robot     needed_length = 0;
253*7c3d14c8STreehugger Robot     // Check that data fits into the current buffer.
254*7c3d14c8STreehugger Robot #   define CHECK_NEEDED_LENGTH \
255*7c3d14c8STreehugger Robot       if (needed_length >= buffer_size) { \
256*7c3d14c8STreehugger Robot         if (!use_mmap) continue; \
257*7c3d14c8STreehugger Robot         RAW_CHECK_MSG(needed_length < kLen, \
258*7c3d14c8STreehugger Robot                       "Buffer in Report is too short!\n"); \
259*7c3d14c8STreehugger Robot       }
260*7c3d14c8STreehugger Robot     if (append_pid) {
261*7c3d14c8STreehugger Robot       int pid = internal_getpid();
262*7c3d14c8STreehugger Robot       const char *exe_name = GetProcessName();
263*7c3d14c8STreehugger Robot       if (common_flags()->log_exe_name && exe_name) {
264*7c3d14c8STreehugger Robot         needed_length += internal_snprintf(buffer, buffer_size,
265*7c3d14c8STreehugger Robot                                            "==%s", exe_name);
266*7c3d14c8STreehugger Robot         CHECK_NEEDED_LENGTH
267*7c3d14c8STreehugger Robot       }
268*7c3d14c8STreehugger Robot       needed_length += internal_snprintf(buffer + needed_length,
269*7c3d14c8STreehugger Robot                                          buffer_size - needed_length,
270*7c3d14c8STreehugger Robot                                          "==%d==", pid);
271*7c3d14c8STreehugger Robot       CHECK_NEEDED_LENGTH
272*7c3d14c8STreehugger Robot     }
273*7c3d14c8STreehugger Robot     needed_length += VSNPrintf(buffer + needed_length,
274*7c3d14c8STreehugger Robot                                buffer_size - needed_length, format, args);
275*7c3d14c8STreehugger Robot     CHECK_NEEDED_LENGTH
276*7c3d14c8STreehugger Robot     // If the message fit into the buffer, print it and exit.
277*7c3d14c8STreehugger Robot     break;
278*7c3d14c8STreehugger Robot #   undef CHECK_NEEDED_LENGTH
279*7c3d14c8STreehugger Robot   }
280*7c3d14c8STreehugger Robot   RawWrite(buffer);
281*7c3d14c8STreehugger Robot 
282*7c3d14c8STreehugger Robot   // Remove color sequences from the message.
283*7c3d14c8STreehugger Robot   RemoveANSIEscapeSequencesFromString(buffer);
284*7c3d14c8STreehugger Robot   CallPrintfAndReportCallback(buffer);
285*7c3d14c8STreehugger Robot   LogMessageOnPrintf(buffer);
286*7c3d14c8STreehugger Robot 
287*7c3d14c8STreehugger Robot   // If we had mapped any memory, clean up.
288*7c3d14c8STreehugger Robot   if (buffer != local_buffer)
289*7c3d14c8STreehugger Robot     UnmapOrDie((void *)buffer, buffer_size);
290*7c3d14c8STreehugger Robot   va_end(args2);
291*7c3d14c8STreehugger Robot }
292*7c3d14c8STreehugger Robot 
293*7c3d14c8STreehugger Robot FORMAT(1, 2)
Printf(const char * format,...)294*7c3d14c8STreehugger Robot void Printf(const char *format, ...) {
295*7c3d14c8STreehugger Robot   va_list args;
296*7c3d14c8STreehugger Robot   va_start(args, format);
297*7c3d14c8STreehugger Robot   SharedPrintfCode(false, format, args);
298*7c3d14c8STreehugger Robot   va_end(args);
299*7c3d14c8STreehugger Robot }
300*7c3d14c8STreehugger Robot 
301*7c3d14c8STreehugger Robot // Like Printf, but prints the current PID before the output string.
302*7c3d14c8STreehugger Robot FORMAT(1, 2)
Report(const char * format,...)303*7c3d14c8STreehugger Robot void Report(const char *format, ...) {
304*7c3d14c8STreehugger Robot   va_list args;
305*7c3d14c8STreehugger Robot   va_start(args, format);
306*7c3d14c8STreehugger Robot   SharedPrintfCode(true, format, args);
307*7c3d14c8STreehugger Robot   va_end(args);
308*7c3d14c8STreehugger Robot }
309*7c3d14c8STreehugger Robot 
310*7c3d14c8STreehugger Robot // Writes at most "length" symbols to "buffer" (including trailing '\0').
311*7c3d14c8STreehugger Robot // Returns the number of symbols that should have been written to buffer
312*7c3d14c8STreehugger Robot // (not including trailing '\0'). Thus, the string is truncated
313*7c3d14c8STreehugger Robot // iff return value is not less than "length".
314*7c3d14c8STreehugger Robot FORMAT(3, 4)
internal_snprintf(char * buffer,uptr length,const char * format,...)315*7c3d14c8STreehugger Robot int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
316*7c3d14c8STreehugger Robot   va_list args;
317*7c3d14c8STreehugger Robot   va_start(args, format);
318*7c3d14c8STreehugger Robot   int needed_length = VSNPrintf(buffer, length, format, args);
319*7c3d14c8STreehugger Robot   va_end(args);
320*7c3d14c8STreehugger Robot   return needed_length;
321*7c3d14c8STreehugger Robot }
322*7c3d14c8STreehugger Robot 
323*7c3d14c8STreehugger Robot FORMAT(2, 3)
append(const char * format,...)324*7c3d14c8STreehugger Robot void InternalScopedString::append(const char *format, ...) {
325*7c3d14c8STreehugger Robot   CHECK_LT(length_, size());
326*7c3d14c8STreehugger Robot   va_list args;
327*7c3d14c8STreehugger Robot   va_start(args, format);
328*7c3d14c8STreehugger Robot   VSNPrintf(data() + length_, size() - length_, format, args);
329*7c3d14c8STreehugger Robot   va_end(args);
330*7c3d14c8STreehugger Robot   length_ += internal_strlen(data() + length_);
331*7c3d14c8STreehugger Robot   CHECK_LT(length_, size());
332*7c3d14c8STreehugger Robot }
333*7c3d14c8STreehugger Robot 
334*7c3d14c8STreehugger Robot } // namespace __sanitizer
335