1 //===-- sanitizer_common.cc -----------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is shared between AddressSanitizer and ThreadSanitizer
11 // run-time libraries.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common.h"
15 #include "sanitizer_flags.h"
16 #include "sanitizer_libc.h"
18 namespace __sanitizer {
20 const char *SanitizerToolName = "SanitizerTool";
22 uptr GetPageSizeCached() {
25 PageSize = GetPageSize();
29 StaticSpinMutex report_file_mu;
30 ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
32 void RawWrite(const char *buffer) {
33 report_file.Write(buffer, internal_strlen(buffer));
36 void ReportFile::ReopenIfNecessary() {
38 if (fd == kStdoutFd || fd == kStderrFd) return;
40 uptr pid = internal_getpid();
41 // If in tracer, use the parent's file.
42 if (pid == stoptheworld_tracer_pid)
43 pid = stoptheworld_tracer_ppid;
44 if (fd != kInvalidFd) {
45 // If the report file is already opened by the current process,
46 // do nothing. Otherwise the report file was opened by the parent
47 // process, close it now.
54 internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
55 uptr openrv = OpenFile(full_path, true);
56 if (internal_iserror(openrv)) {
57 const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
58 internal_write(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
59 internal_write(kStderrFd, full_path, internal_strlen(full_path));
66 void ReportFile::SetReportPath(const char *path) {
69 uptr len = internal_strlen(path);
70 if (len > sizeof(path_prefix) - 100) {
71 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
72 path[0], path[1], path[2], path[3],
73 path[4], path[5], path[6], path[7]);
78 if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
81 if (internal_strcmp(path, "stdout") == 0) {
83 } else if (internal_strcmp(path, "stderr") == 0) {
86 internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
90 // PID of the tracer task in StopTheWorld. It shares the address space with the
91 // main process, but has a different PID and thus requires special handling.
92 uptr stoptheworld_tracer_pid = 0;
93 // Cached pid of parent process - if the parent process dies, we want to keep
94 // writing to the same log file.
95 uptr stoptheworld_tracer_ppid = 0;
97 static DieCallbackType DieCallback;
98 void SetDieCallback(DieCallbackType callback) {
99 DieCallback = callback;
102 DieCallbackType GetDieCallback() {
106 void NORETURN Die() {
113 static CheckFailedCallbackType CheckFailedCallback;
114 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
115 CheckFailedCallback = callback;
118 void NORETURN CheckFailed(const char *file, int line, const char *cond,
120 if (CheckFailedCallback) {
121 CheckFailedCallback(file, line, cond, v1, v2);
123 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
128 uptr ReadFileToBuffer(const char *file_name, char **buff,
129 uptr *buff_size, uptr max_len) {
130 uptr PageSize = GetPageSizeCached();
131 uptr kMinFileLen = PageSize;
135 // The files we usually open are not seekable, so try different buffer sizes.
136 for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
137 uptr openrv = OpenFile(file_name, /*write*/ false);
138 if (internal_iserror(openrv)) return 0;
140 UnmapOrDie(*buff, *buff_size);
141 *buff = (char*)MmapOrDie(size, __func__);
143 // Read up to one page at a time.
145 bool reached_eof = false;
146 while (read_len + PageSize <= size) {
147 uptr just_read = internal_read(fd, *buff + read_len, PageSize);
148 if (just_read == 0) {
152 read_len += just_read;
155 if (reached_eof) // We've read the whole file.
161 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
164 static inline bool CompareLess(const T &a, const T &b) {
168 void SortArray(uptr *array, uptr size) {
169 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
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;
183 if (res & (alignment - 1)) // Not aligned.
184 res = (map_res + alignment) & ~(alignment - 1);
185 uptr end = res + size;
187 UnmapOrDie((void*)map_res, res - map_res);
189 UnmapOrDie((void*)end, map_end - end);
193 const char *StripPathPrefix(const char *filepath,
194 const char *strip_path_prefix) {
195 if (filepath == 0) return 0;
196 if (strip_path_prefix == 0) return filepath;
197 const char *pos = internal_strstr(filepath, strip_path_prefix);
198 if (pos == 0) return filepath;
199 pos += internal_strlen(strip_path_prefix);
200 if (pos[0] == '.' && pos[1] == '/')
205 const char *StripModuleName(const char *module) {
208 if (const char *slash_pos = internal_strrchr(module, '/'))
209 return slash_pos + 1;
213 void ReportErrorSummary(const char *error_message) {
214 if (!common_flags()->print_summary)
216 InternalScopedString buff(kMaxSummaryLength);
217 buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
218 __sanitizer_report_error_summary(buff.data());
221 void ReportErrorSummary(const char *error_type, const char *file,
222 int line, const char *function) {
223 if (!common_flags()->print_summary)
225 InternalScopedString buff(kMaxSummaryLength);
226 buff.append("%s %s:%d %s", error_type,
227 file ? StripPathPrefix(file, common_flags()->strip_path_prefix)
229 line, function ? function : "??");
230 ReportErrorSummary(buff.data());
233 LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
234 full_name_ = internal_strdup(module_name);
235 base_address_ = base_address;
239 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
240 CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
241 ranges_[n_ranges_].beg = beg;
242 ranges_[n_ranges_].end = end;
243 exec_[n_ranges_] = executable;
247 bool LoadedModule::containsAddress(uptr address) const {
248 for (uptr i = 0; i < n_ranges_; i++) {
249 if (ranges_[i].beg <= address && address < ranges_[i].end)
255 static atomic_uintptr_t g_total_mmaped;
257 void IncreaseTotalMmap(uptr size) {
258 if (!common_flags()->mmap_limit_mb) return;
260 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
261 // Since for now mmap_limit_mb is not a user-facing flag, just kill
262 // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
263 RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
266 void DecreaseTotalMmap(uptr size) {
267 if (!common_flags()->mmap_limit_mb) return;
268 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
271 } // namespace __sanitizer
273 using namespace __sanitizer; // NOLINT
276 void __sanitizer_set_report_path(const char *path) {
277 report_file.SetReportPath(path);
280 void __sanitizer_report_error_summary(const char *error_summary) {
281 Printf("%s\n", error_summary);