sanitizer_common.cc revision ae51c273d55fa172908cf940c238eacec0f73223
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(InternalScopedString *buffer, const char *file, 154 int line, int column) { 155 CHECK(file); 156 buffer->append("%s", 157 StripPathPrefix(file, common_flags()->strip_path_prefix)); 158 if (line > 0) { 159 buffer->append(":%d", line); 160 if (column > 0) 161 buffer->append(":%d", column); 162 } 163} 164 165void PrintModuleAndOffset(InternalScopedString *buffer, const char *module, 166 uptr offset) { 167 buffer->append("(%s+0x%zx)", 168 StripPathPrefix(module, common_flags()->strip_path_prefix), 169 offset); 170} 171 172void ReportErrorSummary(const char *error_message) { 173 if (!common_flags()->print_summary) 174 return; 175 InternalScopedBuffer<char> buff(kMaxSummaryLength); 176 internal_snprintf(buff.data(), buff.size(), 177 "SUMMARY: %s: %s", SanitizerToolName, error_message); 178 __sanitizer_report_error_summary(buff.data()); 179} 180 181void ReportErrorSummary(const char *error_type, const char *file, 182 int line, const char *function) { 183 if (!common_flags()->print_summary) 184 return; 185 InternalScopedBuffer<char> buff(kMaxSummaryLength); 186 internal_snprintf( 187 buff.data(), buff.size(), "%s %s:%d %s", error_type, 188 file ? StripPathPrefix(file, common_flags()->strip_path_prefix) : "??", 189 line, function ? function : "??"); 190 ReportErrorSummary(buff.data()); 191} 192 193void ReportErrorSummary(const char *error_type, StackTrace *stack) { 194 if (!common_flags()->print_summary) 195 return; 196 AddressInfo ai; 197#if !SANITIZER_GO 198 if (stack->size > 0 && Symbolizer::Get()->IsAvailable()) { 199 // Currently, we include the first stack frame into the report summary. 200 // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). 201 uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); 202 Symbolizer::Get()->SymbolizeCode(pc, &ai, 1); 203 } 204#endif 205 ReportErrorSummary(error_type, ai.file, ai.line, ai.function); 206} 207 208LoadedModule::LoadedModule(const char *module_name, uptr base_address) { 209 full_name_ = internal_strdup(module_name); 210 base_address_ = base_address; 211 n_ranges_ = 0; 212} 213 214void LoadedModule::addAddressRange(uptr beg, uptr end) { 215 CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges); 216 ranges_[n_ranges_].beg = beg; 217 ranges_[n_ranges_].end = end; 218 n_ranges_++; 219} 220 221bool LoadedModule::containsAddress(uptr address) const { 222 for (uptr i = 0; i < n_ranges_; i++) { 223 if (ranges_[i].beg <= address && address < ranges_[i].end) 224 return true; 225 } 226 return false; 227} 228 229} // namespace __sanitizer 230 231using namespace __sanitizer; // NOLINT 232 233extern "C" { 234void __sanitizer_set_report_path(const char *path) { 235 if (!path) 236 return; 237 uptr len = internal_strlen(path); 238 if (len > sizeof(report_path_prefix) - 100) { 239 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 240 path[0], path[1], path[2], path[3], 241 path[4], path[5], path[6], path[7]); 242 Die(); 243 } 244 if (report_fd != kStdoutFd && 245 report_fd != kStderrFd && 246 report_fd != kInvalidFd) 247 internal_close(report_fd); 248 report_fd = kInvalidFd; 249 log_to_file = false; 250 if (internal_strcmp(path, "stdout") == 0) { 251 report_fd = kStdoutFd; 252 } else if (internal_strcmp(path, "stderr") == 0) { 253 report_fd = kStderrFd; 254 } else { 255 internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix)); 256 report_path_prefix[len] = '\0'; 257 log_to_file = true; 258 } 259} 260 261void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) { 262 (void)reserved; 263 PrepareForSandboxing(); 264} 265 266void __sanitizer_report_error_summary(const char *error_summary) { 267 Printf("%s\n", error_summary); 268} 269} // extern "C" 270