1e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov//===-- sanitizer_printf.cc -----------------------------------------------===// 2e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// 3e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// The LLVM Compiler Infrastructure 4e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// 5e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// This file is distributed under the University of Illinois Open Source 6e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// License. See LICENSE.TXT for details. 7e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// 8e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov//===----------------------------------------------------------------------===// 9e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// 10e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// This file is shared between AddressSanitizer and ThreadSanitizer. 11e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// 12e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// Internal printf function, used inside run-time libraries. 13e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// We can't use libc printf because we intercept some of the functions used 14e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// inside it. 15e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov//===----------------------------------------------------------------------===// 16e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 17e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov#include "sanitizer_common.h" 182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_flags.h" 19e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov#include "sanitizer_libc.h" 20e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 21e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov#include <stdio.h> 22e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov#include <stdarg.h> 23e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 246d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \ 256d1862363c88c183b0ed7740fca876342cf0474bStephen Hines !defined(va_copy) 266a72c9d8509bb8e751cb92e71407c039a767caa1Dmitry Vyukov# define va_copy(dst, src) ((dst) = (src)) 276a72c9d8509bb8e751cb92e71407c039a767caa1Dmitry Vyukov#endif 286a72c9d8509bb8e751cb92e71407c039a767caa1Dmitry Vyukov 29e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonovnamespace __sanitizer { 30e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 317ed46ff7af911da0dd2067734d1408c6986c6657Alexey SamsonovStaticSpinMutex CommonSanitizerReportMutex; 327ed46ff7af911da0dd2067734d1408c6986c6657Alexey Samsonov 33e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonovstatic int AppendChar(char **buff, const char *buff_end, char c) { 34e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov if (*buff < buff_end) { 35e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov **buff = c; 36e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov (*buff)++; 37e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 38e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov return 1; 39e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov} 40e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 41e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov// Appends number in a given base to buffer. If its length is less than 42134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev// |minimal_num_length|, it is padded with leading zeroes or spaces, depending 43134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev// on the value of |pad_with_zero|. 44134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveevstatic int AppendNumber(char **buff, const char *buff_end, u64 absolute_value, 45134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev u8 base, u8 minimal_num_length, bool pad_with_zero, 46134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev bool negative) { 47e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov uptr const kMaxLen = 30; 48e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov RAW_CHECK(base == 10 || base == 16); 49134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev RAW_CHECK(base == 10 || !negative); 50134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev RAW_CHECK(absolute_value || !negative); 51e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov RAW_CHECK(minimal_num_length < kMaxLen); 52134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev int result = 0; 53134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev if (negative && minimal_num_length) 54134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev --minimal_num_length; 55134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev if (negative && pad_with_zero) 56134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev result += AppendChar(buff, buff_end, '-'); 57e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov uptr num_buffer[kMaxLen]; 58134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev int pos = 0; 59e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov do { 60134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow"); 61134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev num_buffer[pos++] = absolute_value % base; 62134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev absolute_value /= base; 63134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev } while (absolute_value > 0); 64e52e2806f5eef9aa6a46fc81119f592ea22b0cbfAlexey Samsonov if (pos < minimal_num_length) { 65e52e2806f5eef9aa6a46fc81119f592ea22b0cbfAlexey Samsonov // Make sure compiler doesn't insert call to memset here. 66e52e2806f5eef9aa6a46fc81119f592ea22b0cbfAlexey Samsonov internal_memset(&num_buffer[pos], 0, 67e52e2806f5eef9aa6a46fc81119f592ea22b0cbfAlexey Samsonov sizeof(num_buffer[0]) * (minimal_num_length - pos)); 68e52e2806f5eef9aa6a46fc81119f592ea22b0cbfAlexey Samsonov pos = minimal_num_length; 69e52e2806f5eef9aa6a46fc81119f592ea22b0cbfAlexey Samsonov } 70134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev RAW_CHECK(pos > 0); 71134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev pos--; 72134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev for (; pos >= 0 && num_buffer[pos] == 0; pos--) { 73134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev char c = (pad_with_zero || pos == 0) ? '0' : ' '; 74134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev result += AppendChar(buff, buff_end, c); 75134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev } 76134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-'); 77134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev for (; pos >= 0; pos--) { 785e97ba38b00eb843a55189bb913b445cbe620894Timur Iskhodzhanov char digit = static_cast<char>(num_buffer[pos]); 79e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit 80e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov : 'a' + digit - 10); 81e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 82e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov return result; 83e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov} 84e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 85134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveevstatic int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base, 86134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev u8 minimal_num_length, bool pad_with_zero) { 87134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev return AppendNumber(buff, buff_end, num, base, minimal_num_length, 88134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev pad_with_zero, false /* negative */); 89134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev} 90134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev 91f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smithstatic int AppendSignedDecimal(char **buff, const char *buff_end, s64 num, 92134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev u8 minimal_num_length, bool pad_with_zero) { 93134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev bool negative = (num < 0); 94134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10, 95134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev minimal_num_length, pad_with_zero, negative); 96e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov} 97e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic int AppendString(char **buff, const char *buff_end, int precision, 992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines const char *s) { 100799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar if (!s) 101e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov s = "<null>"; 102e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov int result = 0; 103e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov for (; *s; s++) { 1042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (precision >= 0 && result >= precision) 1052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines break; 106e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov result += AppendChar(buff, buff_end, *s); 107e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 108e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov return result; 109e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov} 110e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 111e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonovstatic int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) { 112e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov int result = 0; 1132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines result += AppendString(buff, buff_end, -1, "0x"); 114e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov result += AppendUnsigned(buff, buff_end, ptr_value, 16, 1156d1862363c88c183b0ed7740fca876342cf0474bStephen Hines SANITIZER_POINTER_FORMAT_LENGTH, true); 116e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov return result; 117e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov} 118e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 119e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonovint VSNPrintf(char *buff, int buff_length, 120e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov const char *format, va_list args) { 121f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith static const char *kPrintfFormatsHelp = 1222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %(\\.\\*)?s; %c\n"; 123e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov RAW_CHECK(format); 124e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov RAW_CHECK(buff_length > 0); 125e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov const char *buff_end = &buff[buff_length - 1]; 126e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov const char *cur = format; 127e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov int result = 0; 128e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov for (; *cur; cur++) { 129e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov if (*cur != '%') { 130e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov result += AppendChar(&buff, buff_end, *cur); 131e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov continue; 132e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 133e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov cur++; 134134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev bool have_width = (*cur >= '0' && *cur <= '9'); 135134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev bool pad_with_zero = (*cur == '0'); 136f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith int width = 0; 137f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith if (have_width) { 138f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith while (*cur >= '0' && *cur <= '9') { 139f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith width = width * 10 + *cur++ - '0'; 140f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith } 141f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith } 1422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines bool have_precision = (cur[0] == '.' && cur[1] == '*'); 1432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines int precision = -1; 1442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (have_precision) { 1452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines cur += 2; 1462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines precision = va_arg(args, int); 1472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 148e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov bool have_z = (*cur == 'z'); 149e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov cur += have_z; 150f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l'); 151f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith cur += have_ll * 2; 152e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov s64 dval; 153e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov u64 uval; 154f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith bool have_flags = have_width | have_z | have_ll; 1552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // Only %s supports precision for now 1562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK(!(precision >= 0 && *cur != 's')); 157e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov switch (*cur) { 158e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov case 'd': { 159f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith dval = have_ll ? va_arg(args, s64) 160f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith : have_z ? va_arg(args, sptr) 161f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith : va_arg(args, int); 162134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev result += AppendSignedDecimal(&buff, buff_end, dval, width, 163134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev pad_with_zero); 164e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov break; 165e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 166e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov case 'u': 167e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov case 'x': { 168f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith uval = have_ll ? va_arg(args, u64) 169f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith : have_z ? va_arg(args, uptr) 170f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith : va_arg(args, unsigned); 171e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov result += AppendUnsigned(&buff, buff_end, uval, 172134da448d092f82bfd5ddcdfa203c5c652c51474Sergey Matveev (*cur == 'u') ? 10 : 16, width, pad_with_zero); 173e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov break; 174e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 175e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov case 'p': { 176f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); 177e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov result += AppendPointer(&buff, buff_end, va_arg(args, uptr)); 178e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov break; 179e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 180e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov case 's': { 181f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); 1822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines result += AppendString(&buff, buff_end, precision, va_arg(args, char*)); 183e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov break; 184e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 18581dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany case 'c': { 186f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); 18701167e89d77530d5d8507e1f0f1f2979a1497573Kostya Serebryany result += AppendChar(&buff, buff_end, va_arg(args, int)); 18881dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany break; 18981dfbb76f858fbc4084771fce4967ede04ed5f44Kostya Serebryany } 190e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov case '%' : { 191f4932204d7cf89cc2402b1e30fb728cf84ff7b7fRichard Smith RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); 192e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov result += AppendChar(&buff, buff_end, '%'); 193e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov break; 194e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 195e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov default: { 196e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov RAW_CHECK_MSG(false, kPrintfFormatsHelp); 197e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 198e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 199e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov } 200e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov RAW_CHECK(buff <= buff_end); 201e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov AppendChar(&buff, buff_end + 1, '\0'); 202e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov return result; 203e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov} 204e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 205283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryanystatic void (*PrintfAndReportCallback)(const char *); 206283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryanyvoid SetPrintfAndReportCallback(void (*callback)(const char *)) { 207283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany PrintfAndReportCallback = callback; 208283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany} 209283c296b64bc55deec9698260b3427a9b050a925Kostya Serebryany 21013f62b2cdaa09376e917a1efd0b1dd3d23bbff8dDmitry Vyukov// Can be overriden in frontend. 2116f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukov#if SANITIZER_SUPPORTS_WEAK_HOOKS 2123c80c6c574850106481f82b9e23d1c728458d4a9Timur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 2136f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukovvoid OnPrint(const char *str) { 2146f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukov (void)str; 2156f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukov} 2166f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukov#elif defined(SANITIZER_GO) && defined(TSAN_EXTERNAL_HOOKS) 21778b580f3d40132816f813c3dbf073d824137436aAlexey Samsonovvoid OnPrint(const char *str); 2186f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukov#else 2196f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukovvoid OnPrint(const char *str) { 2206f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukov (void)str; 2216f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukov} 22213f62b2cdaa09376e917a1efd0b1dd3d23bbff8dDmitry Vyukov#endif 22313f62b2cdaa09376e917a1efd0b1dd3d23bbff8dDmitry Vyukov 22413f62b2cdaa09376e917a1efd0b1dd3d23bbff8dDmitry Vyukovstatic void CallPrintfAndReportCallback(const char *str) { 2256f2741c6325e0112f52b537444e1aaac8e746f85Dmitry Vyukov OnPrint(str); 22613f62b2cdaa09376e917a1efd0b1dd3d23bbff8dDmitry Vyukov if (PrintfAndReportCallback) 22713f62b2cdaa09376e917a1efd0b1dd3d23bbff8dDmitry Vyukov PrintfAndReportCallback(str); 22813f62b2cdaa09376e917a1efd0b1dd3d23bbff8dDmitry Vyukov} 22913f62b2cdaa09376e917a1efd0b1dd3d23bbff8dDmitry Vyukov 23099f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonovstatic void SharedPrintfCode(bool append_pid, const char *format, 23199f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_list args) { 2324f5e4bbdf775354433430fea4598ff3991442915Dmitry Vyukov va_list args2; 2334f5e4bbdf775354433430fea4598ff3991442915Dmitry Vyukov va_copy(args2, args); 234b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov const int kLen = 16 * 1024; 235c1b73e84db2f9f62633ee52b13cd1f83ef2fbe99Alexander Potapenko // |local_buffer| is small enough not to overflow the stack and/or violate 236c1b73e84db2f9f62633ee52b13cd1f83ef2fbe99Alexander Potapenko // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other 237c1b73e84db2f9f62633ee52b13cd1f83ef2fbe99Alexander Potapenko // hand, the bigger the buffer is, the more the chance the error report will 238c1b73e84db2f9f62633ee52b13cd1f83ef2fbe99Alexander Potapenko // fit into it. 239c1b73e84db2f9f62633ee52b13cd1f83ef2fbe99Alexander Potapenko char local_buffer[400]; 240e282b1ac6f9d370f9b30dbbd2da43f6346947f7fAlexander Potapenko int needed_length; 241e282b1ac6f9d370f9b30dbbd2da43f6346947f7fAlexander Potapenko char *buffer = local_buffer; 24299f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov int buffer_size = ARRAY_SIZE(local_buffer); 24399f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov // First try to print a message using a local buffer, and then fall back to 24499f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov // mmaped buffer. 245e282b1ac6f9d370f9b30dbbd2da43f6346947f7fAlexander Potapenko for (int use_mmap = 0; use_mmap < 2; use_mmap++) { 24699f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov if (use_mmap) { 2474f5e4bbdf775354433430fea4598ff3991442915Dmitry Vyukov va_end(args); 2484f5e4bbdf775354433430fea4598ff3991442915Dmitry Vyukov va_copy(args, args2); 24999f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov buffer = (char*)MmapOrDie(kLen, "Report"); 25099f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov buffer_size = kLen; 25199f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov } 25299f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov needed_length = 0; 253cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar // Check that data fits into the current buffer. 254cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar# define CHECK_NEEDED_LENGTH \ 255cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar if (needed_length >= buffer_size) { \ 256cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar if (!use_mmap) continue; \ 257cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar RAW_CHECK_MSG(needed_length < kLen, \ 258cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar "Buffer in Report is too short!\n"); \ 259cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar } 26099f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov if (append_pid) { 2610b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne int pid = internal_getpid(); 262799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar const char *exe_name = GetProcessName(); 263cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar if (common_flags()->log_exe_name && exe_name) { 264cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar needed_length += internal_snprintf(buffer, buffer_size, 265cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar "==%s", exe_name); 266cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar CHECK_NEEDED_LENGTH 267e282b1ac6f9d370f9b30dbbd2da43f6346947f7fAlexander Potapenko } 268cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar needed_length += internal_snprintf(buffer + needed_length, 269cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar buffer_size - needed_length, 270cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar "==%d==", pid); 271cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar CHECK_NEEDED_LENGTH 272e282b1ac6f9d370f9b30dbbd2da43f6346947f7fAlexander Potapenko } 273e282b1ac6f9d370f9b30dbbd2da43f6346947f7fAlexander Potapenko needed_length += VSNPrintf(buffer + needed_length, 27499f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov buffer_size - needed_length, format, args); 275cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar CHECK_NEEDED_LENGTH 27699f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov // If the message fit into the buffer, print it and exit. 27799f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov break; 278cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar# undef CHECK_NEEDED_LENGTH 279e282b1ac6f9d370f9b30dbbd2da43f6346947f7fAlexander Potapenko } 28099f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov RawWrite(buffer); 281c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar 282c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar // Remove color sequences from the message. 283c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar RemoveANSIEscapeSequencesFromString(buffer); 28499f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov CallPrintfAndReportCallback(buffer); 285c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar LogMessageOnPrintf(buffer); 286c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar 287e282b1ac6f9d370f9b30dbbd2da43f6346947f7fAlexander Potapenko // If we had mapped any memory, clean up. 28899f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov if (buffer != local_buffer) 28999f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov UnmapOrDie((void *)buffer, buffer_size); 2904f5e4bbdf775354433430fea4598ff3991442915Dmitry Vyukov va_end(args2); 29199f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov} 29299f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov 2932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesFORMAT(1, 2) 29499f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonovvoid Printf(const char *format, ...) { 29599f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_list args; 29699f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_start(args, format); 29799f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov SharedPrintfCode(false, format, args); 29899f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_end(args); 29999f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov} 30099f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov 30199f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov// Like Printf, but prints the current PID before the output string. 3022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesFORMAT(1, 2) 30399f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonovvoid Report(const char *format, ...) { 30499f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_list args; 30599f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_start(args, format); 30699f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov SharedPrintfCode(true, format, args); 30799f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_end(args); 30899f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov} 30999f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov 31099f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov// Writes at most "length" symbols to "buffer" (including trailing '\0'). 31199f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov// Returns the number of symbols that should have been written to buffer 31299f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov// (not including trailing '\0'). Thus, the string is truncated 31399f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov// iff return value is not less than "length". 3142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesFORMAT(3, 4) 31599f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonovint internal_snprintf(char *buffer, uptr length, const char *format, ...) { 31699f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_list args; 31799f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_start(args, format); 31899f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov int needed_length = VSNPrintf(buffer, length, format, args); 31999f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov va_end(args); 32099f1e2011a855edd3b1036660ec5e7b70aa06520Alexey Samsonov return needed_length; 321e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov} 322e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov 3232d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesFORMAT(2, 3) 324bb4697fe8cbe79c517e6f85713f2de6bd804209dAlexey Samsonovvoid InternalScopedString::append(const char *format, ...) { 325bb4697fe8cbe79c517e6f85713f2de6bd804209dAlexey Samsonov CHECK_LT(length_, size()); 326bb4697fe8cbe79c517e6f85713f2de6bd804209dAlexey Samsonov va_list args; 327bb4697fe8cbe79c517e6f85713f2de6bd804209dAlexey Samsonov va_start(args, format); 328bb4697fe8cbe79c517e6f85713f2de6bd804209dAlexey Samsonov VSNPrintf(data() + length_, size() - length_, format, args); 329bb4697fe8cbe79c517e6f85713f2de6bd804209dAlexey Samsonov va_end(args); 330bb4697fe8cbe79c517e6f85713f2de6bd804209dAlexey Samsonov length_ += internal_strlen(data() + length_); 3312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK_LT(length_, size()); 332bb4697fe8cbe79c517e6f85713f2de6bd804209dAlexey Samsonov} 333bb4697fe8cbe79c517e6f85713f2de6bd804209dAlexey Samsonov 334799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar} // namespace __sanitizer 335