1//===-- asan_printf.cc ------------------------------------------*- C++ -*-===// 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 a part of AddressSanitizer, an address sanity checker. 11// 12// Internal printf function, used inside ASan run-time library. 13// We can't use libc printf because we intercept some of the functions used 14// inside it. 15//===----------------------------------------------------------------------===// 16 17#include "asan_internal.h" 18#include "asan_interceptors.h" 19 20#include <stdarg.h> 21#include <stdio.h> 22 23namespace __asan { 24 25extern char *error_message_buffer; 26extern size_t error_message_buffer_pos, error_message_buffer_size; 27 28void RawWrite(const char *buffer) { 29 static const char *kRawWriteError = "RawWrite can't output requested buffer!"; 30 size_t length = (size_t)internal_strlen(buffer); 31 if (length != AsanWrite(2, buffer, length)) { 32 AsanWrite(2, kRawWriteError, internal_strlen(kRawWriteError)); 33 AsanDie(); 34 } 35 if (error_message_buffer) { 36 int remaining = error_message_buffer_size - error_message_buffer_pos; 37 internal_strncpy(error_message_buffer + error_message_buffer_pos, 38 buffer, remaining); 39 error_message_buffer[error_message_buffer_size - 1] = '\0'; 40 // FIXME: reallocate the buffer instead of truncating the message. 41 error_message_buffer_pos += remaining > length ? length : remaining; 42 } 43} 44 45static inline int AppendChar(char **buff, const char *buff_end, char c) { 46 if (*buff < buff_end) { 47 **buff = c; 48 (*buff)++; 49 } 50 return 1; 51} 52 53// Appends number in a given base to buffer. If its length is less than 54// "minimal_num_length", it is padded with leading zeroes. 55static int AppendUnsigned(char **buff, const char *buff_end, uint64_t num, 56 uint8_t base, uint8_t minimal_num_length) { 57 size_t const kMaxLen = 30; 58 RAW_CHECK(base == 10 || base == 16); 59 RAW_CHECK(minimal_num_length < kMaxLen); 60 size_t num_buffer[kMaxLen]; 61 size_t pos = 0; 62 do { 63 RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow"); 64 num_buffer[pos++] = num % base; 65 num /= base; 66 } while (num > 0); 67 while (pos < minimal_num_length) num_buffer[pos++] = 0; 68 int result = 0; 69 while (pos-- > 0) { 70 size_t digit = num_buffer[pos]; 71 result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit 72 : 'a' + digit - 10); 73 } 74 return result; 75} 76 77static inline int AppendSignedDecimal(char **buff, const char *buff_end, 78 int64_t num) { 79 int result = 0; 80 if (num < 0) { 81 result += AppendChar(buff, buff_end, '-'); 82 num = -num; 83 } 84 result += AppendUnsigned(buff, buff_end, (uint64_t)num, 10, 0); 85 return result; 86} 87 88static inline int AppendString(char **buff, const char *buff_end, 89 const char *s) { 90 // Avoid library functions like stpcpy here. 91 RAW_CHECK(s); 92 int result = 0; 93 for (; *s; s++) { 94 result += AppendChar(buff, buff_end, *s); 95 } 96 return result; 97} 98 99static inline int AppendPointer(char **buff, const char *buff_end, 100 uint64_t ptr_value) { 101 int result = 0; 102 result += AppendString(buff, buff_end, "0x"); 103 result += AppendUnsigned(buff, buff_end, ptr_value, 16, 104 (__WORDSIZE == 64) ? 12 : 8); 105 return result; 106} 107 108static int VSNPrintf(char *buff, int buff_length, 109 const char *format, va_list args) { 110 static const char *kPrintfFormatsHelp = "Supported Printf formats: " 111 "%%[z]{d,u,x}; %%p; %%s"; 112 RAW_CHECK(format); 113 RAW_CHECK(buff_length > 0); 114 const char *buff_end = &buff[buff_length - 1]; 115 const char *cur = format; 116 int result = 0; 117 for (; *cur; cur++) { 118 if (*cur == '%') { 119 cur++; 120 bool have_z = (*cur == 'z'); 121 cur += have_z; 122 int64_t dval; 123 uint64_t uval; 124 switch (*cur) { 125 case 'd': dval = have_z ? va_arg(args, intptr_t) 126 : va_arg(args, int); 127 result += AppendSignedDecimal(&buff, buff_end, dval); 128 break; 129 case 'u': uval = have_z ? va_arg(args, size_t) 130 : va_arg(args, unsigned); 131 result += AppendUnsigned(&buff, buff_end, uval, 10, 0); 132 break; 133 case 'x': uval = have_z ? va_arg(args, size_t) 134 : va_arg(args, unsigned); 135 result += AppendUnsigned(&buff, buff_end, uval, 16, 0); 136 break; 137 case 'p': RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp); 138 result += AppendPointer(&buff, buff_end, 139 va_arg(args, uintptr_t)); 140 break; 141 case 's': RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp); 142 result += AppendString(&buff, buff_end, va_arg(args, char*)); 143 break; 144 default: RAW_CHECK_MSG(false, kPrintfFormatsHelp); 145 } 146 } else { 147 result += AppendChar(&buff, buff_end, *cur); 148 } 149 } 150 RAW_CHECK(buff <= buff_end); 151 AppendChar(&buff, buff_end + 1, '\0'); 152 return result; 153} 154 155void Printf(const char *format, ...) { 156 const int kLen = 1024 * 4; 157 char buffer[kLen]; 158 va_list args; 159 va_start(args, format); 160 int needed_length = VSNPrintf(buffer, kLen, format, args); 161 va_end(args); 162 RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n"); 163 RawWrite(buffer); 164} 165 166// Writes at most "length" symbols to "buffer" (including trailing '\0'). 167// Returns the number of symbols that should have been written to buffer 168// (not including trailing '\0'). Thus, the string is truncated 169// iff return value is not less than "length". 170int SNPrintf(char *buffer, size_t length, const char *format, ...) { 171 va_list args; 172 va_start(args, format); 173 int needed_length = VSNPrintf(buffer, length, format, args); 174 va_end(args); 175 return needed_length; 176} 177 178// Like Printf, but prints the current PID before the output string. 179void Report(const char *format, ...) { 180 const int kLen = 1024 * 4; 181 char buffer[kLen]; 182 int needed_length = SNPrintf(buffer, kLen, "==%d== ", GetPid()); 183 RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n"); 184 va_list args; 185 va_start(args, format); 186 needed_length += VSNPrintf(buffer + needed_length, kLen - needed_length, 187 format, args); 188 va_end(args); 189 RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n"); 190 RawWrite(buffer); 191} 192 193int SScanf(const char *str, const char *format, ...) { 194#ifndef _WIN32 195 va_list args; 196 va_start(args, format); 197 int res = vsscanf(str, format, args); 198 va_end(args); 199 return res; 200#else 201 UNIMPLEMENTED(); 202 return -1; 203#endif 204} 205 206} // namespace __asan 207