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 20 namespace __sanitizer { 21 22 const char *SanitizerToolName = "SanitizerTool"; 23 24 uptr 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>". 35 fd_t report_fd = kStderrFd; 36 37 // Set via __sanitizer_set_report_path. 38 bool log_to_file = false; 39 char 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|. 43 uptr report_fd_pid = 0; 44 45 // PID of the tracer task in StopTheWorld. It shares the address space with the 46 // main process, but has a different PID and thus requires special handling. 47 uptr stoptheworld_tracer_pid = 0; 48 // Cached pid of parent process - if the parent process dies, we want to keep 49 // writing to the same log file. 50 uptr stoptheworld_tracer_ppid = 0; 51 52 static DieCallbackType DieCallback; 53 void SetDieCallback(DieCallbackType callback) { 54 DieCallback = callback; 55 } 56 57 DieCallbackType GetDieCallback() { 58 return DieCallback; 59 } 60 61 void NORETURN Die() { 62 if (DieCallback) { 63 DieCallback(); 64 } 65 internal__exit(1); 66 } 67 68 static CheckFailedCallbackType CheckFailedCallback; 69 void SetCheckFailedCallback(CheckFailedCallbackType callback) { 70 CheckFailedCallback = callback; 71 } 72 73 void NORETURN CheckFailed(const char *file, int line, const char *cond, 74 u64 v1, u64 v2) { 75 if (CheckFailedCallback) { 76 CheckFailedCallback(file, line, cond, v1, v2); 77 } 78 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond, 79 v1, v2); 80 Die(); 81 } 82 83 uptr ReadFileToBuffer(const char *file_name, char **buff, 84 uptr *buff_size, uptr max_len) { 85 uptr PageSize = GetPageSizeCached(); 86 uptr kMinFileLen = PageSize; 87 uptr read_len = 0; 88 *buff = 0; 89 *buff_size = 0; 90 // The files we usually open are not seekable, so try different buffer sizes. 91 for (uptr size = kMinFileLen; size <= max_len; size *= 2) { 92 uptr openrv = OpenFile(file_name, /*write*/ false); 93 if (internal_iserror(openrv)) return 0; 94 fd_t fd = openrv; 95 UnmapOrDie(*buff, *buff_size); 96 *buff = (char*)MmapOrDie(size, __func__); 97 *buff_size = size; 98 // Read up to one page at a time. 99 read_len = 0; 100 bool reached_eof = false; 101 while (read_len + PageSize <= size) { 102 uptr just_read = internal_read(fd, *buff + read_len, PageSize); 103 if (just_read == 0) { 104 reached_eof = true; 105 break; 106 } 107 read_len += just_read; 108 } 109 internal_close(fd); 110 if (reached_eof) // We've read the whole file. 111 break; 112 } 113 return read_len; 114 } 115 116 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); 117 118 template<class T> 119 static inline bool CompareLess(const T &a, const T &b) { 120 return a < b; 121 } 122 123 void SortArray(uptr *array, uptr size) { 124 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess); 125 } 126 127 // We want to map a chunk of address space aligned to 'alignment'. 128 // We do it by maping a bit more and then unmaping redundant pieces. 129 // We probably can do it with fewer syscalls in some OS-dependent way. 130 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { 131 // uptr PageSize = GetPageSizeCached(); 132 CHECK(IsPowerOfTwo(size)); 133 CHECK(IsPowerOfTwo(alignment)); 134 uptr map_size = size + alignment; 135 uptr map_res = (uptr)MmapOrDie(map_size, mem_type); 136 uptr map_end = map_res + map_size; 137 uptr res = map_res; 138 if (res & (alignment - 1)) // Not aligned. 139 res = (map_res + alignment) & ~(alignment - 1); 140 uptr end = res + size; 141 if (res != map_res) 142 UnmapOrDie((void*)map_res, res - map_res); 143 if (end != map_end) 144 UnmapOrDie((void*)end, map_end - end); 145 return (void*)res; 146 } 147 148 const char *StripPathPrefix(const char *filepath, 149 const char *strip_path_prefix) { 150 if (filepath == 0) return 0; 151 if (strip_path_prefix == 0) return filepath; 152 const char *pos = internal_strstr(filepath, strip_path_prefix); 153 if (pos == 0) return filepath; 154 pos += internal_strlen(strip_path_prefix); 155 if (pos[0] == '.' && pos[1] == '/') 156 pos += 2; 157 return pos; 158 } 159 160 void PrintSourceLocation(InternalScopedString *buffer, const char *file, 161 int line, int column) { 162 CHECK(file); 163 buffer->append("%s", 164 StripPathPrefix(file, common_flags()->strip_path_prefix)); 165 if (line > 0) { 166 buffer->append(":%d", line); 167 if (column > 0) 168 buffer->append(":%d", column); 169 } 170 } 171 172 void PrintModuleAndOffset(InternalScopedString *buffer, const char *module, 173 uptr offset) { 174 buffer->append("(%s+0x%zx)", 175 StripPathPrefix(module, common_flags()->strip_path_prefix), 176 offset); 177 } 178 179 void ReportErrorSummary(const char *error_message) { 180 if (!common_flags()->print_summary) 181 return; 182 InternalScopedBuffer<char> buff(kMaxSummaryLength); 183 internal_snprintf(buff.data(), buff.size(), 184 "SUMMARY: %s: %s", SanitizerToolName, error_message); 185 __sanitizer_report_error_summary(buff.data()); 186 } 187 188 void ReportErrorSummary(const char *error_type, const char *file, 189 int line, const char *function) { 190 if (!common_flags()->print_summary) 191 return; 192 InternalScopedBuffer<char> buff(kMaxSummaryLength); 193 internal_snprintf( 194 buff.data(), buff.size(), "%s %s:%d %s", error_type, 195 file ? StripPathPrefix(file, common_flags()->strip_path_prefix) : "??", 196 line, function ? function : "??"); 197 ReportErrorSummary(buff.data()); 198 } 199 200 void ReportErrorSummary(const char *error_type, StackTrace *stack) { 201 if (!common_flags()->print_summary) 202 return; 203 AddressInfo ai; 204 #if !SANITIZER_GO 205 if (stack->size > 0 && Symbolizer::Get()->CanReturnFileLineInfo()) { 206 // Currently, we include the first stack frame into the report summary. 207 // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). 208 uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); 209 Symbolizer::Get()->SymbolizePC(pc, &ai, 1); 210 } 211 #endif 212 ReportErrorSummary(error_type, ai.file, ai.line, ai.function); 213 } 214 215 LoadedModule::LoadedModule(const char *module_name, uptr base_address) { 216 full_name_ = internal_strdup(module_name); 217 base_address_ = base_address; 218 n_ranges_ = 0; 219 } 220 221 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) { 222 CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges); 223 ranges_[n_ranges_].beg = beg; 224 ranges_[n_ranges_].end = end; 225 exec_[n_ranges_] = executable; 226 n_ranges_++; 227 } 228 229 bool LoadedModule::containsAddress(uptr address) const { 230 for (uptr i = 0; i < n_ranges_; i++) { 231 if (ranges_[i].beg <= address && address < ranges_[i].end) 232 return true; 233 } 234 return false; 235 } 236 237 char *StripModuleName(const char *module) { 238 if (module == 0) 239 return 0; 240 const char *short_module_name = internal_strrchr(module, '/'); 241 if (short_module_name) 242 short_module_name += 1; 243 else 244 short_module_name = module; 245 return internal_strdup(short_module_name); 246 } 247 248 static atomic_uintptr_t g_total_mmaped; 249 250 void IncreaseTotalMmap(uptr size) { 251 if (!common_flags()->mmap_limit_mb) return; 252 uptr total_mmaped = 253 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; 254 if ((total_mmaped >> 20) > common_flags()->mmap_limit_mb) { 255 // Since for now mmap_limit_mb is not a user-facing flag, just CHECK. 256 uptr mmap_limit_mb = common_flags()->mmap_limit_mb; 257 common_flags()->mmap_limit_mb = 0; // Allow mmap in CHECK. 258 RAW_CHECK(total_mmaped >> 20 < mmap_limit_mb); 259 } 260 } 261 262 void DecreaseTotalMmap(uptr size) { 263 if (!common_flags()->mmap_limit_mb) return; 264 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); 265 } 266 267 } // namespace __sanitizer 268 269 using namespace __sanitizer; // NOLINT 270 271 extern "C" { 272 void __sanitizer_set_report_path(const char *path) { 273 if (!path) 274 return; 275 uptr len = internal_strlen(path); 276 if (len > sizeof(report_path_prefix) - 100) { 277 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 278 path[0], path[1], path[2], path[3], 279 path[4], path[5], path[6], path[7]); 280 Die(); 281 } 282 if (report_fd != kStdoutFd && 283 report_fd != kStderrFd && 284 report_fd != kInvalidFd) 285 internal_close(report_fd); 286 report_fd = kInvalidFd; 287 log_to_file = false; 288 if (internal_strcmp(path, "stdout") == 0) { 289 report_fd = kStdoutFd; 290 } else if (internal_strcmp(path, "stderr") == 0) { 291 report_fd = kStderrFd; 292 } else { 293 internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix)); 294 report_path_prefix[len] = '\0'; 295 log_to_file = true; 296 } 297 } 298 299 void __sanitizer_report_error_summary(const char *error_summary) { 300 Printf("%s\n", error_summary); 301 } 302 } // extern "C" 303