168d75effSDimitry Andric //===-- sanitizer_printf.cpp ----------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // Internal printf function, used inside run-time libraries. 1268d75effSDimitry Andric // We can't use libc printf because we intercept some of the functions used 1368d75effSDimitry Andric // inside it. 1468d75effSDimitry Andric //===----------------------------------------------------------------------===// 1568d75effSDimitry Andric 1668d75effSDimitry Andric #include "sanitizer_common.h" 1768d75effSDimitry Andric #include "sanitizer_flags.h" 1868d75effSDimitry Andric #include "sanitizer_libc.h" 1968d75effSDimitry Andric 2068d75effSDimitry Andric #include <stdio.h> 2168d75effSDimitry Andric #include <stdarg.h> 2268d75effSDimitry Andric 2368d75effSDimitry Andric #if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \ 2468d75effSDimitry Andric !defined(va_copy) 2568d75effSDimitry Andric # define va_copy(dst, src) ((dst) = (src)) 2668d75effSDimitry Andric #endif 2768d75effSDimitry Andric 2868d75effSDimitry Andric namespace __sanitizer { 2968d75effSDimitry Andric 3068d75effSDimitry Andric static int AppendChar(char **buff, const char *buff_end, char c) { 3168d75effSDimitry Andric if (*buff < buff_end) { 3268d75effSDimitry Andric **buff = c; 3368d75effSDimitry Andric (*buff)++; 3468d75effSDimitry Andric } 3568d75effSDimitry Andric return 1; 3668d75effSDimitry Andric } 3768d75effSDimitry Andric 3868d75effSDimitry Andric // Appends number in a given base to buffer. If its length is less than 3968d75effSDimitry Andric // |minimal_num_length|, it is padded with leading zeroes or spaces, depending 4068d75effSDimitry Andric // on the value of |pad_with_zero|. 4168d75effSDimitry Andric static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value, 4268d75effSDimitry Andric u8 base, u8 minimal_num_length, bool pad_with_zero, 4368d75effSDimitry Andric bool negative, bool uppercase) { 4468d75effSDimitry Andric uptr const kMaxLen = 30; 4568d75effSDimitry Andric RAW_CHECK(base == 10 || base == 16); 4668d75effSDimitry Andric RAW_CHECK(base == 10 || !negative); 4768d75effSDimitry Andric RAW_CHECK(absolute_value || !negative); 4868d75effSDimitry Andric RAW_CHECK(minimal_num_length < kMaxLen); 4968d75effSDimitry Andric int result = 0; 5068d75effSDimitry Andric if (negative && minimal_num_length) 5168d75effSDimitry Andric --minimal_num_length; 5268d75effSDimitry Andric if (negative && pad_with_zero) 5368d75effSDimitry Andric result += AppendChar(buff, buff_end, '-'); 5468d75effSDimitry Andric uptr num_buffer[kMaxLen]; 5568d75effSDimitry Andric int pos = 0; 5668d75effSDimitry Andric do { 57*0fca6ea1SDimitry Andric RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow",); 5868d75effSDimitry Andric num_buffer[pos++] = absolute_value % base; 5968d75effSDimitry Andric absolute_value /= base; 6068d75effSDimitry Andric } while (absolute_value > 0); 6168d75effSDimitry Andric if (pos < minimal_num_length) { 6268d75effSDimitry Andric // Make sure compiler doesn't insert call to memset here. 6368d75effSDimitry Andric internal_memset(&num_buffer[pos], 0, 6468d75effSDimitry Andric sizeof(num_buffer[0]) * (minimal_num_length - pos)); 6568d75effSDimitry Andric pos = minimal_num_length; 6668d75effSDimitry Andric } 6768d75effSDimitry Andric RAW_CHECK(pos > 0); 6868d75effSDimitry Andric pos--; 6968d75effSDimitry Andric for (; pos >= 0 && num_buffer[pos] == 0; pos--) { 7068d75effSDimitry Andric char c = (pad_with_zero || pos == 0) ? '0' : ' '; 7168d75effSDimitry Andric result += AppendChar(buff, buff_end, c); 7268d75effSDimitry Andric } 7368d75effSDimitry Andric if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-'); 7468d75effSDimitry Andric for (; pos >= 0; pos--) { 7568d75effSDimitry Andric char digit = static_cast<char>(num_buffer[pos]); 7668d75effSDimitry Andric digit = (digit < 10) ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10; 7768d75effSDimitry Andric result += AppendChar(buff, buff_end, digit); 7868d75effSDimitry Andric } 7968d75effSDimitry Andric return result; 8068d75effSDimitry Andric } 8168d75effSDimitry Andric 8268d75effSDimitry Andric static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base, 8368d75effSDimitry Andric u8 minimal_num_length, bool pad_with_zero, 8468d75effSDimitry Andric bool uppercase) { 8568d75effSDimitry Andric return AppendNumber(buff, buff_end, num, base, minimal_num_length, 8668d75effSDimitry Andric pad_with_zero, false /* negative */, uppercase); 8768d75effSDimitry Andric } 8868d75effSDimitry Andric 8968d75effSDimitry Andric static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num, 9068d75effSDimitry Andric u8 minimal_num_length, bool pad_with_zero) { 9168d75effSDimitry Andric bool negative = (num < 0); 9268d75effSDimitry Andric return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10, 9368d75effSDimitry Andric minimal_num_length, pad_with_zero, negative, 9468d75effSDimitry Andric false /* uppercase */); 9568d75effSDimitry Andric } 9668d75effSDimitry Andric 9768d75effSDimitry Andric 9868d75effSDimitry Andric // Use the fact that explicitly requesting 0 width (%0s) results in UB and 9968d75effSDimitry Andric // interpret width == 0 as "no width requested": 10068d75effSDimitry Andric // width == 0 - no width requested 10168d75effSDimitry Andric // width < 0 - left-justify s within and pad it to -width chars, if necessary 10268d75effSDimitry Andric // width > 0 - right-justify s, not implemented yet 10368d75effSDimitry Andric static int AppendString(char **buff, const char *buff_end, int width, 10468d75effSDimitry Andric int max_chars, const char *s) { 10568d75effSDimitry Andric if (!s) 10668d75effSDimitry Andric s = "<null>"; 10768d75effSDimitry Andric int result = 0; 10868d75effSDimitry Andric for (; *s; s++) { 10968d75effSDimitry Andric if (max_chars >= 0 && result >= max_chars) 11068d75effSDimitry Andric break; 11168d75effSDimitry Andric result += AppendChar(buff, buff_end, *s); 11268d75effSDimitry Andric } 11368d75effSDimitry Andric // Only the left justified strings are supported. 11468d75effSDimitry Andric while (width < -result) 11568d75effSDimitry Andric result += AppendChar(buff, buff_end, ' '); 11668d75effSDimitry Andric return result; 11768d75effSDimitry Andric } 11868d75effSDimitry Andric 11968d75effSDimitry Andric static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) { 12068d75effSDimitry Andric int result = 0; 12168d75effSDimitry Andric result += AppendString(buff, buff_end, 0, -1, "0x"); 12268d75effSDimitry Andric result += AppendUnsigned(buff, buff_end, ptr_value, 16, 12368d75effSDimitry Andric SANITIZER_POINTER_FORMAT_LENGTH, 12468d75effSDimitry Andric true /* pad_with_zero */, false /* uppercase */); 12568d75effSDimitry Andric return result; 12668d75effSDimitry Andric } 12768d75effSDimitry Andric 12868d75effSDimitry Andric int VSNPrintf(char *buff, int buff_length, 12968d75effSDimitry Andric const char *format, va_list args) { 13068d75effSDimitry Andric static const char *kPrintfFormatsHelp = 131349cc55cSDimitry Andric "Supported Printf formats: %([0-9]*)?(z|l|ll)?{d,u,x,X}; %p; " 132349cc55cSDimitry Andric "%[-]([0-9]*)?(\\.\\*)?s; %c\nProvided format: "; 13368d75effSDimitry Andric RAW_CHECK(format); 13468d75effSDimitry Andric RAW_CHECK(buff_length > 0); 13568d75effSDimitry Andric const char *buff_end = &buff[buff_length - 1]; 13668d75effSDimitry Andric const char *cur = format; 13768d75effSDimitry Andric int result = 0; 13868d75effSDimitry Andric for (; *cur; cur++) { 13968d75effSDimitry Andric if (*cur != '%') { 14068d75effSDimitry Andric result += AppendChar(&buff, buff_end, *cur); 14168d75effSDimitry Andric continue; 14268d75effSDimitry Andric } 14368d75effSDimitry Andric cur++; 14468d75effSDimitry Andric bool left_justified = *cur == '-'; 14568d75effSDimitry Andric if (left_justified) 14668d75effSDimitry Andric cur++; 14768d75effSDimitry Andric bool have_width = (*cur >= '0' && *cur <= '9'); 14868d75effSDimitry Andric bool pad_with_zero = (*cur == '0'); 14968d75effSDimitry Andric int width = 0; 15068d75effSDimitry Andric if (have_width) { 15168d75effSDimitry Andric while (*cur >= '0' && *cur <= '9') { 15268d75effSDimitry Andric width = width * 10 + *cur++ - '0'; 15368d75effSDimitry Andric } 15468d75effSDimitry Andric } 15568d75effSDimitry Andric bool have_precision = (cur[0] == '.' && cur[1] == '*'); 15668d75effSDimitry Andric int precision = -1; 15768d75effSDimitry Andric if (have_precision) { 15868d75effSDimitry Andric cur += 2; 15968d75effSDimitry Andric precision = va_arg(args, int); 16068d75effSDimitry Andric } 16168d75effSDimitry Andric bool have_z = (*cur == 'z'); 16268d75effSDimitry Andric cur += have_z; 163349cc55cSDimitry Andric bool have_l = cur[0] == 'l' && cur[1] != 'l'; 164349cc55cSDimitry Andric cur += have_l; 165349cc55cSDimitry Andric bool have_ll = cur[0] == 'l' && cur[1] == 'l'; 16668d75effSDimitry Andric cur += have_ll * 2; 167349cc55cSDimitry Andric const bool have_length = have_z || have_l || have_ll; 16868d75effSDimitry Andric const bool have_flags = have_width || have_length; 16968d75effSDimitry Andric // At the moment only %s supports precision and left-justification. 17068d75effSDimitry Andric CHECK(!((precision >= 0 || left_justified) && *cur != 's')); 17168d75effSDimitry Andric switch (*cur) { 17268d75effSDimitry Andric case 'd': { 173fe6060f1SDimitry Andric s64 dval = have_ll ? va_arg(args, s64) 17468d75effSDimitry Andric : have_z ? va_arg(args, sptr) 175349cc55cSDimitry Andric : have_l ? va_arg(args, long) 17668d75effSDimitry Andric : va_arg(args, int); 17768d75effSDimitry Andric result += AppendSignedDecimal(&buff, buff_end, dval, width, 17868d75effSDimitry Andric pad_with_zero); 17968d75effSDimitry Andric break; 18068d75effSDimitry Andric } 18168d75effSDimitry Andric case 'u': 18268d75effSDimitry Andric case 'x': 18368d75effSDimitry Andric case 'X': { 184fe6060f1SDimitry Andric u64 uval = have_ll ? va_arg(args, u64) 18568d75effSDimitry Andric : have_z ? va_arg(args, uptr) 186349cc55cSDimitry Andric : have_l ? va_arg(args, unsigned long) 18768d75effSDimitry Andric : va_arg(args, unsigned); 18868d75effSDimitry Andric bool uppercase = (*cur == 'X'); 18968d75effSDimitry Andric result += AppendUnsigned(&buff, buff_end, uval, (*cur == 'u') ? 10 : 16, 19068d75effSDimitry Andric width, pad_with_zero, uppercase); 19168d75effSDimitry Andric break; 19268d75effSDimitry Andric } 19368d75effSDimitry Andric case 'p': { 194349cc55cSDimitry Andric RAW_CHECK_VA(!have_flags, kPrintfFormatsHelp, format); 19568d75effSDimitry Andric result += AppendPointer(&buff, buff_end, va_arg(args, uptr)); 19668d75effSDimitry Andric break; 19768d75effSDimitry Andric } 19868d75effSDimitry Andric case 's': { 199349cc55cSDimitry Andric RAW_CHECK_VA(!have_length, kPrintfFormatsHelp, format); 20068d75effSDimitry Andric // Only left-justified width is supported. 20168d75effSDimitry Andric CHECK(!have_width || left_justified); 20268d75effSDimitry Andric result += AppendString(&buff, buff_end, left_justified ? -width : width, 20368d75effSDimitry Andric precision, va_arg(args, char*)); 20468d75effSDimitry Andric break; 20568d75effSDimitry Andric } 20668d75effSDimitry Andric case 'c': { 207349cc55cSDimitry Andric RAW_CHECK_VA(!have_flags, kPrintfFormatsHelp, format); 20868d75effSDimitry Andric result += AppendChar(&buff, buff_end, va_arg(args, int)); 20968d75effSDimitry Andric break; 21068d75effSDimitry Andric } 21168d75effSDimitry Andric case '%' : { 212349cc55cSDimitry Andric RAW_CHECK_VA(!have_flags, kPrintfFormatsHelp, format); 21368d75effSDimitry Andric result += AppendChar(&buff, buff_end, '%'); 21468d75effSDimitry Andric break; 21568d75effSDimitry Andric } 21668d75effSDimitry Andric default: { 217349cc55cSDimitry Andric RAW_CHECK_VA(false, kPrintfFormatsHelp, format); 21868d75effSDimitry Andric } 21968d75effSDimitry Andric } 22068d75effSDimitry Andric } 22168d75effSDimitry Andric RAW_CHECK(buff <= buff_end); 22268d75effSDimitry Andric AppendChar(&buff, buff_end + 1, '\0'); 22368d75effSDimitry Andric return result; 22468d75effSDimitry Andric } 22568d75effSDimitry Andric 22668d75effSDimitry Andric static void (*PrintfAndReportCallback)(const char *); 22768d75effSDimitry Andric void SetPrintfAndReportCallback(void (*callback)(const char *)) { 22868d75effSDimitry Andric PrintfAndReportCallback = callback; 22968d75effSDimitry Andric } 23068d75effSDimitry Andric 23168d75effSDimitry Andric // Can be overriden in frontend. 23268d75effSDimitry Andric #if SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS) 23368d75effSDimitry Andric // Implementation must be defined in frontend. 23468d75effSDimitry Andric extern "C" void __sanitizer_on_print(const char *str); 23568d75effSDimitry Andric #else 23668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_on_print, const char *str) { 23768d75effSDimitry Andric (void)str; 23868d75effSDimitry Andric } 23968d75effSDimitry Andric #endif 24068d75effSDimitry Andric 24168d75effSDimitry Andric static void CallPrintfAndReportCallback(const char *str) { 24268d75effSDimitry Andric __sanitizer_on_print(str); 24368d75effSDimitry Andric if (PrintfAndReportCallback) 24468d75effSDimitry Andric PrintfAndReportCallback(str); 24568d75effSDimitry Andric } 24668d75effSDimitry Andric 24768d75effSDimitry Andric static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, 24868d75effSDimitry Andric char *local_buffer, 24968d75effSDimitry Andric int buffer_size, 25068d75effSDimitry Andric const char *format, 25168d75effSDimitry Andric va_list args) { 25268d75effSDimitry Andric va_list args2; 25368d75effSDimitry Andric va_copy(args2, args); 254fe6060f1SDimitry Andric InternalMmapVector<char> v; 255fe6060f1SDimitry Andric int needed_length = 0; 25668d75effSDimitry Andric char *buffer = local_buffer; 25768d75effSDimitry Andric // First try to print a message using a local buffer, and then fall back to 25868d75effSDimitry Andric // mmaped buffer. 259fe6060f1SDimitry Andric for (int use_mmap = 0;; use_mmap++) { 26068d75effSDimitry Andric if (use_mmap) { 26168d75effSDimitry Andric va_end(args); 26268d75effSDimitry Andric va_copy(args, args2); 263fe6060f1SDimitry Andric v.resize(needed_length + 1); 264fe6060f1SDimitry Andric buffer_size = v.capacity(); 265fe6060f1SDimitry Andric v.resize(buffer_size); 266fe6060f1SDimitry Andric buffer = &v[0]; 26768d75effSDimitry Andric } 26868d75effSDimitry Andric needed_length = 0; 26968d75effSDimitry Andric // Fuchsia's logging infrastructure always keeps track of the logging 27068d75effSDimitry Andric // process, thread, and timestamp, so never prepend such information. 27168d75effSDimitry Andric if (!SANITIZER_FUCHSIA && append_pid) { 27268d75effSDimitry Andric int pid = internal_getpid(); 27368d75effSDimitry Andric const char *exe_name = GetProcessName(); 27468d75effSDimitry Andric if (common_flags()->log_exe_name && exe_name) { 27568d75effSDimitry Andric needed_length += internal_snprintf(buffer, buffer_size, 27668d75effSDimitry Andric "==%s", exe_name); 277fe6060f1SDimitry Andric if (needed_length >= buffer_size) 278fe6060f1SDimitry Andric continue; 27968d75effSDimitry Andric } 28068d75effSDimitry Andric needed_length += internal_snprintf( 28168d75effSDimitry Andric buffer + needed_length, buffer_size - needed_length, "==%d==", pid); 282fe6060f1SDimitry Andric if (needed_length >= buffer_size) 283fe6060f1SDimitry Andric continue; 28468d75effSDimitry Andric } 28568d75effSDimitry Andric needed_length += VSNPrintf(buffer + needed_length, 28668d75effSDimitry Andric buffer_size - needed_length, format, args); 287fe6060f1SDimitry Andric if (needed_length >= buffer_size) 288fe6060f1SDimitry Andric continue; 28968d75effSDimitry Andric // If the message fit into the buffer, print it and exit. 29068d75effSDimitry Andric break; 29168d75effSDimitry Andric } 29268d75effSDimitry Andric RawWrite(buffer); 29368d75effSDimitry Andric 29468d75effSDimitry Andric // Remove color sequences from the message. 29568d75effSDimitry Andric RemoveANSIEscapeSequencesFromString(buffer); 29668d75effSDimitry Andric CallPrintfAndReportCallback(buffer); 29768d75effSDimitry Andric LogMessageOnPrintf(buffer); 29868d75effSDimitry Andric 29968d75effSDimitry Andric va_end(args2); 30068d75effSDimitry Andric } 30168d75effSDimitry Andric 30268d75effSDimitry Andric static void NOINLINE SharedPrintfCode(bool append_pid, const char *format, 30368d75effSDimitry Andric va_list args) { 30468d75effSDimitry Andric // |local_buffer| is small enough not to overflow the stack and/or violate 30568d75effSDimitry Andric // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other 30668d75effSDimitry Andric // hand, the bigger the buffer is, the more the chance the error report will 30768d75effSDimitry Andric // fit into it. 30868d75effSDimitry Andric char local_buffer[400]; 30968d75effSDimitry Andric SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer), 31068d75effSDimitry Andric format, args); 31168d75effSDimitry Andric } 31268d75effSDimitry Andric 31368d75effSDimitry Andric void Printf(const char *format, ...) { 31468d75effSDimitry Andric va_list args; 31568d75effSDimitry Andric va_start(args, format); 31668d75effSDimitry Andric SharedPrintfCode(false, format, args); 31768d75effSDimitry Andric va_end(args); 31868d75effSDimitry Andric } 31968d75effSDimitry Andric 32068d75effSDimitry Andric // Like Printf, but prints the current PID before the output string. 32168d75effSDimitry Andric void Report(const char *format, ...) { 32268d75effSDimitry Andric va_list args; 32368d75effSDimitry Andric va_start(args, format); 32468d75effSDimitry Andric SharedPrintfCode(true, format, args); 32568d75effSDimitry Andric va_end(args); 32668d75effSDimitry Andric } 32768d75effSDimitry Andric 32868d75effSDimitry Andric // Writes at most "length" symbols to "buffer" (including trailing '\0'). 32968d75effSDimitry Andric // Returns the number of symbols that should have been written to buffer 33068d75effSDimitry Andric // (not including trailing '\0'). Thus, the string is truncated 33168d75effSDimitry Andric // iff return value is not less than "length". 33268d75effSDimitry Andric int internal_snprintf(char *buffer, uptr length, const char *format, ...) { 33368d75effSDimitry Andric va_list args; 33468d75effSDimitry Andric va_start(args, format); 33568d75effSDimitry Andric int needed_length = VSNPrintf(buffer, length, format, args); 33668d75effSDimitry Andric va_end(args); 33768d75effSDimitry Andric return needed_length; 33868d75effSDimitry Andric } 33968d75effSDimitry Andric 3405f757f3fSDimitry Andric void InternalScopedString::Append(const char *str) { 3415f757f3fSDimitry Andric uptr prev_len = length(); 3425f757f3fSDimitry Andric uptr str_len = internal_strlen(str); 3435f757f3fSDimitry Andric buffer_.resize(prev_len + str_len + 1); 3445f757f3fSDimitry Andric internal_memcpy(buffer_.data() + prev_len, str, str_len + 1); 3455f757f3fSDimitry Andric } 3465f757f3fSDimitry Andric 3475f757f3fSDimitry Andric void InternalScopedString::AppendF(const char *format, ...) { 348fe6060f1SDimitry Andric uptr prev_len = length(); 349fe6060f1SDimitry Andric 350fe6060f1SDimitry Andric while (true) { 351fe6060f1SDimitry Andric buffer_.resize(buffer_.capacity()); 352fe6060f1SDimitry Andric 35368d75effSDimitry Andric va_list args; 35468d75effSDimitry Andric va_start(args, format); 355fe6060f1SDimitry Andric uptr sz = VSNPrintf(buffer_.data() + prev_len, buffer_.size() - prev_len, 356fe6060f1SDimitry Andric format, args); 35768d75effSDimitry Andric va_end(args); 358fe6060f1SDimitry Andric if (sz < buffer_.size() - prev_len) { 359fe6060f1SDimitry Andric buffer_.resize(prev_len + sz + 1); 360fe6060f1SDimitry Andric break; 361fe6060f1SDimitry Andric } 362fe6060f1SDimitry Andric 363fe6060f1SDimitry Andric buffer_.reserve(buffer_.capacity() * 2); 364fe6060f1SDimitry Andric } 365fe6060f1SDimitry Andric CHECK_EQ(buffer_[length()], '\0'); 36668d75effSDimitry Andric } 36768d75effSDimitry Andric 36868d75effSDimitry Andric } // namespace __sanitizer 369