sanitizer_common.cc revision 50cdc5a0d78f400183bd9dc7c23a2ed6e733e48b
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_flags.h" 16#include "sanitizer_libc.h" 17#include "sanitizer_stacktrace.h" 18#include "sanitizer_symbolizer.h" 19 20namespace __sanitizer { 21 22const char *SanitizerToolName = "SanitizerTool"; 23 24uptr GetPageSizeCached() { 25 static uptr PageSize; 26 if (!PageSize) 27 PageSize = GetPageSize(); 28 return PageSize; 29} 30 31 32// By default, dump to stderr. If |log_to_file| is true and |report_fd_pid| 33// isn't equal to the current PID, try to obtain file descriptor by opening 34// file "report_path_prefix.<PID>". 35fd_t report_fd = kStderrFd; 36 37// Set via __sanitizer_set_report_path. 38bool log_to_file = false; 39char report_path_prefix[sizeof(report_path_prefix)]; 40 41// PID of process that opened |report_fd|. If a fork() occurs, the PID of the 42// child thread will be different from |report_fd_pid|. 43uptr report_fd_pid = 0; 44 45static DieCallbackType DieCallback; 46void SetDieCallback(DieCallbackType callback) { 47 DieCallback = callback; 48} 49 50DieCallbackType GetDieCallback() { 51 return DieCallback; 52} 53 54void NORETURN Die() { 55 if (DieCallback) { 56 DieCallback(); 57 } 58 internal__exit(1); 59} 60 61static CheckFailedCallbackType CheckFailedCallback; 62void SetCheckFailedCallback(CheckFailedCallbackType callback) { 63 CheckFailedCallback = callback; 64} 65 66void NORETURN CheckFailed(const char *file, int line, const char *cond, 67 u64 v1, u64 v2) { 68 if (CheckFailedCallback) { 69 CheckFailedCallback(file, line, cond, v1, v2); 70 } 71 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond, 72 v1, v2); 73 Die(); 74} 75 76uptr ReadFileToBuffer(const char *file_name, char **buff, 77 uptr *buff_size, uptr max_len) { 78 uptr PageSize = GetPageSizeCached(); 79 uptr kMinFileLen = PageSize; 80 uptr read_len = 0; 81 *buff = 0; 82 *buff_size = 0; 83 // The files we usually open are not seekable, so try different buffer sizes. 84 for (uptr size = kMinFileLen; size <= max_len; size *= 2) { 85 uptr openrv = OpenFile(file_name, /*write*/ false); 86 if (internal_iserror(openrv)) return 0; 87 fd_t fd = openrv; 88 UnmapOrDie(*buff, *buff_size); 89 *buff = (char*)MmapOrDie(size, __FUNCTION__); 90 *buff_size = size; 91 // Read up to one page at a time. 92 read_len = 0; 93 bool reached_eof = false; 94 while (read_len + PageSize <= size) { 95 uptr just_read = internal_read(fd, *buff + read_len, PageSize); 96 if (just_read == 0) { 97 reached_eof = true; 98 break; 99 } 100 read_len += just_read; 101 } 102 internal_close(fd); 103 if (reached_eof) // We've read the whole file. 104 break; 105 } 106 return read_len; 107} 108 109typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); 110 111template<class T> 112static inline bool CompareLess(const T &a, const T &b) { 113 return a < b; 114} 115 116void SortArray(uptr *array, uptr size) { 117 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess); 118} 119 120// We want to map a chunk of address space aligned to 'alignment'. 121// We do it by maping a bit more and then unmaping redundant pieces. 122// We probably can do it with fewer syscalls in some OS-dependent way. 123void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { 124// uptr PageSize = GetPageSizeCached(); 125 CHECK(IsPowerOfTwo(size)); 126 CHECK(IsPowerOfTwo(alignment)); 127 uptr map_size = size + alignment; 128 uptr map_res = (uptr)MmapOrDie(map_size, mem_type); 129 uptr map_end = map_res + map_size; 130 uptr res = map_res; 131 if (res & (alignment - 1)) // Not aligned. 132 res = (map_res + alignment) & ~(alignment - 1); 133 uptr end = res + size; 134 if (res != map_res) 135 UnmapOrDie((void*)map_res, res - map_res); 136 if (end != map_end) 137 UnmapOrDie((void*)end, map_end - end); 138 return (void*)res; 139} 140 141const char *StripPathPrefix(const char *filepath, 142 const char *strip_path_prefix) { 143 if (filepath == 0) return 0; 144 if (strip_path_prefix == 0) return filepath; 145 const char *pos = internal_strstr(filepath, strip_path_prefix); 146 if (pos == 0) return filepath; 147 pos += internal_strlen(strip_path_prefix); 148 if (pos[0] == '.' && pos[1] == '/') 149 pos += 2; 150 return pos; 151} 152 153void PrintSourceLocation(const char *file, int line, int column) { 154 CHECK(file); 155 Printf("%s", StripPathPrefix(file, common_flags()->strip_path_prefix)); 156 if (line > 0) { 157 Printf(":%d", line); 158 if (column > 0) 159 Printf(":%d", column); 160 } 161} 162 163void PrintModuleAndOffset(const char *module, uptr offset) { 164 Printf("(%s+0x%zx)", 165 StripPathPrefix(module, common_flags()->strip_path_prefix), offset); 166} 167 168void ReportErrorSummary(const char *error_message) { 169 InternalScopedBuffer<char> buff(kMaxSummaryLength); 170 internal_snprintf(buff.data(), buff.size(), 171 "SUMMARY: %s: %s", SanitizerToolName, error_message); 172 __sanitizer_report_error_summary(buff.data()); 173} 174 175void ReportErrorSummary(const char *error_type, const char *file, 176 int line, const char *function) { 177 InternalScopedBuffer<char> buff(kMaxSummaryLength); 178 internal_snprintf( 179 buff.data(), buff.size(), "%s %s:%d %s", error_type, 180 file ? StripPathPrefix(file, common_flags()->strip_path_prefix) : "??", 181 line, function ? function : "??"); 182 ReportErrorSummary(buff.data()); 183} 184 185void ReportErrorSummary(const char *error_type, StackTrace *stack) { 186 AddressInfo ai; 187#if !SANITIZER_GO 188 if (stack->size > 0 && Symbolizer::Get()->IsAvailable()) { 189 // Currently, we include the first stack frame into the report summary. 190 // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). 191 uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); 192 Symbolizer::Get()->SymbolizeCode(pc, &ai, 1); 193 } 194#endif 195 ReportErrorSummary(error_type, ai.file, ai.line, ai.function); 196} 197 198LoadedModule::LoadedModule(const char *module_name, uptr base_address) { 199 full_name_ = internal_strdup(module_name); 200 base_address_ = base_address; 201 n_ranges_ = 0; 202} 203 204void LoadedModule::addAddressRange(uptr beg, uptr end) { 205 CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges); 206 ranges_[n_ranges_].beg = beg; 207 ranges_[n_ranges_].end = end; 208 n_ranges_++; 209} 210 211bool LoadedModule::containsAddress(uptr address) const { 212 for (uptr i = 0; i < n_ranges_; i++) { 213 if (ranges_[i].beg <= address && address < ranges_[i].end) 214 return true; 215 } 216 return false; 217} 218 219} // namespace __sanitizer 220 221using namespace __sanitizer; // NOLINT 222 223extern "C" { 224void __sanitizer_set_report_path(const char *path) { 225 if (!path) 226 return; 227 uptr len = internal_strlen(path); 228 if (len > sizeof(report_path_prefix) - 100) { 229 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 230 path[0], path[1], path[2], path[3], 231 path[4], path[5], path[6], path[7]); 232 Die(); 233 } 234 if (report_fd != kStdoutFd && 235 report_fd != kStderrFd && 236 report_fd != kInvalidFd) 237 internal_close(report_fd); 238 report_fd = kInvalidFd; 239 log_to_file = false; 240 if (internal_strcmp(path, "stdout") == 0) { 241 report_fd = kStdoutFd; 242 } else if (internal_strcmp(path, "stderr") == 0) { 243 report_fd = kStderrFd; 244 } else { 245 internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix)); 246 report_path_prefix[len] = '\0'; 247 log_to_file = true; 248 } 249} 250 251void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) { 252 (void)reserved; 253 PrepareForSandboxing(); 254} 255 256void __sanitizer_report_error_summary(const char *error_summary) { 257 Printf("%s\n", error_summary); 258} 259} // extern "C" 260