sanitizer_common.cc revision 25742574510cfb41b97e32f63f107fbb9b328d13
1//===-- sanitizer_common.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// run-time libraries. 12//===----------------------------------------------------------------------===// 13 14#include "sanitizer_common.h" 15#include "sanitizer_libc.h" 16 17namespace __sanitizer { 18 19uptr GetPageSizeCached() { 20 static uptr PageSize; 21 if (!PageSize) 22 PageSize = GetPageSize(); 23 return PageSize; 24} 25 26// By default, dump to stderr. If report_fd is kInvalidFd, try to obtain file 27// descriptor by opening file in report_path. 28static fd_t report_fd = kStderrFd; 29static char report_path[4096]; // Set via __sanitizer_set_report_path. 30 31static void (*DieCallback)(void); 32void SetDieCallback(void (*callback)(void)) { 33 DieCallback = callback; 34} 35 36void NORETURN Die() { 37 if (DieCallback) { 38 DieCallback(); 39 } 40 Exit(1); 41} 42 43static CheckFailedCallbackType CheckFailedCallback; 44void SetCheckFailedCallback(CheckFailedCallbackType callback) { 45 CheckFailedCallback = callback; 46} 47 48void NORETURN CheckFailed(const char *file, int line, const char *cond, 49 u64 v1, u64 v2) { 50 if (CheckFailedCallback) { 51 CheckFailedCallback(file, line, cond, v1, v2); 52 } 53 Report("Sanitizer CHECK failed: %s:%d %s (%zd, %zd)\n", file, line, cond, 54 v1, v2); 55 Die(); 56} 57 58static void MaybeOpenReportFile() { 59 if (report_fd != kInvalidFd) 60 return; 61 fd_t fd = internal_open(report_path, true); 62 if (fd == kInvalidFd) { 63 report_fd = kStderrFd; 64 Report("ERROR: Can't open file: %s\n", report_path); 65 Die(); 66 } 67 report_fd = fd; 68} 69 70bool PrintsToTty() { 71 MaybeOpenReportFile(); 72 return internal_isatty(report_fd); 73} 74 75void RawWrite(const char *buffer) { 76 static const char *kRawWriteError = "RawWrite can't output requested buffer!"; 77 uptr length = (uptr)internal_strlen(buffer); 78 MaybeOpenReportFile(); 79 if (length != internal_write(report_fd, buffer, length)) { 80 internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError)); 81 Die(); 82 } 83} 84 85uptr ReadFileToBuffer(const char *file_name, char **buff, 86 uptr *buff_size, uptr max_len) { 87 uptr PageSize = GetPageSizeCached(); 88 uptr kMinFileLen = PageSize; 89 uptr read_len = 0; 90 *buff = 0; 91 *buff_size = 0; 92 // The files we usually open are not seekable, so try different buffer sizes. 93 for (uptr size = kMinFileLen; size <= max_len; size *= 2) { 94 fd_t fd = internal_open(file_name, /*write*/ false); 95 if (fd == kInvalidFd) return 0; 96 UnmapOrDie(*buff, *buff_size); 97 *buff = (char*)MmapOrDie(size, __FUNCTION__); 98 *buff_size = size; 99 // Read up to one page at a time. 100 read_len = 0; 101 bool reached_eof = false; 102 while (read_len + PageSize <= size) { 103 uptr just_read = internal_read(fd, *buff + read_len, PageSize); 104 if (just_read == 0) { 105 reached_eof = true; 106 break; 107 } 108 read_len += just_read; 109 } 110 internal_close(fd); 111 if (reached_eof) // We've read the whole file. 112 break; 113 } 114 return read_len; 115} 116 117// We don't want to use std::sort to avoid including <algorithm>, as 118// we may end up with two implementation of std::sort - one in instrumented 119// code, and the other in runtime. 120// qsort() from stdlib won't work as it calls malloc(), which results 121// in deadlock in ASan allocator. 122// We re-implement in-place sorting w/o recursion as straightforward heapsort. 123void SortArray(uptr *array, uptr size) { 124 if (size < 2) 125 return; 126 // Stage 1: insert elements to the heap. 127 for (uptr i = 1; i < size; i++) { 128 uptr j, p; 129 for (j = i; j > 0; j = p) { 130 p = (j - 1) / 2; 131 if (array[j] > array[p]) 132 Swap(array[j], array[p]); 133 else 134 break; 135 } 136 } 137 // Stage 2: swap largest element with the last one, 138 // and sink the new top. 139 for (uptr i = size - 1; i > 0; i--) { 140 Swap(array[0], array[i]); 141 uptr j, max_ind; 142 for (j = 0; j < i; j = max_ind) { 143 uptr left = 2 * j + 1; 144 uptr right = 2 * j + 2; 145 max_ind = j; 146 if (left < i && array[left] > array[max_ind]) 147 max_ind = left; 148 if (right < i && array[right] > array[max_ind]) 149 max_ind = right; 150 if (max_ind != j) 151 Swap(array[j], array[max_ind]); 152 else 153 break; 154 } 155 } 156} 157 158// We want to map a chunk of address space aligned to 'alignment'. 159// We do it by maping a bit more and then unmaping redundant pieces. 160// We probably can do it with fewer syscalls in some OS-dependent way. 161void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { 162// uptr PageSize = GetPageSizeCached(); 163 CHECK(IsPowerOfTwo(size)); 164 CHECK(IsPowerOfTwo(alignment)); 165 uptr map_size = size + alignment; 166 uptr map_res = (uptr)MmapOrDie(map_size, mem_type); 167 uptr map_end = map_res + map_size; 168 uptr res = map_res; 169 if (res & (alignment - 1)) // Not aligned. 170 res = (map_res + alignment) & ~(alignment - 1); 171 uptr end = res + size; 172 if (res != map_res) 173 UnmapOrDie((void*)map_res, res - map_res); 174 if (end != map_end) 175 UnmapOrDie((void*)end, map_end - end); 176 return (void*)res; 177} 178 179} // namespace __sanitizer 180 181using namespace __sanitizer; // NOLINT 182 183extern "C" { 184void __sanitizer_set_report_path(const char *path) { 185 if (!path) return; 186 uptr len = internal_strlen(path); 187 if (len > sizeof(report_path) - 100) { 188 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 189 path[0], path[1], path[2], path[3], 190 path[4], path[5], path[6], path[7]); 191 Die(); 192 } 193 internal_snprintf(report_path, sizeof(report_path), "%s.%d", path, GetPid()); 194 report_fd = kInvalidFd; 195} 196 197void __sanitizer_set_report_fd(int fd) { 198 if (report_fd != kStdoutFd && 199 report_fd != kStderrFd && 200 report_fd != kInvalidFd) 201 internal_close(report_fd); 202 report_fd = fd; 203} 204 205void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) { 206 (void)reserved; 207 PrepareForSandboxing(); 208} 209 210} // extern "C" 211