]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
Reintegrate head revisions r273096-r277147
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / sanitizer_common / sanitizer_common.cc
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
18 namespace __sanitizer {
19
20 const char *SanitizerToolName = "SanitizerTool";
21
22 uptr GetPageSizeCached() {
23   static uptr PageSize;
24   if (!PageSize)
25     PageSize = GetPageSize();
26   return PageSize;
27 }
28
29 StaticSpinMutex report_file_mu;
30 ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
31
32 void RawWrite(const char *buffer) {
33   report_file.Write(buffer, internal_strlen(buffer));
34 }
35
36 void ReportFile::ReopenIfNecessary() {
37   mu->CheckLocked();
38   if (fd == kStdoutFd || fd == kStderrFd) return;
39
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.
48     if (fd_pid == pid)
49       return;
50     else
51       internal_close(fd);
52   }
53
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));
60     Die();
61   }
62   fd = openrv;
63   fd_pid = pid;
64 }
65
66 void ReportFile::SetReportPath(const char *path) {
67   if (!path)
68     return;
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]);
74     Die();
75   }
76
77   SpinMutexLock l(mu);
78   if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
79     internal_close(fd);
80   fd = kInvalidFd;
81   if (internal_strcmp(path, "stdout") == 0) {
82     fd = kStdoutFd;
83   } else if (internal_strcmp(path, "stderr") == 0) {
84     fd = kStderrFd;
85   } else {
86     internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
87   }
88 }
89
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;
96
97 static DieCallbackType DieCallback;
98 void SetDieCallback(DieCallbackType callback) {
99   DieCallback = callback;
100 }
101
102 DieCallbackType GetDieCallback() {
103   return DieCallback;
104 }
105
106 void NORETURN Die() {
107   if (DieCallback) {
108     DieCallback();
109   }
110   internal__exit(1);
111 }
112
113 static CheckFailedCallbackType CheckFailedCallback;
114 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
115   CheckFailedCallback = callback;
116 }
117
118 void NORETURN CheckFailed(const char *file, int line, const char *cond,
119                           u64 v1, u64 v2) {
120   if (CheckFailedCallback) {
121     CheckFailedCallback(file, line, cond, v1, v2);
122   }
123   Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
124                                                             v1, v2);
125   Die();
126 }
127
128 uptr ReadFileToBuffer(const char *file_name, char **buff,
129                       uptr *buff_size, uptr max_len) {
130   uptr PageSize = GetPageSizeCached();
131   uptr kMinFileLen = PageSize;
132   uptr read_len = 0;
133   *buff = 0;
134   *buff_size = 0;
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;
139     fd_t fd = openrv;
140     UnmapOrDie(*buff, *buff_size);
141     *buff = (char*)MmapOrDie(size, __func__);
142     *buff_size = size;
143     // Read up to one page at a time.
144     read_len = 0;
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) {
149         reached_eof = true;
150         break;
151       }
152       read_len += just_read;
153     }
154     internal_close(fd);
155     if (reached_eof)  // We've read the whole file.
156       break;
157   }
158   return read_len;
159 }
160
161 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
162
163 template<class T>
164 static inline bool CompareLess(const T &a, const T &b) {
165   return a < b;
166 }
167
168 void SortArray(uptr *array, uptr size) {
169   InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
170 }
171
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;
182   uptr res = map_res;
183   if (res & (alignment - 1))  // Not aligned.
184     res = (map_res + alignment) & ~(alignment - 1);
185   uptr end = res + size;
186   if (res != map_res)
187     UnmapOrDie((void*)map_res, res - map_res);
188   if (end != map_end)
189     UnmapOrDie((void*)end, map_end - end);
190   return (void*)res;
191 }
192
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] == '/')
201     pos += 2;
202   return pos;
203 }
204
205 const char *StripModuleName(const char *module) {
206   if (module == 0)
207     return 0;
208   if (const char *slash_pos = internal_strrchr(module, '/'))
209     return slash_pos + 1;
210   return module;
211 }
212
213 void ReportErrorSummary(const char *error_message) {
214   if (!common_flags()->print_summary)
215     return;
216   InternalScopedString buff(kMaxSummaryLength);
217   buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
218   __sanitizer_report_error_summary(buff.data());
219 }
220
221 void ReportErrorSummary(const char *error_type, const char *file,
222                         int line, const char *function) {
223   if (!common_flags()->print_summary)
224     return;
225   InternalScopedString buff(kMaxSummaryLength);
226   buff.append("%s %s:%d %s", error_type,
227               file ? StripPathPrefix(file, common_flags()->strip_path_prefix)
228                    : "??",
229               line, function ? function : "??");
230   ReportErrorSummary(buff.data());
231 }
232
233 LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
234   full_name_ = internal_strdup(module_name);
235   base_address_ = base_address;
236   n_ranges_ = 0;
237 }
238
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;
244   n_ranges_++;
245 }
246
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)
250       return true;
251   }
252   return false;
253 }
254
255 static atomic_uintptr_t g_total_mmaped;
256
257 void IncreaseTotalMmap(uptr size) {
258   if (!common_flags()->mmap_limit_mb) return;
259   uptr total_mmaped =
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);
264 }
265
266 void DecreaseTotalMmap(uptr size) {
267   if (!common_flags()->mmap_limit_mb) return;
268   atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
269 }
270
271 }  // namespace __sanitizer
272
273 using namespace __sanitizer;  // NOLINT
274
275 extern "C" {
276 void __sanitizer_set_report_path(const char *path) {
277   report_file.SetReportPath(path);
278 }
279
280 void __sanitizer_report_error_summary(const char *error_summary) {
281   Printf("%s\n", error_summary);
282 }
283 }  // extern "C"