]> git.ipfire.org Git - thirdparty/gcc.git/blob - libsanitizer/sanitizer_common/sanitizer_printf.cpp
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / libsanitizer / sanitizer_common / sanitizer_printf.cpp
1 //===-- sanitizer_printf.cpp ----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is shared between AddressSanitizer and ThreadSanitizer.
10 //
11 // Internal printf function, used inside run-time libraries.
12 // We can't use libc printf because we intercept some of the functions used
13 // inside it.
14 //===----------------------------------------------------------------------===//
15
16 #include "sanitizer_common.h"
17 #include "sanitizer_flags.h"
18 #include "sanitizer_libc.h"
19
20 #include <stdio.h>
21 #include <stdarg.h>
22
23 #if defined(__x86_64__)
24 # include <emmintrin.h>
25 #endif
26
27 #if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \
28 !defined(va_copy)
29 # define va_copy(dst, src) ((dst) = (src))
30 #endif
31
32 namespace __sanitizer {
33
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
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, bool uppercase) {
48 uptr const kMaxLen = 30;
49 RAW_CHECK(base == 10 || base == 16);
50 RAW_CHECK(base == 10 || !negative);
51 RAW_CHECK(absolute_value || !negative);
52 RAW_CHECK(minimal_num_length < kMaxLen);
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, '-');
58 uptr num_buffer[kMaxLen];
59 int pos = 0;
60 do {
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);
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 }
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--) {
79 char digit = static_cast<char>(num_buffer[pos]);
80 digit = (digit < 10) ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10;
81 result += AppendChar(buff, buff_end, digit);
82 }
83 return result;
84 }
85
86 static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base,
87 u8 minimal_num_length, bool pad_with_zero,
88 bool uppercase) {
89 return AppendNumber(buff, buff_end, num, base, minimal_num_length,
90 pad_with_zero, false /* negative */, uppercase);
91 }
92
93 static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
94 u8 minimal_num_length, bool pad_with_zero) {
95 bool negative = (num < 0);
96 return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10,
97 minimal_num_length, pad_with_zero, negative,
98 false /* uppercase */);
99 }
100
101
102 // Use the fact that explicitly requesting 0 width (%0s) results in UB and
103 // interpret width == 0 as "no width requested":
104 // width == 0 - no width requested
105 // width < 0 - left-justify s within and pad it to -width chars, if necessary
106 // width > 0 - right-justify s, not implemented yet
107 static int AppendString(char **buff, const char *buff_end, int width,
108 int max_chars, const char *s) {
109 if (!s)
110 s = "<null>";
111 int result = 0;
112 for (; *s; s++) {
113 if (max_chars >= 0 && result >= max_chars)
114 break;
115 result += AppendChar(buff, buff_end, *s);
116 }
117 // Only the left justified strings are supported.
118 while (width < -result)
119 result += AppendChar(buff, buff_end, ' ');
120 return result;
121 }
122
123 static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
124 int result = 0;
125 result += AppendString(buff, buff_end, 0, -1, "0x");
126 result += AppendUnsigned(buff, buff_end, ptr_value, 16,
127 SANITIZER_POINTER_FORMAT_LENGTH,
128 true /* pad_with_zero */, false /* uppercase */);
129 return result;
130 }
131
132 int VSNPrintf(char *buff, int buff_length,
133 const char *format, va_list args) {
134 static const char *kPrintfFormatsHelp =
135 "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X,V}; %p; "
136 "%[-]([0-9]*)?(\\.\\*)?s; %c\n";
137 RAW_CHECK(format);
138 RAW_CHECK(buff_length > 0);
139 const char *buff_end = &buff[buff_length - 1];
140 const char *cur = format;
141 int result = 0;
142 for (; *cur; cur++) {
143 if (*cur != '%') {
144 result += AppendChar(&buff, buff_end, *cur);
145 continue;
146 }
147 cur++;
148 bool left_justified = *cur == '-';
149 if (left_justified)
150 cur++;
151 bool have_width = (*cur >= '0' && *cur <= '9');
152 bool pad_with_zero = (*cur == '0');
153 int width = 0;
154 if (have_width) {
155 while (*cur >= '0' && *cur <= '9') {
156 width = width * 10 + *cur++ - '0';
157 }
158 }
159 bool have_precision = (cur[0] == '.' && cur[1] == '*');
160 int precision = -1;
161 if (have_precision) {
162 cur += 2;
163 precision = va_arg(args, int);
164 }
165 bool have_z = (*cur == 'z');
166 cur += have_z;
167 bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l');
168 cur += have_ll * 2;
169 const bool have_length = have_z || have_ll;
170 const bool have_flags = have_width || have_length;
171 // At the moment only %s supports precision and left-justification.
172 CHECK(!((precision >= 0 || left_justified) && *cur != 's'));
173 switch (*cur) {
174 case 'd': {
175 s64 dval = have_ll ? va_arg(args, s64)
176 : have_z ? va_arg(args, sptr)
177 : va_arg(args, int);
178 result += AppendSignedDecimal(&buff, buff_end, dval, width,
179 pad_with_zero);
180 break;
181 }
182 case 'u':
183 case 'x':
184 case 'X': {
185 u64 uval = have_ll ? va_arg(args, u64)
186 : have_z ? va_arg(args, uptr)
187 : va_arg(args, unsigned);
188 bool uppercase = (*cur == 'X');
189 result += AppendUnsigned(&buff, buff_end, uval, (*cur == 'u') ? 10 : 16,
190 width, pad_with_zero, uppercase);
191 break;
192 }
193 case 'V': {
194 for (uptr i = 0; i < 16; i++) {
195 unsigned x = va_arg(args, unsigned);
196 result += AppendUnsigned(&buff, buff_end, x, 16, 2, true, false);
197 }
198 break;
199 }
200 case 'p': {
201 RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
202 result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
203 break;
204 }
205 case 's': {
206 RAW_CHECK_MSG(!have_length, kPrintfFormatsHelp);
207 // Only left-justified width is supported.
208 CHECK(!have_width || left_justified);
209 result += AppendString(&buff, buff_end, left_justified ? -width : width,
210 precision, va_arg(args, char*));
211 break;
212 }
213 case 'c': {
214 RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
215 result += AppendChar(&buff, buff_end, va_arg(args, int));
216 break;
217 }
218 case '%' : {
219 RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
220 result += AppendChar(&buff, buff_end, '%');
221 break;
222 }
223 default: {
224 RAW_CHECK_MSG(false, kPrintfFormatsHelp);
225 }
226 }
227 }
228 RAW_CHECK(buff <= buff_end);
229 AppendChar(&buff, buff_end + 1, '\0');
230 return result;
231 }
232
233 static void (*PrintfAndReportCallback)(const char *);
234 void SetPrintfAndReportCallback(void (*callback)(const char *)) {
235 PrintfAndReportCallback = callback;
236 }
237
238 // Can be overriden in frontend.
239 #if SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS)
240 // Implementation must be defined in frontend.
241 extern "C" void __sanitizer_on_print(const char *str);
242 #else
243 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_on_print, const char *str) {
244 (void)str;
245 }
246 #endif
247
248 static void CallPrintfAndReportCallback(const char *str) {
249 __sanitizer_on_print(str);
250 if (PrintfAndReportCallback)
251 PrintfAndReportCallback(str);
252 }
253
254 static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
255 char *local_buffer,
256 int buffer_size,
257 const char *format,
258 va_list args) {
259 va_list args2;
260 va_copy(args2, args);
261 InternalMmapVector<char> v;
262 int needed_length = 0;
263 char *buffer = local_buffer;
264 // First try to print a message using a local buffer, and then fall back to
265 // mmaped buffer.
266 for (int use_mmap = 0;; use_mmap++) {
267 if (use_mmap) {
268 va_end(args);
269 va_copy(args, args2);
270 v.resize(needed_length + 1);
271 buffer_size = v.capacity();
272 v.resize(buffer_size);
273 buffer = &v[0];
274 }
275 needed_length = 0;
276 // Fuchsia's logging infrastructure always keeps track of the logging
277 // process, thread, and timestamp, so never prepend such information.
278 if (!SANITIZER_FUCHSIA && append_pid) {
279 int pid = internal_getpid();
280 const char *exe_name = GetProcessName();
281 if (common_flags()->log_exe_name && exe_name) {
282 needed_length += internal_snprintf(buffer, buffer_size,
283 "==%s", exe_name);
284 if (needed_length >= buffer_size)
285 continue;
286 }
287 needed_length += internal_snprintf(
288 buffer + needed_length, buffer_size - needed_length, "==%d==", pid);
289 if (needed_length >= buffer_size)
290 continue;
291 }
292 needed_length += VSNPrintf(buffer + needed_length,
293 buffer_size - needed_length, format, args);
294 if (needed_length >= buffer_size)
295 continue;
296 // If the message fit into the buffer, print it and exit.
297 break;
298 }
299 RawWrite(buffer);
300
301 // Remove color sequences from the message.
302 RemoveANSIEscapeSequencesFromString(buffer);
303 CallPrintfAndReportCallback(buffer);
304 LogMessageOnPrintf(buffer);
305
306 va_end(args2);
307 }
308
309 static void NOINLINE SharedPrintfCode(bool append_pid, const char *format,
310 va_list args) {
311 // |local_buffer| is small enough not to overflow the stack and/or violate
312 // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other
313 // hand, the bigger the buffer is, the more the chance the error report will
314 // fit into it.
315 char local_buffer[400];
316 SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer),
317 format, args);
318 }
319
320 FORMAT(1, 2)
321 void Printf(const char *format, ...) {
322 va_list args;
323 va_start(args, format);
324 SharedPrintfCode(false, format, args);
325 va_end(args);
326 }
327
328 // Like Printf, but prints the current PID before the output string.
329 FORMAT(1, 2)
330 void Report(const char *format, ...) {
331 va_list args;
332 va_start(args, format);
333 SharedPrintfCode(true, format, args);
334 va_end(args);
335 }
336
337 // Writes at most "length" symbols to "buffer" (including trailing '\0').
338 // Returns the number of symbols that should have been written to buffer
339 // (not including trailing '\0'). Thus, the string is truncated
340 // iff return value is not less than "length".
341 FORMAT(3, 4)
342 int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
343 va_list args;
344 va_start(args, format);
345 int needed_length = VSNPrintf(buffer, length, format, args);
346 va_end(args);
347 return needed_length;
348 }
349
350 FORMAT(2, 3)
351 void InternalScopedString::append(const char *format, ...) {
352 uptr prev_len = length();
353
354 while (true) {
355 buffer_.resize(buffer_.capacity());
356
357 va_list args;
358 va_start(args, format);
359 uptr sz = VSNPrintf(buffer_.data() + prev_len, buffer_.size() - prev_len,
360 format, args);
361 va_end(args);
362 if (sz < buffer_.size() - prev_len) {
363 buffer_.resize(prev_len + sz + 1);
364 break;
365 }
366
367 buffer_.reserve(buffer_.capacity() * 2);
368 }
369 CHECK_EQ(buffer_[length()], '\0');
370 }
371
372 } // namespace __sanitizer