summaryrefslogtreecommitdiff
path: root/libsanitizer/sanitizer_common/sanitizer_printf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libsanitizer/sanitizer_common/sanitizer_printf.cc')
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_printf.cc175
1 files changed, 123 insertions, 52 deletions
diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cc b/libsanitizer/sanitizer_common/sanitizer_printf.cc
index 8298f12bd7b..d7ce9736b24 100644
--- a/libsanitizer/sanitizer_common/sanitizer_printf.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_printf.cc
@@ -19,6 +19,10 @@
#include <stdio.h>
#include <stdarg.h>
+#if SANITIZER_WINDOWS && !defined(va_copy)
+# define va_copy(dst, src) ((dst) = (src))
+#endif
+
namespace __sanitizer {
StaticSpinMutex CommonSanitizerReportMutex;
@@ -32,45 +36,60 @@ static int AppendChar(char **buff, const char *buff_end, char c) {
}
// Appends number in a given base to buffer. If its length is less than
-// "minimal_num_length", it is padded with leading zeroes.
-static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
- u8 base, u8 minimal_num_length) {
+// |minimal_num_length|, it is padded with leading zeroes or spaces, depending
+// on the value of |pad_with_zero|.
+static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
+ u8 base, u8 minimal_num_length, bool pad_with_zero,
+ bool negative) {
uptr const kMaxLen = 30;
RAW_CHECK(base == 10 || base == 16);
+ RAW_CHECK(base == 10 || !negative);
+ RAW_CHECK(absolute_value || !negative);
RAW_CHECK(minimal_num_length < kMaxLen);
+ int result = 0;
+ if (negative && minimal_num_length)
+ --minimal_num_length;
+ if (negative && pad_with_zero)
+ result += AppendChar(buff, buff_end, '-');
uptr num_buffer[kMaxLen];
- uptr pos = 0;
+ int pos = 0;
do {
- RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
- num_buffer[pos++] = num % base;
- num /= base;
- } while (num > 0);
+ RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow");
+ num_buffer[pos++] = absolute_value % base;
+ absolute_value /= base;
+ } while (absolute_value > 0);
if (pos < minimal_num_length) {
// Make sure compiler doesn't insert call to memset here.
internal_memset(&num_buffer[pos], 0,
sizeof(num_buffer[0]) * (minimal_num_length - pos));
pos = minimal_num_length;
}
- int result = 0;
- while (pos-- > 0) {
- uptr digit = num_buffer[pos];
+ RAW_CHECK(pos > 0);
+ pos--;
+ for (; pos >= 0 && num_buffer[pos] == 0; pos--) {
+ char c = (pad_with_zero || pos == 0) ? '0' : ' ';
+ result += AppendChar(buff, buff_end, c);
+ }
+ if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-');
+ for (; pos >= 0; pos--) {
+ char digit = static_cast<char>(num_buffer[pos]);
result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
: 'a' + digit - 10);
}
return result;
}
+static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base,
+ u8 minimal_num_length, bool pad_with_zero) {
+ return AppendNumber(buff, buff_end, num, base, minimal_num_length,
+ pad_with_zero, false /* negative */);
+}
+
static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
- u8 minimal_num_length) {
- int result = 0;
- if (num < 0) {
- result += AppendChar(buff, buff_end, '-');
- num = -num;
- if (minimal_num_length)
- --minimal_num_length;
- }
- result += AppendUnsigned(buff, buff_end, (u64)num, 10, minimal_num_length);
- return result;
+ u8 minimal_num_length, bool pad_with_zero) {
+ bool negative = (num < 0);
+ return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10,
+ minimal_num_length, pad_with_zero, negative);
}
static int AppendString(char **buff, const char *buff_end, const char *s) {
@@ -87,14 +106,14 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
int result = 0;
result += AppendString(buff, buff_end, "0x");
result += AppendUnsigned(buff, buff_end, ptr_value, 16,
- (SANITIZER_WORDSIZE == 64) ? 12 : 8);
+ (SANITIZER_WORDSIZE == 64) ? 12 : 8, true);
return result;
}
int VSNPrintf(char *buff, int buff_length,
const char *format, va_list args) {
static const char *kPrintfFormatsHelp =
- "Supported Printf formats: %(0[0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n";
+ "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %s; %c\n";
RAW_CHECK(format);
RAW_CHECK(buff_length > 0);
const char *buff_end = &buff[buff_length - 1];
@@ -106,11 +125,11 @@ int VSNPrintf(char *buff, int buff_length,
continue;
}
cur++;
- bool have_width = (*cur == '0');
+ bool have_width = (*cur >= '0' && *cur <= '9');
+ bool pad_with_zero = (*cur == '0');
int width = 0;
if (have_width) {
while (*cur >= '0' && *cur <= '9') {
- have_width = true;
width = width * 10 + *cur++ - '0';
}
}
@@ -126,7 +145,8 @@ int VSNPrintf(char *buff, int buff_length,
dval = have_ll ? va_arg(args, s64)
: have_z ? va_arg(args, sptr)
: va_arg(args, int);
- result += AppendSignedDecimal(&buff, buff_end, dval, width);
+ result += AppendSignedDecimal(&buff, buff_end, dval, width,
+ pad_with_zero);
break;
}
case 'u':
@@ -135,7 +155,7 @@ int VSNPrintf(char *buff, int buff_length,
: have_z ? va_arg(args, uptr)
: va_arg(args, unsigned);
result += AppendUnsigned(&buff, buff_end, uval,
- (*cur == 'u') ? 10 : 16, width);
+ (*cur == 'u') ? 10 : 16, width, pad_with_zero);
break;
}
case 'p': {
@@ -173,17 +193,86 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)) {
PrintfAndReportCallback = callback;
}
-void Printf(const char *format, ...) {
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+// Can be overriden in frontend.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void OnPrint(const char *str);
+#endif
+
+static void CallPrintfAndReportCallback(const char *str) {
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+ if (&OnPrint != NULL)
+ OnPrint(str);
+#endif
+ if (PrintfAndReportCallback)
+ PrintfAndReportCallback(str);
+}
+
+static void SharedPrintfCode(bool append_pid, const char *format,
+ va_list args) {
+ va_list args2;
+ va_copy(args2, args);
const int kLen = 16 * 1024;
- InternalScopedBuffer<char> buffer(kLen);
+ // |local_buffer| is small enough not to overflow the stack and/or violate
+ // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other
+ // hand, the bigger the buffer is, the more the chance the error report will
+ // fit into it.
+ char local_buffer[400];
+ int needed_length;
+ char *buffer = local_buffer;
+ int buffer_size = ARRAY_SIZE(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++) {
+ if (use_mmap) {
+ va_end(args);
+ va_copy(args, args2);
+ buffer = (char*)MmapOrDie(kLen, "Report");
+ buffer_size = kLen;
+ }
+ needed_length = 0;
+ if (append_pid) {
+ int pid = internal_getpid();
+ needed_length += internal_snprintf(buffer, buffer_size, "==%d==", pid);
+ if (needed_length >= buffer_size) {
+ // The pid doesn't fit into the current buffer.
+ if (!use_mmap)
+ continue;
+ RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+ }
+ }
+ needed_length += VSNPrintf(buffer + needed_length,
+ buffer_size - needed_length, format, args);
+ if (needed_length >= buffer_size) {
+ // The message doesn't fit into the current buffer.
+ if (!use_mmap)
+ continue;
+ RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+ }
+ // If the message fit into the buffer, print it and exit.
+ break;
+ }
+ RawWrite(buffer);
+ CallPrintfAndReportCallback(buffer);
+ // If we had mapped any memory, clean up.
+ if (buffer != local_buffer)
+ UnmapOrDie((void *)buffer, buffer_size);
+ va_end(args2);
+}
+
+void Printf(const char *format, ...) {
va_list args;
va_start(args, format);
- int needed_length = VSNPrintf(buffer.data(), kLen, format, args);
+ SharedPrintfCode(false, format, args);
+ va_end(args);
+}
+
+// Like Printf, but prints the current PID before the output string.
+void Report(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ SharedPrintfCode(true, format, args);
va_end(args);
- RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
- RawWrite(buffer.data());
- if (PrintfAndReportCallback)
- PrintfAndReportCallback(buffer.data());
}
// Writes at most "length" symbols to "buffer" (including trailing '\0').
@@ -198,22 +287,4 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
return needed_length;
}
-// Like Printf, but prints the current PID before the output string.
-void Report(const char *format, ...) {
- const int kLen = 16 * 1024;
- InternalScopedBuffer<char> buffer(kLen);
- int needed_length = internal_snprintf(buffer.data(),
- kLen, "==%d== ", GetPid());
- RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
- va_list args;
- va_start(args, format);
- needed_length += VSNPrintf(buffer.data() + needed_length,
- kLen - needed_length, format, args);
- va_end(args);
- RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
- RawWrite(buffer.data());
- if (PrintfAndReportCallback)
- PrintfAndReportCallback(buffer.data());
-}
-
} // namespace __sanitizer