diff options
Diffstat (limited to 'compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp')
-rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp | 84 |
1 files changed, 49 insertions, 35 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp index a032787114bb..b913c92e16f1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_printf.cpp @@ -20,6 +20,10 @@ #include <stdio.h> #include <stdarg.h> +#if defined(__x86_64__) +# include <emmintrin.h> +#endif + #if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \ !defined(va_copy) # define va_copy(dst, src) ((dst) = (src)) @@ -128,7 +132,7 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) { int VSNPrintf(char *buff, int buff_length, const char *format, va_list args) { static const char *kPrintfFormatsHelp = - "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; " + "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X,V}; %p; " "%[-]([0-9]*)?(\\.\\*)?s; %c\n"; RAW_CHECK(format); RAW_CHECK(buff_length > 0); @@ -162,17 +166,15 @@ int VSNPrintf(char *buff, int buff_length, cur += have_z; bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l'); cur += have_ll * 2; - s64 dval; - u64 uval; const bool have_length = have_z || have_ll; const bool have_flags = have_width || have_length; // At the moment only %s supports precision and left-justification. CHECK(!((precision >= 0 || left_justified) && *cur != 's')); switch (*cur) { case 'd': { - dval = have_ll ? va_arg(args, s64) - : have_z ? va_arg(args, sptr) - : va_arg(args, int); + s64 dval = have_ll ? va_arg(args, s64) + : have_z ? va_arg(args, sptr) + : va_arg(args, int); result += AppendSignedDecimal(&buff, buff_end, dval, width, pad_with_zero); break; @@ -180,14 +182,21 @@ int VSNPrintf(char *buff, int buff_length, case 'u': case 'x': case 'X': { - uval = have_ll ? va_arg(args, u64) - : have_z ? va_arg(args, uptr) - : va_arg(args, unsigned); + u64 uval = have_ll ? va_arg(args, u64) + : have_z ? va_arg(args, uptr) + : va_arg(args, unsigned); bool uppercase = (*cur == 'X'); result += AppendUnsigned(&buff, buff_end, uval, (*cur == 'u') ? 10 : 16, width, pad_with_zero, uppercase); break; } + case 'V': { + for (uptr i = 0; i < 16; i++) { + unsigned x = va_arg(args, unsigned); + result += AppendUnsigned(&buff, buff_end, x, 16, 2, true, false); + } + break; + } case 'p': { RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp); result += AppendPointer(&buff, buff_end, va_arg(args, uptr)); @@ -249,26 +258,21 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, va_list args) { va_list args2; va_copy(args2, args); - const int kLen = 16 * 1024; - int needed_length; + InternalMmapVector<char> v; + int needed_length = 0; char *buffer = local_buffer; // First try to print a message using a local buffer, and then fall back to // mmaped buffer. - for (int use_mmap = 0; use_mmap < 2; use_mmap++) { + for (int use_mmap = 0;; use_mmap++) { if (use_mmap) { va_end(args); va_copy(args, args2); - buffer = (char*)MmapOrDie(kLen, "Report"); - buffer_size = kLen; + v.resize(needed_length + 1); + buffer_size = v.capacity(); + v.resize(buffer_size); + buffer = &v[0]; } needed_length = 0; - // Check that data fits into the current buffer. -# define CHECK_NEEDED_LENGTH \ - if (needed_length >= buffer_size) { \ - if (!use_mmap) continue; \ - RAW_CHECK_MSG(needed_length < kLen, \ - "Buffer in Report is too short!\n"); \ - } // Fuchsia's logging infrastructure always keeps track of the logging // process, thread, and timestamp, so never prepend such information. if (!SANITIZER_FUCHSIA && append_pid) { @@ -277,18 +281,20 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, if (common_flags()->log_exe_name && exe_name) { needed_length += internal_snprintf(buffer, buffer_size, "==%s", exe_name); - CHECK_NEEDED_LENGTH + if (needed_length >= buffer_size) + continue; } needed_length += internal_snprintf( buffer + needed_length, buffer_size - needed_length, "==%d==", pid); - CHECK_NEEDED_LENGTH + if (needed_length >= buffer_size) + continue; } needed_length += VSNPrintf(buffer + needed_length, buffer_size - needed_length, format, args); - CHECK_NEEDED_LENGTH + if (needed_length >= buffer_size) + continue; // If the message fit into the buffer, print it and exit. break; -# undef CHECK_NEEDED_LENGTH } RawWrite(buffer); @@ -297,9 +303,6 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid, CallPrintfAndReportCallback(buffer); LogMessageOnPrintf(buffer); - // If we had mapped any memory, clean up. - if (buffer != local_buffer) - UnmapOrDie((void *)buffer, buffer_size); va_end(args2); } @@ -346,13 +349,24 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) { FORMAT(2, 3) void InternalScopedString::append(const char *format, ...) { - CHECK_LT(length_, size()); - va_list args; - va_start(args, format); - VSNPrintf(data() + length_, size() - length_, format, args); - va_end(args); - length_ += internal_strlen(data() + length_); - CHECK_LT(length_, size()); + uptr prev_len = length(); + + while (true) { + buffer_.resize(buffer_.capacity()); + + va_list args; + va_start(args, format); + uptr sz = VSNPrintf(buffer_.data() + prev_len, buffer_.size() - prev_len, + format, args); + va_end(args); + if (sz < buffer_.size() - prev_len) { + buffer_.resize(prev_len + sz + 1); + break; + } + + buffer_.reserve(buffer_.capacity() * 2); + } + CHECK_EQ(buffer_[length()], '\0'); } } // namespace __sanitizer |