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_allocator_internal.h"
16 #include "sanitizer_flags.h"
17 #include "sanitizer_libc.h"
18 #include "sanitizer_placement_new.h"
20 namespace __sanitizer {
22 const char *SanitizerToolName = "SanitizerTool";
24 atomic_uint32_t current_verbosity;
26 uptr GetPageSizeCached() {
29 PageSize = GetPageSize();
33 StaticSpinMutex report_file_mu;
34 ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
36 void RawWrite(const char *buffer) {
37 report_file.Write(buffer, internal_strlen(buffer));
40 void ReportFile::ReopenIfNecessary() {
42 if (fd == kStdoutFd || fd == kStderrFd) return;
44 uptr pid = internal_getpid();
45 // If in tracer, use the parent's file.
46 if (pid == stoptheworld_tracer_pid)
47 pid = stoptheworld_tracer_ppid;
48 if (fd != kInvalidFd) {
49 // If the report file is already opened by the current process,
50 // do nothing. Otherwise the report file was opened by the parent
51 // process, close it now.
58 internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
59 uptr openrv = OpenFile(full_path, true);
60 if (internal_iserror(openrv)) {
61 const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
62 internal_write(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
63 internal_write(kStderrFd, full_path, internal_strlen(full_path));
70 void ReportFile::SetReportPath(const char *path) {
73 uptr len = internal_strlen(path);
74 if (len > sizeof(path_prefix) - 100) {
75 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
76 path[0], path[1], path[2], path[3],
77 path[4], path[5], path[6], path[7]);
82 if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
85 if (internal_strcmp(path, "stdout") == 0) {
87 } else if (internal_strcmp(path, "stderr") == 0) {
90 internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
94 // PID of the tracer task in StopTheWorld. It shares the address space with the
95 // main process, but has a different PID and thus requires special handling.
96 uptr stoptheworld_tracer_pid = 0;
97 // Cached pid of parent process - if the parent process dies, we want to keep
98 // writing to the same log file.
99 uptr stoptheworld_tracer_ppid = 0;
101 static DieCallbackType InternalDieCallback, UserDieCallback;
102 void SetDieCallback(DieCallbackType callback) {
103 InternalDieCallback = callback;
105 void SetUserDieCallback(DieCallbackType callback) {
106 UserDieCallback = callback;
109 DieCallbackType GetDieCallback() {
110 return InternalDieCallback;
113 void NORETURN Die() {
116 if (InternalDieCallback)
117 InternalDieCallback();
121 static CheckFailedCallbackType CheckFailedCallback;
122 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
123 CheckFailedCallback = callback;
126 void NORETURN CheckFailed(const char *file, int line, const char *cond,
128 if (CheckFailedCallback) {
129 CheckFailedCallback(file, line, cond, v1, v2);
131 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
136 uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
137 uptr max_len, int *errno_p) {
138 uptr PageSize = GetPageSizeCached();
139 uptr kMinFileLen = PageSize;
143 // The files we usually open are not seekable, so try different buffer sizes.
144 for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
145 uptr openrv = OpenFile(file_name, /*write*/ false);
146 if (internal_iserror(openrv, errno_p)) return 0;
148 UnmapOrDie(*buff, *buff_size);
149 *buff = (char*)MmapOrDie(size, __func__);
151 // Read up to one page at a time.
153 bool reached_eof = false;
154 while (read_len + PageSize <= size) {
155 uptr just_read = internal_read(fd, *buff + read_len, PageSize);
156 if (internal_iserror(just_read, errno_p)) {
157 UnmapOrDie(*buff, *buff_size);
160 if (just_read == 0) {
164 read_len += just_read;
167 if (reached_eof) // We've read the whole file.
173 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
176 static inline bool CompareLess(const T &a, const T &b) {
180 void SortArray(uptr *array, uptr size) {
181 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
184 // We want to map a chunk of address space aligned to 'alignment'.
185 // We do it by maping a bit more and then unmaping redundant pieces.
186 // We probably can do it with fewer syscalls in some OS-dependent way.
187 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
188 // uptr PageSize = GetPageSizeCached();
189 CHECK(IsPowerOfTwo(size));
190 CHECK(IsPowerOfTwo(alignment));
191 uptr map_size = size + alignment;
192 uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
193 uptr map_end = map_res + map_size;
195 if (res & (alignment - 1)) // Not aligned.
196 res = (map_res + alignment) & ~(alignment - 1);
197 uptr end = res + size;
199 UnmapOrDie((void*)map_res, res - map_res);
201 UnmapOrDie((void*)end, map_end - end);
205 const char *StripPathPrefix(const char *filepath,
206 const char *strip_path_prefix) {
207 if (filepath == 0) return 0;
208 if (strip_path_prefix == 0) return filepath;
209 const char *pos = internal_strstr(filepath, strip_path_prefix);
210 if (pos == 0) return filepath;
211 pos += internal_strlen(strip_path_prefix);
212 if (pos[0] == '.' && pos[1] == '/')
217 const char *StripModuleName(const char *module) {
220 if (const char *slash_pos = internal_strrchr(module, '/'))
221 return slash_pos + 1;
225 void ReportErrorSummary(const char *error_message) {
226 if (!common_flags()->print_summary)
228 InternalScopedString buff(kMaxSummaryLength);
229 buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
230 __sanitizer_report_error_summary(buff.data());
233 void ReportErrorSummary(const char *error_type, const char *file,
234 int line, const char *function) {
235 if (!common_flags()->print_summary)
237 InternalScopedString buff(kMaxSummaryLength);
238 buff.append("%s %s:%d %s", error_type,
239 file ? StripPathPrefix(file, common_flags()->strip_path_prefix)
241 line, function ? function : "??");
242 ReportErrorSummary(buff.data());
245 LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
246 full_name_ = internal_strdup(module_name);
247 base_address_ = base_address;
251 void LoadedModule::clear() {
252 InternalFree(full_name_);
253 while (!ranges_.empty()) {
254 AddressRange *r = ranges_.front();
260 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
261 void *mem = InternalAlloc(sizeof(AddressRange));
262 AddressRange *r = new(mem) AddressRange(beg, end, executable);
263 ranges_.push_back(r);
266 bool LoadedModule::containsAddress(uptr address) const {
267 for (Iterator iter = ranges(); iter.hasNext();) {
268 const AddressRange *r = iter.next();
269 if (r->beg <= address && address < r->end)
275 static atomic_uintptr_t g_total_mmaped;
277 void IncreaseTotalMmap(uptr size) {
278 if (!common_flags()->mmap_limit_mb) return;
280 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
281 // Since for now mmap_limit_mb is not a user-facing flag, just kill
282 // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
283 RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
286 void DecreaseTotalMmap(uptr size) {
287 if (!common_flags()->mmap_limit_mb) return;
288 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
291 bool TemplateMatch(const char *templ, const char *str) {
292 if (str == 0 || str[0] == 0)
295 if (templ && templ[0] == '^') {
299 bool asterisk = false;
300 while (templ && templ[0]) {
301 if (templ[0] == '*') {
308 return str[0] == 0 || asterisk;
311 char *tpos = (char*)internal_strchr(templ, '*');
312 char *tpos1 = (char*)internal_strchr(templ, '$');
313 if (tpos == 0 || (tpos1 && tpos1 < tpos))
317 const char *str0 = str;
318 const char *spos = internal_strstr(str, templ);
319 str = spos + internal_strlen(templ);
322 tpos[0] = tpos == tpos1 ? '$' : '*';
325 if (start && spos != str0)
333 } // namespace __sanitizer
335 using namespace __sanitizer; // NOLINT
338 void __sanitizer_set_report_path(const char *path) {
339 report_file.SetReportPath(path);
342 void __sanitizer_report_error_summary(const char *error_summary) {
343 Printf("%s\n", error_summary);
346 SANITIZER_INTERFACE_ATTRIBUTE
347 void __sanitizer_set_death_callback(void (*callback)(void)) {
348 SetUserDieCallback(callback);