blob: 76f90712c76daf1bdd8fc96b6e0872466f8a6e35 [file] [log] [blame]
Alexey Samsonovee072902012-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"
Alexey Samsonovf2b811a2013-10-04 08:55:03 +000015#include "sanitizer_flags.h"
Alexey Samsonovee072902012-06-06 09:26:25 +000016#include "sanitizer_libc.h"
Alexey Samsonove4a88982012-06-15 07:00:31 +000017
Alexey Samsonovee072902012-06-06 09:26:25 +000018namespace __sanitizer {
19
Kostya Serebryanybda64b42013-01-31 14:11:21 +000020const char *SanitizerToolName = "SanitizerTool";
Alexander Potapenko845b5752013-03-15 14:37:21 +000021uptr SanitizerVerbosity = 0;
Kostya Serebryanybda64b42013-01-31 14:11:21 +000022
Kostya Serebryanyf22c6972012-11-23 15:38:49 +000023uptr GetPageSizeCached() {
24 static uptr PageSize;
25 if (!PageSize)
26 PageSize = GetPageSize();
27 return PageSize;
28}
29
Alexander Potapenkob4ba9952013-01-18 16:44:27 +000030
31// By default, dump to stderr. If |log_to_file| is true and |report_fd_pid|
32// isn't equal to the current PID, try to obtain file descriptor by opening
33// file "report_path_prefix.<PID>".
Peter Collingbourne6d4a7d372013-05-17 16:17:19 +000034fd_t report_fd = kStderrFd;
Reid Klecknerd483c072013-09-05 03:19:57 +000035
36// Set via __sanitizer_set_report_path.
37bool log_to_file = false;
38char report_path_prefix[sizeof(report_path_prefix)];
39
Alexander Potapenkob4ba9952013-01-18 16:44:27 +000040// PID of process that opened |report_fd|. If a fork() occurs, the PID of the
41// child thread will be different from |report_fd_pid|.
Reid Klecknerd483c072013-09-05 03:19:57 +000042uptr report_fd_pid = 0;
Kostya Serebryany45d849c2012-09-14 04:35:14 +000043
Sergey Matveevef7db732013-08-26 13:20:31 +000044static DieCallbackType DieCallback;
45void SetDieCallback(DieCallbackType callback) {
Alexey Samsonov5c6b93b2012-09-11 09:44:48 +000046 DieCallback = callback;
47}
48
Sergey Matveevef7db732013-08-26 13:20:31 +000049DieCallbackType GetDieCallback() {
50 return DieCallback;
51}
52
Alexey Samsonov5c6b93b2012-09-11 09:44:48 +000053void NORETURN Die() {
54 if (DieCallback) {
55 DieCallback();
56 }
Alexey Samsonovaadd1f22013-02-20 13:54:32 +000057 internal__exit(1);
Alexey Samsonov5c6b93b2012-09-11 09:44:48 +000058}
59
60static CheckFailedCallbackType CheckFailedCallback;
61void SetCheckFailedCallback(CheckFailedCallbackType callback) {
62 CheckFailedCallback = callback;
63}
64
65void NORETURN CheckFailed(const char *file, int line, const char *cond,
66 u64 v1, u64 v2) {
67 if (CheckFailedCallback) {
68 CheckFailedCallback(file, line, cond, v1, v2);
69 }
Dmitry Vyukovaf96edb2013-01-11 15:07:49 +000070 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
71 v1, v2);
Alexey Samsonov5c6b93b2012-09-11 09:44:48 +000072 Die();
73}
74
Alexey Samsonovfe44fbd2012-06-07 05:38:26 +000075uptr ReadFileToBuffer(const char *file_name, char **buff,
76 uptr *buff_size, uptr max_len) {
Kostya Serebryanyf22c6972012-11-23 15:38:49 +000077 uptr PageSize = GetPageSizeCached();
78 uptr kMinFileLen = PageSize;
Alexey Samsonovfe44fbd2012-06-07 05:38:26 +000079 uptr read_len = 0;
80 *buff = 0;
81 *buff_size = 0;
82 // The files we usually open are not seekable, so try different buffer sizes.
83 for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
Peter Collingbourne6f4be192013-05-08 14:43:49 +000084 uptr openrv = OpenFile(file_name, /*write*/ false);
85 if (internal_iserror(openrv)) return 0;
86 fd_t fd = openrv;
Alexey Samsonovfe44fbd2012-06-07 05:38:26 +000087 UnmapOrDie(*buff, *buff_size);
88 *buff = (char*)MmapOrDie(size, __FUNCTION__);
89 *buff_size = size;
90 // Read up to one page at a time.
91 read_len = 0;
92 bool reached_eof = false;
Kostya Serebryanyf22c6972012-11-23 15:38:49 +000093 while (read_len + PageSize <= size) {
94 uptr just_read = internal_read(fd, *buff + read_len, PageSize);
Alexey Samsonovfe44fbd2012-06-07 05:38:26 +000095 if (just_read == 0) {
96 reached_eof = true;
97 break;
98 }
99 read_len += just_read;
100 }
101 internal_close(fd);
102 if (reached_eof) // We've read the whole file.
103 break;
104 }
105 return read_len;
106}
107
Sergey Matveevd9da20f2013-05-13 11:58:48 +0000108typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
109
110template<class T>
111static inline bool CompareLess(const T &a, const T &b) {
112 return a < b;
113}
114
Alexey Samsonove4a88982012-06-15 07:00:31 +0000115void SortArray(uptr *array, uptr size) {
Sergey Matveevd9da20f2013-05-13 11:58:48 +0000116 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
Alexey Samsonove4a88982012-06-15 07:00:31 +0000117}
118
Kostya Serebryany1e3d3872012-12-06 06:10:31 +0000119// We want to map a chunk of address space aligned to 'alignment'.
120// We do it by maping a bit more and then unmaping redundant pieces.
121// We probably can do it with fewer syscalls in some OS-dependent way.
122void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
Bill Wendlingf9528842012-12-06 07:43:17 +0000123// uptr PageSize = GetPageSizeCached();
Kostya Serebryany1e3d3872012-12-06 06:10:31 +0000124 CHECK(IsPowerOfTwo(size));
125 CHECK(IsPowerOfTwo(alignment));
126 uptr map_size = size + alignment;
127 uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
128 uptr map_end = map_res + map_size;
129 uptr res = map_res;
130 if (res & (alignment - 1)) // Not aligned.
Dmitry Vyukove3e05572012-12-06 15:42:54 +0000131 res = (map_res + alignment) & ~(alignment - 1);
Kostya Serebryany1e3d3872012-12-06 06:10:31 +0000132 uptr end = res + size;
133 if (res != map_res)
134 UnmapOrDie((void*)map_res, res - map_res);
135 if (end != map_end)
136 UnmapOrDie((void*)end, map_end - end);
137 return (void*)res;
138}
139
Alexey Samsonovf2b811a2013-10-04 08:55:03 +0000140const char *StripPathPrefix(const char *filepath,
141 const char *strip_path_prefix) {
142 if (filepath == 0) return 0;
143 if (strip_path_prefix == 0) return filepath;
144 const char *pos = internal_strstr(filepath, strip_path_prefix);
145 if (pos == 0) return filepath;
146 pos += internal_strlen(strip_path_prefix);
147 if (pos[0] == '.' && pos[1] == '/')
148 pos += 2;
149 return pos;
150}
151
152void PrintSourceLocation(const char *file, int line, int column) {
153 CHECK(file);
154 Printf("%s", StripPathPrefix(file, common_flags()->strip_path_prefix));
155 if (line > 0) {
156 Printf(":%d", line);
157 if (column > 0)
158 Printf(":%d", column);
159 }
160}
161
162void PrintModuleAndOffset(const char *module, uptr offset) {
163 Printf("(%s+0x%zx)",
164 StripPathPrefix(module, common_flags()->strip_path_prefix), offset);
165}
166
Kostya Serebryanyb4c2c5c2013-02-06 12:36:49 +0000167void ReportErrorSummary(const char *error_type, const char *file,
168 int line, const char *function) {
169 const int kMaxSize = 1024; // We don't want a summary too long.
170 InternalScopedBuffer<char> buff(kMaxSize);
Alexey Samsonovf2b811a2013-10-04 08:55:03 +0000171 internal_snprintf(
172 buff.data(), kMaxSize, "%s: %s %s:%d %s", SanitizerToolName, error_type,
173 file ? StripPathPrefix(file, common_flags()->strip_path_prefix) : "??",
174 line, function ? function : "??");
Kostya Serebryanyb4c2c5c2013-02-06 12:36:49 +0000175 __sanitizer_report_error_summary(buff.data());
176}
177
Alexey Samsonov7a36e612013-09-10 14:36:16 +0000178LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
179 full_name_ = internal_strdup(module_name);
180 base_address_ = base_address;
181 n_ranges_ = 0;
182}
183
184void LoadedModule::addAddressRange(uptr beg, uptr end) {
185 CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
186 ranges_[n_ranges_].beg = beg;
187 ranges_[n_ranges_].end = end;
188 n_ranges_++;
189}
190
191bool LoadedModule::containsAddress(uptr address) const {
192 for (uptr i = 0; i < n_ranges_; i++) {
193 if (ranges_[i].beg <= address && address < ranges_[i].end)
194 return true;
195 }
196 return false;
197}
198
Alexey Samsonovee072902012-06-06 09:26:25 +0000199} // namespace __sanitizer
Kostya Serebryany45d849c2012-09-14 04:35:14 +0000200
Alexey Samsonovfd67c832012-11-02 09:23:36 +0000201using namespace __sanitizer; // NOLINT
202
203extern "C" {
Kostya Serebryany45d849c2012-09-14 04:35:14 +0000204void __sanitizer_set_report_path(const char *path) {
Dmitry Vyukov7ac0b2b2013-10-15 12:25:29 +0000205 if (!path)
206 return;
Kostya Serebryany45d849c2012-09-14 04:35:14 +0000207 uptr len = internal_strlen(path);
Alexander Potapenkob4ba9952013-01-18 16:44:27 +0000208 if (len > sizeof(report_path_prefix) - 100) {
Kostya Serebryany45d849c2012-09-14 04:35:14 +0000209 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
210 path[0], path[1], path[2], path[3],
211 path[4], path[5], path[6], path[7]);
212 Die();
213 }
Alexey Samsonov20ba98f2012-11-02 09:38:47 +0000214 if (report_fd != kStdoutFd &&
215 report_fd != kStderrFd &&
216 report_fd != kInvalidFd)
217 internal_close(report_fd);
Dmitry Vyukov7ac0b2b2013-10-15 12:25:29 +0000218 report_fd = kInvalidFd;
219 log_to_file = false;
220 if (internal_strcmp(path, "stdout") == 0) {
221 report_fd = kStdoutFd;
222 } else if (internal_strcmp(path, "stderr") == 0) {
223 report_fd = kStderrFd;
224 } else {
225 internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix));
226 report_path_prefix[len] = '\0';
227 log_to_file = true;
228 }
Alexey Samsonovfd67c832012-11-02 09:23:36 +0000229}
Alexander Potapenko1746f552012-12-10 13:10:40 +0000230
231void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
232 (void)reserved;
233 PrepareForSandboxing();
234}
Kostya Serebryanyb4c2c5c2013-02-06 12:36:49 +0000235
236void __sanitizer_report_error_summary(const char *error_summary) {
237 Printf("SUMMARY: %s\n", error_summary);
238}
Alexey Samsonovfd67c832012-11-02 09:23:36 +0000239} // extern "C"