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