1 //===-- sanitizer_common.cc -----------------------------------------------===// 2 // 3 // This file is distributed under the University of Illinois Open Source 4 // License. See LICENSE.TXT for details. 5 // 6 //===----------------------------------------------------------------------===// 7 // 8 // This file is shared between AddressSanitizer and ThreadSanitizer 9 // run-time libraries. 10 //===----------------------------------------------------------------------===// 11 12 #include "sanitizer_common.h" 13 #include "sanitizer_libc.h" 14 15 namespace __sanitizer { 16 17 const char *SanitizerToolName = "SanitizerTool"; 18 19 uptr GetPageSizeCached() { 20 static uptr PageSize; 21 if (!PageSize) 22 PageSize = GetPageSize(); 23 return PageSize; 24 } 25 26 static 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>". 31 static fd_t report_fd = kStderrFd; 32 static 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|. 35 static int report_fd_pid = 0; 36 37 static void (*DieCallback)(void); 38 void SetDieCallback(void (*callback)(void)) { 39 DieCallback = callback; 40 } 41 42 void NORETURN Die() { 43 if (DieCallback) { 44 DieCallback(); 45 } 46 internal__exit(1); 47 } 48 49 static CheckFailedCallbackType CheckFailedCallback; 50 void SetCheckFailedCallback(CheckFailedCallbackType callback) { 51 CheckFailedCallback = callback; 52 } 53 54 void 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 64 static void MaybeOpenReportFile() { 65 if (!log_to_file || (report_fd_pid == GetPid())) return; 66 InternalScopedBuffer<char> report_path_full(4096); 67 internal_snprintf(report_path_full.data(), report_path_full.size(), 68 "%s.%d", report_path_prefix, GetPid()); 69 fd_t fd = OpenFile(report_path_full.data(), 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.data()); 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 84 bool PrintsToTty() { 85 MaybeOpenReportFile(); 86 return internal_isatty(report_fd); 87 } 88 89 void 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 99 uptr 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 = OpenFile(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. 137 void 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. 175 void *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 void ReportErrorSummary(const char *error_type, const char *file, 194 int line, const char *function) { 195 const int kMaxSize = 1024; // We don't want a summary too long. 196 InternalScopedBuffer<char> buff(kMaxSize); 197 internal_snprintf(buff.data(), kMaxSize, "%s: %s %s:%d %s", 198 SanitizerToolName, error_type, 199 file ? file : "??", line, function ? function : "??"); 200 __sanitizer_report_error_summary(buff.data()); 201 } 202 203 } // namespace __sanitizer 204 205 using namespace __sanitizer; // NOLINT 206 207 extern "C" { 208 void __sanitizer_set_report_path(const char *path) { 209 if (!path) return; 210 uptr len = internal_strlen(path); 211 if (len > sizeof(report_path_prefix) - 100) { 212 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 213 path[0], path[1], path[2], path[3], 214 path[4], path[5], path[6], path[7]); 215 Die(); 216 } 217 internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix)); 218 report_path_prefix[len] = '\0'; 219 report_fd = kInvalidFd; 220 log_to_file = true; 221 } 222 223 void __sanitizer_set_report_fd(int fd) { 224 if (report_fd != kStdoutFd && 225 report_fd != kStderrFd && 226 report_fd != kInvalidFd) 227 internal_close(report_fd); 228 report_fd = fd; 229 } 230 231 void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) { 232 (void)reserved; 233 PrepareForSandboxing(); 234 } 235 236 void __sanitizer_report_error_summary(const char *error_summary) { 237 Printf("SUMMARY: %s\n", error_summary); 238 } 239 } // extern "C" 240