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