blob: 14871a1d3164379b33c4e31862733876cb89d42c [file] [log] [blame]
Alexey Samsonov230c3be2012-06-06 09:26:25 +00001//===-- 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"
Stephen Hines86277eb2015-03-23 12:06:32 -070015#include "sanitizer_allocator_internal.h"
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +000016#include "sanitizer_flags.h"
Alexey Samsonov230c3be2012-06-06 09:26:25 +000017#include "sanitizer_libc.h"
Stephen Hines86277eb2015-03-23 12:06:32 -070018#include "sanitizer_placement_new.h"
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -070019#include "sanitizer_stacktrace_printer.h"
20#include "sanitizer_symbolizer.h"
Alexey Samsonov4c496662012-06-15 07:00:31 +000021
Alexey Samsonov230c3be2012-06-06 09:26:25 +000022namespace __sanitizer {
23
Kostya Serebryany859778a2013-01-31 14:11:21 +000024const char *SanitizerToolName = "SanitizerTool";
25
Stephen Hines86277eb2015-03-23 12:06:32 -070026atomic_uint32_t current_verbosity;
27
Kostya Serebryanyf67ec2b2012-11-23 15:38:49 +000028uptr GetPageSizeCached() {
29 static uptr PageSize;
30 if (!PageSize)
31 PageSize = GetPageSize();
32 return PageSize;
33}
34
Stephen Hines86277eb2015-03-23 12:06:32 -070035StaticSpinMutex report_file_mu;
36ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
Alexander Potapenkodedba5d2013-01-18 16:44:27 +000037
Stephen Hines86277eb2015-03-23 12:06:32 -070038void RawWrite(const char *buffer) {
39 report_file.Write(buffer, internal_strlen(buffer));
40}
Reid Kleckner923bac72013-09-05 03:19:57 +000041
Stephen Hines86277eb2015-03-23 12:06:32 -070042void ReportFile::ReopenIfNecessary() {
43 mu->CheckLocked();
44 if (fd == kStdoutFd || fd == kStderrFd) return;
Reid Kleckner923bac72013-09-05 03:19:57 +000045
Stephen Hines86277eb2015-03-23 12:06:32 -070046 uptr pid = internal_getpid();
47 // If in tracer, use the parent's file.
48 if (pid == stoptheworld_tracer_pid)
49 pid = stoptheworld_tracer_ppid;
50 if (fd != kInvalidFd) {
51 // If the report file is already opened by the current process,
52 // do nothing. Otherwise the report file was opened by the parent
53 // process, close it now.
54 if (fd_pid == pid)
55 return;
56 else
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -070057 CloseFile(fd);
Stephen Hines86277eb2015-03-23 12:06:32 -070058 }
59
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -070060 const char *exe_name = GetBinaryBasename();
61 if (common_flags()->log_exe_name && exe_name) {
62 internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,
63 exe_name, pid);
64 } else {
65 internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
66 }
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -070067 fd = OpenFile(full_path, WrOnly);
68 if (fd == kInvalidFd) {
Stephen Hines86277eb2015-03-23 12:06:32 -070069 const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -070070 WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
71 WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
Stephen Hines86277eb2015-03-23 12:06:32 -070072 Die();
73 }
Stephen Hines86277eb2015-03-23 12:06:32 -070074 fd_pid = pid;
75}
76
77void ReportFile::SetReportPath(const char *path) {
78 if (!path)
79 return;
80 uptr len = internal_strlen(path);
81 if (len > sizeof(path_prefix) - 100) {
82 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
83 path[0], path[1], path[2], path[3],
84 path[4], path[5], path[6], path[7]);
85 Die();
86 }
87
88 SpinMutexLock l(mu);
89 if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -070090 CloseFile(fd);
Stephen Hines86277eb2015-03-23 12:06:32 -070091 fd = kInvalidFd;
92 if (internal_strcmp(path, "stdout") == 0) {
93 fd = kStdoutFd;
94 } else if (internal_strcmp(path, "stderr") == 0) {
95 fd = kStderrFd;
96 } else {
97 internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
98 }
99}
Kostya Serebryany81dfbb72012-09-14 04:35:14 +0000100
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700101// PID of the tracer task in StopTheWorld. It shares the address space with the
102// main process, but has a different PID and thus requires special handling.
103uptr stoptheworld_tracer_pid = 0;
104// Cached pid of parent process - if the parent process dies, we want to keep
105// writing to the same log file.
106uptr stoptheworld_tracer_ppid = 0;
107
Stephen Hines86277eb2015-03-23 12:06:32 -0700108static DieCallbackType InternalDieCallback, UserDieCallback;
Sergey Matveev90629fb2013-08-26 13:20:31 +0000109void SetDieCallback(DieCallbackType callback) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700110 InternalDieCallback = callback;
111}
112void SetUserDieCallback(DieCallbackType callback) {
113 UserDieCallback = callback;
Alexey Samsonov591616d2012-09-11 09:44:48 +0000114}
115
Sergey Matveev90629fb2013-08-26 13:20:31 +0000116DieCallbackType GetDieCallback() {
Stephen Hines86277eb2015-03-23 12:06:32 -0700117 return InternalDieCallback;
Sergey Matveev90629fb2013-08-26 13:20:31 +0000118}
119
Alexey Samsonov591616d2012-09-11 09:44:48 +0000120void NORETURN Die() {
Stephen Hines86277eb2015-03-23 12:06:32 -0700121 if (UserDieCallback)
122 UserDieCallback();
123 if (InternalDieCallback)
124 InternalDieCallback();
Alexey Samsonovf8822472013-02-20 13:54:32 +0000125 internal__exit(1);
Alexey Samsonov591616d2012-09-11 09:44:48 +0000126}
127
128static CheckFailedCallbackType CheckFailedCallback;
129void SetCheckFailedCallback(CheckFailedCallbackType callback) {
130 CheckFailedCallback = callback;
131}
132
133void NORETURN CheckFailed(const char *file, int line, const char *cond,
134 u64 v1, u64 v2) {
135 if (CheckFailedCallback) {
136 CheckFailedCallback(file, line, cond, v1, v2);
137 }
Dmitry Vyukove3c35c72013-01-11 15:07:49 +0000138 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
139 v1, v2);
Alexey Samsonov591616d2012-09-11 09:44:48 +0000140 Die();
141}
142
Stephen Hines86277eb2015-03-23 12:06:32 -0700143uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700144 uptr max_len, error_t *errno_p) {
Kostya Serebryanyf67ec2b2012-11-23 15:38:49 +0000145 uptr PageSize = GetPageSizeCached();
146 uptr kMinFileLen = PageSize;
Alexey Samsonovcffe2f52012-06-07 05:38:26 +0000147 uptr read_len = 0;
148 *buff = 0;
149 *buff_size = 0;
150 // The files we usually open are not seekable, so try different buffer sizes.
151 for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700152 fd_t fd = OpenFile(file_name, RdOnly, errno_p);
153 if (fd == kInvalidFd) return 0;
Alexey Samsonovcffe2f52012-06-07 05:38:26 +0000154 UnmapOrDie(*buff, *buff_size);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700155 *buff = (char*)MmapOrDie(size, __func__);
Alexey Samsonovcffe2f52012-06-07 05:38:26 +0000156 *buff_size = size;
157 // Read up to one page at a time.
158 read_len = 0;
159 bool reached_eof = false;
Kostya Serebryanyf67ec2b2012-11-23 15:38:49 +0000160 while (read_len + PageSize <= size) {
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700161 uptr just_read;
162 if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700163 UnmapOrDie(*buff, *buff_size);
164 return 0;
165 }
Alexey Samsonovcffe2f52012-06-07 05:38:26 +0000166 if (just_read == 0) {
167 reached_eof = true;
168 break;
169 }
170 read_len += just_read;
171 }
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700172 CloseFile(fd);
Alexey Samsonovcffe2f52012-06-07 05:38:26 +0000173 if (reached_eof) // We've read the whole file.
174 break;
175 }
176 return read_len;
177}
178
Sergey Matveev15bb32b2013-05-13 11:58:48 +0000179typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
180
181template<class T>
182static inline bool CompareLess(const T &a, const T &b) {
183 return a < b;
184}
185
Alexey Samsonov4c496662012-06-15 07:00:31 +0000186void SortArray(uptr *array, uptr size) {
Sergey Matveev15bb32b2013-05-13 11:58:48 +0000187 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
Alexey Samsonov4c496662012-06-15 07:00:31 +0000188}
189
Kostya Serebryanycc752592012-12-06 06:10:31 +0000190// We want to map a chunk of address space aligned to 'alignment'.
191// We do it by maping a bit more and then unmaping redundant pieces.
192// We probably can do it with fewer syscalls in some OS-dependent way.
193void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
Bill Wendling2dae63a2012-12-06 07:43:17 +0000194// uptr PageSize = GetPageSizeCached();
Kostya Serebryanycc752592012-12-06 06:10:31 +0000195 CHECK(IsPowerOfTwo(size));
196 CHECK(IsPowerOfTwo(alignment));
197 uptr map_size = size + alignment;
198 uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
199 uptr map_end = map_res + map_size;
200 uptr res = map_res;
201 if (res & (alignment - 1)) // Not aligned.
Dmitry Vyukov3617ad72012-12-06 15:42:54 +0000202 res = (map_res + alignment) & ~(alignment - 1);
Kostya Serebryanycc752592012-12-06 06:10:31 +0000203 uptr end = res + size;
204 if (res != map_res)
205 UnmapOrDie((void*)map_res, res - map_res);
206 if (end != map_end)
207 UnmapOrDie((void*)end, map_end - end);
208 return (void*)res;
209}
210
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +0000211const char *StripPathPrefix(const char *filepath,
212 const char *strip_path_prefix) {
213 if (filepath == 0) return 0;
214 if (strip_path_prefix == 0) return filepath;
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700215 const char *res = filepath;
216 if (const char *pos = internal_strstr(filepath, strip_path_prefix))
217 res = pos + internal_strlen(strip_path_prefix);
218 if (res[0] == '.' && res[1] == '/')
219 res += 2;
220 return res;
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +0000221}
222
Stephen Hines6d186232014-11-26 17:56:19 -0800223const char *StripModuleName(const char *module) {
224 if (module == 0)
225 return 0;
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700226 if (SANITIZER_WINDOWS) {
227 // On Windows, both slash and backslash are possible.
228 // Pick the one that goes last.
229 if (const char *bslash_pos = internal_strrchr(module, '\\'))
230 return StripModuleName(bslash_pos + 1);
231 }
232 if (const char *slash_pos = internal_strrchr(module, '/')) {
Stephen Hines6d186232014-11-26 17:56:19 -0800233 return slash_pos + 1;
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700234 }
Stephen Hines6d186232014-11-26 17:56:19 -0800235 return module;
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +0000236}
237
Alexey Samsonov2fb08722013-11-01 17:02:14 +0000238void ReportErrorSummary(const char *error_message) {
Alexey Samsonov694d8562013-11-14 08:56:59 +0000239 if (!common_flags()->print_summary)
240 return;
Stephen Hines86277eb2015-03-23 12:06:32 -0700241 InternalScopedString buff(kMaxSummaryLength);
242 buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
Alexey Samsonov2fb08722013-11-01 17:02:14 +0000243 __sanitizer_report_error_summary(buff.data());
244}
245
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700246#ifndef SANITIZER_GO
247void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
Alexey Samsonov694d8562013-11-14 08:56:59 +0000248 if (!common_flags()->print_summary)
249 return;
Stephen Hines86277eb2015-03-23 12:06:32 -0700250 InternalScopedString buff(kMaxSummaryLength);
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700251 buff.append("%s ", error_type);
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700252 RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
253 common_flags()->strip_path_prefix);
Alexey Samsonov2fb08722013-11-01 17:02:14 +0000254 ReportErrorSummary(buff.data());
255}
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700256#endif
Alexey Samsonov2fb08722013-11-01 17:02:14 +0000257
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700258void LoadedModule::set(const char *module_name, uptr base_address) {
259 clear();
Alexey Samsonov7847d772013-09-10 14:36:16 +0000260 full_name_ = internal_strdup(module_name);
261 base_address_ = base_address;
Stephen Hines86277eb2015-03-23 12:06:32 -0700262}
263
264void LoadedModule::clear() {
265 InternalFree(full_name_);
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700266 full_name_ = nullptr;
Stephen Hines86277eb2015-03-23 12:06:32 -0700267 while (!ranges_.empty()) {
268 AddressRange *r = ranges_.front();
269 ranges_.pop_front();
270 InternalFree(r);
271 }
Alexey Samsonov7847d772013-09-10 14:36:16 +0000272}
273
Stephen Hines6a211c52014-07-21 00:49:56 -0700274void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700275 void *mem = InternalAlloc(sizeof(AddressRange));
276 AddressRange *r = new(mem) AddressRange(beg, end, executable);
277 ranges_.push_back(r);
Alexey Samsonov7847d772013-09-10 14:36:16 +0000278}
279
280bool LoadedModule::containsAddress(uptr address) const {
Stephen Hines86277eb2015-03-23 12:06:32 -0700281 for (Iterator iter = ranges(); iter.hasNext();) {
282 const AddressRange *r = iter.next();
283 if (r->beg <= address && address < r->end)
Alexey Samsonov7847d772013-09-10 14:36:16 +0000284 return true;
285 }
286 return false;
287}
288
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700289static atomic_uintptr_t g_total_mmaped;
290
291void IncreaseTotalMmap(uptr size) {
292 if (!common_flags()->mmap_limit_mb) return;
293 uptr total_mmaped =
294 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
Stephen Hines86277eb2015-03-23 12:06:32 -0700295 // Since for now mmap_limit_mb is not a user-facing flag, just kill
296 // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
297 RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700298}
299
300void DecreaseTotalMmap(uptr size) {
301 if (!common_flags()->mmap_limit_mb) return;
302 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
303}
304
Stephen Hines86277eb2015-03-23 12:06:32 -0700305bool TemplateMatch(const char *templ, const char *str) {
306 if (str == 0 || str[0] == 0)
307 return false;
308 bool start = false;
309 if (templ && templ[0] == '^') {
310 start = true;
311 templ++;
312 }
313 bool asterisk = false;
314 while (templ && templ[0]) {
315 if (templ[0] == '*') {
316 templ++;
317 start = false;
318 asterisk = true;
319 continue;
320 }
321 if (templ[0] == '$')
322 return str[0] == 0 || asterisk;
323 if (str[0] == 0)
324 return false;
325 char *tpos = (char*)internal_strchr(templ, '*');
326 char *tpos1 = (char*)internal_strchr(templ, '$');
327 if (tpos == 0 || (tpos1 && tpos1 < tpos))
328 tpos = tpos1;
329 if (tpos != 0)
330 tpos[0] = 0;
331 const char *str0 = str;
332 const char *spos = internal_strstr(str, templ);
333 str = spos + internal_strlen(templ);
334 templ = tpos;
335 if (tpos)
336 tpos[0] = tpos == tpos1 ? '$' : '*';
337 if (spos == 0)
338 return false;
339 if (start && spos != str0)
340 return false;
341 start = false;
342 asterisk = false;
343 }
344 return true;
345}
346
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700347static char binary_name_cache_str[kMaxPathLength];
348static const char *binary_basename_cache_str;
349
350const char *GetBinaryName() {
351 return binary_name_cache_str;
352}
353
354const char *GetBinaryBasename() {
355 return binary_basename_cache_str;
356}
357
358// Call once to make sure that binary_name_cache_str is initialized
359void CacheBinaryName() {
360 CHECK_EQ('\0', binary_name_cache_str[0]);
361 ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
362 binary_basename_cache_str = StripModuleName(binary_name_cache_str);
363}
364
Alexey Samsonov230c3be2012-06-06 09:26:25 +0000365} // namespace __sanitizer
Kostya Serebryany81dfbb72012-09-14 04:35:14 +0000366
Alexey Samsonovac8564e2012-11-02 09:23:36 +0000367using namespace __sanitizer; // NOLINT
368
369extern "C" {
Kostya Serebryany81dfbb72012-09-14 04:35:14 +0000370void __sanitizer_set_report_path(const char *path) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700371 report_file.SetReportPath(path);
Alexey Samsonovac8564e2012-11-02 09:23:36 +0000372}
Alexander Potapenko25742572012-12-10 13:10:40 +0000373
Kostya Serebryany2673fd82013-02-06 12:36:49 +0000374void __sanitizer_report_error_summary(const char *error_summary) {
Nick Lewycky47fcd762013-10-23 07:45:53 +0000375 Printf("%s\n", error_summary);
Kostya Serebryany2673fd82013-02-06 12:36:49 +0000376}
Stephen Hines86277eb2015-03-23 12:06:32 -0700377
378SANITIZER_INTERFACE_ATTRIBUTE
379void __sanitizer_set_death_callback(void (*callback)(void)) {
380 SetUserDieCallback(callback);
381}
Alexey Samsonovac8564e2012-11-02 09:23:36 +0000382} // extern "C"