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