Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 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 | |
| 18 | #include "sanitizer_common.h" |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 19 | #include "sanitizer_flags.h" |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 20 | #include "sanitizer_libc.h" |
| 21 | |
| 22 | #include <stdio.h> |
| 23 | #include <stdarg.h> |
| 24 | |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 25 | #if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \ |
| 26 | !defined(va_copy) |
Dmitry Vyukov | 6a72c9d | 2013-04-30 13:30:29 +0000 | [diff] [blame] | 27 | # define va_copy(dst, src) ((dst) = (src)) |
| 28 | #endif |
| 29 | |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 30 | namespace __sanitizer { |
| 31 | |
Alexey Samsonov | 7ed46ff | 2013-04-05 07:30:29 +0000 | [diff] [blame] | 32 | StaticSpinMutex CommonSanitizerReportMutex; |
| 33 | |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 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 |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 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) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 48 | uptr const kMaxLen = 30; |
| 49 | RAW_CHECK(base == 10 || base == 16); |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 50 | RAW_CHECK(base == 10 || !negative); |
| 51 | RAW_CHECK(absolute_value || !negative); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 52 | RAW_CHECK(minimal_num_length < kMaxLen); |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 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, '-'); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 58 | uptr num_buffer[kMaxLen]; |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 59 | int pos = 0; |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 60 | do { |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 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); |
Alexey Samsonov | e52e280 | 2012-11-21 11:12:57 +0000 | [diff] [blame] | 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 | } |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 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--) { |
Timur Iskhodzhanov | 5e97ba3 | 2013-05-29 14:11:44 +0000 | [diff] [blame] | 79 | char digit = static_cast<char>(num_buffer[pos]); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 80 | result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit |
| 81 | : 'a' + digit - 10); |
| 82 | } |
| 83 | return result; |
| 84 | } |
| 85 | |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 86 | static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base, |
| 87 | u8 minimal_num_length, bool pad_with_zero) { |
| 88 | return AppendNumber(buff, buff_end, num, base, minimal_num_length, |
| 89 | pad_with_zero, false /* negative */); |
| 90 | } |
| 91 | |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 92 | static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num, |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 93 | u8 minimal_num_length, bool pad_with_zero) { |
| 94 | bool negative = (num < 0); |
| 95 | return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10, |
| 96 | minimal_num_length, pad_with_zero, negative); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 97 | } |
| 98 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 99 | static int AppendString(char **buff, const char *buff_end, int precision, |
| 100 | const char *s) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 101 | if (s == 0) |
| 102 | s = "<null>"; |
| 103 | int result = 0; |
| 104 | for (; *s; s++) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 105 | if (precision >= 0 && result >= precision) |
| 106 | break; |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 107 | result += AppendChar(buff, buff_end, *s); |
| 108 | } |
| 109 | return result; |
| 110 | } |
| 111 | |
| 112 | static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) { |
| 113 | int result = 0; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 114 | result += AppendString(buff, buff_end, -1, "0x"); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 115 | result += AppendUnsigned(buff, buff_end, ptr_value, 16, |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 116 | SANITIZER_POINTER_FORMAT_LENGTH, true); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 117 | return result; |
| 118 | } |
| 119 | |
| 120 | int VSNPrintf(char *buff, int buff_length, |
| 121 | const char *format, va_list args) { |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 122 | static const char *kPrintfFormatsHelp = |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 123 | "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %(\\.\\*)?s; %c\n"; |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 124 | RAW_CHECK(format); |
| 125 | RAW_CHECK(buff_length > 0); |
| 126 | const char *buff_end = &buff[buff_length - 1]; |
| 127 | const char *cur = format; |
| 128 | int result = 0; |
| 129 | for (; *cur; cur++) { |
| 130 | if (*cur != '%') { |
| 131 | result += AppendChar(&buff, buff_end, *cur); |
| 132 | continue; |
| 133 | } |
| 134 | cur++; |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 135 | bool have_width = (*cur >= '0' && *cur <= '9'); |
| 136 | bool pad_with_zero = (*cur == '0'); |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 137 | int width = 0; |
| 138 | if (have_width) { |
| 139 | while (*cur >= '0' && *cur <= '9') { |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 140 | width = width * 10 + *cur++ - '0'; |
| 141 | } |
| 142 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 143 | bool have_precision = (cur[0] == '.' && cur[1] == '*'); |
| 144 | int precision = -1; |
| 145 | if (have_precision) { |
| 146 | cur += 2; |
| 147 | precision = va_arg(args, int); |
| 148 | } |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 149 | bool have_z = (*cur == 'z'); |
| 150 | cur += have_z; |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 151 | bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l'); |
| 152 | cur += have_ll * 2; |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 153 | s64 dval; |
| 154 | u64 uval; |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 155 | bool have_flags = have_width | have_z | have_ll; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 156 | // Only %s supports precision for now |
| 157 | CHECK(!(precision >= 0 && *cur != 's')); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 158 | switch (*cur) { |
| 159 | case 'd': { |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 160 | dval = have_ll ? va_arg(args, s64) |
| 161 | : have_z ? va_arg(args, sptr) |
| 162 | : va_arg(args, int); |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 163 | result += AppendSignedDecimal(&buff, buff_end, dval, width, |
| 164 | pad_with_zero); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 165 | break; |
| 166 | } |
| 167 | case 'u': |
| 168 | case 'x': { |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 169 | uval = have_ll ? va_arg(args, u64) |
| 170 | : have_z ? va_arg(args, uptr) |
| 171 | : va_arg(args, unsigned); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 172 | result += AppendUnsigned(&buff, buff_end, uval, |
Sergey Matveev | 134da44 | 2013-06-27 15:30:44 +0000 | [diff] [blame] | 173 | (*cur == 'u') ? 10 : 16, width, pad_with_zero); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 174 | break; |
| 175 | } |
| 176 | case 'p': { |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 177 | RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 178 | result += AppendPointer(&buff, buff_end, va_arg(args, uptr)); |
| 179 | break; |
| 180 | } |
| 181 | case 's': { |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 182 | RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 183 | result += AppendString(&buff, buff_end, precision, va_arg(args, char*)); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 184 | break; |
| 185 | } |
Kostya Serebryany | 81dfbb7 | 2012-09-14 04:35:14 +0000 | [diff] [blame] | 186 | case 'c': { |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 187 | RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); |
Kostya Serebryany | 01167e8 | 2012-09-14 06:52:46 +0000 | [diff] [blame] | 188 | result += AppendChar(&buff, buff_end, va_arg(args, int)); |
Kostya Serebryany | 81dfbb7 | 2012-09-14 04:35:14 +0000 | [diff] [blame] | 189 | break; |
| 190 | } |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 191 | case '%' : { |
Richard Smith | f493220 | 2012-11-13 23:42:05 +0000 | [diff] [blame] | 192 | RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 193 | result += AppendChar(&buff, buff_end, '%'); |
| 194 | break; |
| 195 | } |
| 196 | default: { |
| 197 | RAW_CHECK_MSG(false, kPrintfFormatsHelp); |
| 198 | } |
| 199 | } |
| 200 | } |
| 201 | RAW_CHECK(buff <= buff_end); |
| 202 | AppendChar(&buff, buff_end + 1, '\0'); |
| 203 | return result; |
| 204 | } |
| 205 | |
Kostya Serebryany | 283c296 | 2012-08-28 11:34:40 +0000 | [diff] [blame] | 206 | static void (*PrintfAndReportCallback)(const char *); |
| 207 | void SetPrintfAndReportCallback(void (*callback)(const char *)) { |
| 208 | PrintfAndReportCallback = callback; |
| 209 | } |
| 210 | |
Dmitry Vyukov | 13f62b2 | 2013-03-25 12:58:09 +0000 | [diff] [blame] | 211 | // Can be overriden in frontend. |
Dmitry Vyukov | 6f2741c | 2013-10-14 09:52:40 +0000 | [diff] [blame] | 212 | #if SANITIZER_SUPPORTS_WEAK_HOOKS |
Timur Iskhodzhanov | 3c80c6c | 2013-08-13 11:42:45 +0000 | [diff] [blame] | 213 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE |
Dmitry Vyukov | 6f2741c | 2013-10-14 09:52:40 +0000 | [diff] [blame] | 214 | void OnPrint(const char *str) { |
| 215 | (void)str; |
| 216 | } |
| 217 | #elif defined(SANITIZER_GO) && defined(TSAN_EXTERNAL_HOOKS) |
Alexey Samsonov | 78b580f | 2013-04-03 13:22:54 +0000 | [diff] [blame] | 218 | void OnPrint(const char *str); |
Dmitry Vyukov | 6f2741c | 2013-10-14 09:52:40 +0000 | [diff] [blame] | 219 | #else |
| 220 | void OnPrint(const char *str) { |
| 221 | (void)str; |
| 222 | } |
Dmitry Vyukov | 13f62b2 | 2013-03-25 12:58:09 +0000 | [diff] [blame] | 223 | #endif |
| 224 | |
| 225 | static void CallPrintfAndReportCallback(const char *str) { |
Dmitry Vyukov | 6f2741c | 2013-10-14 09:52:40 +0000 | [diff] [blame] | 226 | OnPrint(str); |
Dmitry Vyukov | 13f62b2 | 2013-03-25 12:58:09 +0000 | [diff] [blame] | 227 | if (PrintfAndReportCallback) |
| 228 | PrintfAndReportCallback(str); |
| 229 | } |
| 230 | |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 231 | static void SharedPrintfCode(bool append_pid, const char *format, |
| 232 | va_list args) { |
Dmitry Vyukov | 4f5e4bb | 2013-04-30 12:27:48 +0000 | [diff] [blame] | 233 | va_list args2; |
| 234 | va_copy(args2, args); |
Alexey Samsonov | b1fe302 | 2012-11-02 12:17:51 +0000 | [diff] [blame] | 235 | const int kLen = 16 * 1024; |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 236 | // |local_buffer| is small enough not to overflow the stack and/or violate |
| 237 | // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other |
| 238 | // hand, the bigger the buffer is, the more the chance the error report will |
| 239 | // fit into it. |
| 240 | char local_buffer[400]; |
| 241 | int needed_length; |
| 242 | char *buffer = local_buffer; |
| 243 | int buffer_size = ARRAY_SIZE(local_buffer); |
| 244 | // First try to print a message using a local buffer, and then fall back to |
| 245 | // mmaped buffer. |
| 246 | for (int use_mmap = 0; use_mmap < 2; use_mmap++) { |
| 247 | if (use_mmap) { |
Dmitry Vyukov | 4f5e4bb | 2013-04-30 12:27:48 +0000 | [diff] [blame] | 248 | va_end(args); |
| 249 | va_copy(args, args2); |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 250 | buffer = (char*)MmapOrDie(kLen, "Report"); |
| 251 | buffer_size = kLen; |
| 252 | } |
| 253 | needed_length = 0; |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 254 | // Check that data fits into the current buffer. |
| 255 | # define CHECK_NEEDED_LENGTH \ |
| 256 | if (needed_length >= buffer_size) { \ |
| 257 | if (!use_mmap) continue; \ |
| 258 | RAW_CHECK_MSG(needed_length < kLen, \ |
| 259 | "Buffer in Report is too short!\n"); \ |
| 260 | } |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 261 | if (append_pid) { |
Peter Collingbourne | 0b694fc | 2013-05-17 16:56:53 +0000 | [diff] [blame] | 262 | int pid = internal_getpid(); |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 263 | const char *exe_name = GetBinaryBasename(); |
| 264 | if (common_flags()->log_exe_name && exe_name) { |
| 265 | needed_length += internal_snprintf(buffer, buffer_size, |
| 266 | "==%s", exe_name); |
| 267 | CHECK_NEEDED_LENGTH |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 268 | } |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 269 | needed_length += internal_snprintf(buffer + needed_length, |
| 270 | buffer_size - needed_length, |
| 271 | "==%d==", pid); |
| 272 | CHECK_NEEDED_LENGTH |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 273 | } |
| 274 | needed_length += VSNPrintf(buffer + needed_length, |
| 275 | buffer_size - needed_length, format, args); |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 276 | CHECK_NEEDED_LENGTH |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 277 | // If the message fit into the buffer, print it and exit. |
| 278 | break; |
Pirama Arumuga Nainar | cdce50b | 2015-07-01 12:26:56 -0700 | [diff] [blame] | 279 | # undef CHECK_NEEDED_LENGTH |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 280 | } |
| 281 | RawWrite(buffer); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 282 | AndroidLogWrite(buffer); |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 283 | CallPrintfAndReportCallback(buffer); |
| 284 | // If we had mapped any memory, clean up. |
| 285 | if (buffer != local_buffer) |
| 286 | UnmapOrDie((void *)buffer, buffer_size); |
Dmitry Vyukov | 4f5e4bb | 2013-04-30 12:27:48 +0000 | [diff] [blame] | 287 | va_end(args2); |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 288 | } |
| 289 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 290 | FORMAT(1, 2) |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 291 | void Printf(const char *format, ...) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 292 | va_list args; |
| 293 | va_start(args, format); |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 294 | SharedPrintfCode(false, format, args); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 295 | va_end(args); |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | // Like Printf, but prints the current PID before the output string. |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 299 | FORMAT(1, 2) |
Alexey Samsonov | 99f1e20 | 2013-04-18 13:18:23 +0000 | [diff] [blame] | 300 | void Report(const char *format, ...) { |
| 301 | va_list args; |
| 302 | va_start(args, format); |
| 303 | SharedPrintfCode(true, format, args); |
| 304 | va_end(args); |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 305 | } |
| 306 | |
| 307 | // Writes at most "length" symbols to "buffer" (including trailing '\0'). |
| 308 | // Returns the number of symbols that should have been written to buffer |
| 309 | // (not including trailing '\0'). Thus, the string is truncated |
| 310 | // iff return value is not less than "length". |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 311 | FORMAT(3, 4) |
Alexey Samsonov | de08c02 | 2012-06-19 09:21:57 +0000 | [diff] [blame] | 312 | int internal_snprintf(char *buffer, uptr length, const char *format, ...) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 313 | va_list args; |
| 314 | va_start(args, format); |
| 315 | int needed_length = VSNPrintf(buffer, length, format, args); |
| 316 | va_end(args); |
| 317 | return needed_length; |
| 318 | } |
| 319 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 320 | FORMAT(2, 3) |
Alexey Samsonov | bb4697f | 2013-11-14 09:41:24 +0000 | [diff] [blame] | 321 | void InternalScopedString::append(const char *format, ...) { |
| 322 | CHECK_LT(length_, size()); |
| 323 | va_list args; |
| 324 | va_start(args, format); |
| 325 | VSNPrintf(data() + length_, size() - length_, format, args); |
| 326 | va_end(args); |
| 327 | length_ += internal_strlen(data() + length_); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 328 | CHECK_LT(length_, size()); |
Alexey Samsonov | bb4697f | 2013-11-14 09:41:24 +0000 | [diff] [blame] | 329 | } |
| 330 | |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 331 | } // namespace __sanitizer |