]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
Merge ^/head r288457 through r288830.
[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_allocator_internal.h"
16 #include "sanitizer_flags.h"
17 #include "sanitizer_libc.h"
18 #include "sanitizer_placement_new.h"
19 #include "sanitizer_stacktrace_printer.h"
20 #include "sanitizer_symbolizer.h"
21
22 namespace __sanitizer {
23
24 const char *SanitizerToolName = "SanitizerTool";
25
26 atomic_uint32_t current_verbosity;
27
28 uptr GetPageSizeCached() {
29   static uptr PageSize;
30   if (!PageSize)
31     PageSize = GetPageSize();
32   return PageSize;
33 }
34
35 StaticSpinMutex report_file_mu;
36 ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
37
38 void RawWrite(const char *buffer) {
39   report_file.Write(buffer, internal_strlen(buffer));
40 }
41
42 void ReportFile::ReopenIfNecessary() {
43   mu->CheckLocked();
44   if (fd == kStdoutFd || fd == kStderrFd) return;
45
46   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
57       CloseFile(fd);
58   }
59
60   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   }
67   fd = OpenFile(full_path, WrOnly);
68   if (fd == kInvalidFd) {
69     const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
70     WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
71     WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
72     Die();
73   }
74   fd_pid = pid;
75 }
76
77 void 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)
90     CloseFile(fd);
91   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 }
100
101 // 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.
103 uptr 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.
106 uptr stoptheworld_tracer_ppid = 0;
107
108 static DieCallbackType InternalDieCallback, UserDieCallback;
109 void SetDieCallback(DieCallbackType callback) {
110   InternalDieCallback = callback;
111 }
112 void SetUserDieCallback(DieCallbackType callback) {
113   UserDieCallback = callback;
114 }
115
116 DieCallbackType GetDieCallback() {
117   return InternalDieCallback;
118 }
119
120 void NORETURN Die() {
121   if (UserDieCallback)
122     UserDieCallback();
123   if (InternalDieCallback)
124     InternalDieCallback();
125   internal__exit(1);
126 }
127
128 static CheckFailedCallbackType CheckFailedCallback;
129 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
130   CheckFailedCallback = callback;
131 }
132
133 void 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   }
138   Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
139                                                             v1, v2);
140   Die();
141 }
142
143 uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
144                       uptr max_len, error_t *errno_p) {
145   uptr PageSize = GetPageSizeCached();
146   uptr kMinFileLen = PageSize;
147   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) {
152     fd_t fd = OpenFile(file_name, RdOnly, errno_p);
153     if (fd == kInvalidFd) return 0;
154     UnmapOrDie(*buff, *buff_size);
155     *buff = (char*)MmapOrDie(size, __func__);
156     *buff_size = size;
157     // Read up to one page at a time.
158     read_len = 0;
159     bool reached_eof = false;
160     while (read_len + PageSize <= size) {
161       uptr just_read;
162       if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) {
163         UnmapOrDie(*buff, *buff_size);
164         return 0;
165       }
166       if (just_read == 0) {
167         reached_eof = true;
168         break;
169       }
170       read_len += just_read;
171     }
172     CloseFile(fd);
173     if (reached_eof)  // We've read the whole file.
174       break;
175   }
176   return read_len;
177 }
178
179 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
180
181 template<class T>
182 static inline bool CompareLess(const T &a, const T &b) {
183   return a < b;
184 }
185
186 void SortArray(uptr *array, uptr size) {
187   InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
188 }
189
190 // 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.
193 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
194 // uptr PageSize = GetPageSizeCached();
195   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.
202     res = (map_res + alignment) & ~(alignment - 1);
203   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
211 const 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;
215   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;
221 }
222
223 const char *StripModuleName(const char *module) {
224   if (module == 0)
225     return 0;
226   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, '/')) {
233     return slash_pos + 1;
234   }
235   return module;
236 }
237
238 void ReportErrorSummary(const char *error_message) {
239   if (!common_flags()->print_summary)
240     return;
241   InternalScopedString buff(kMaxSummaryLength);
242   buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
243   __sanitizer_report_error_summary(buff.data());
244 }
245
246 #ifndef SANITIZER_GO
247 void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
248   if (!common_flags()->print_summary)
249     return;
250   InternalScopedString buff(kMaxSummaryLength);
251   buff.append("%s ", error_type);
252   RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
253               common_flags()->strip_path_prefix);
254   ReportErrorSummary(buff.data());
255 }
256 #endif
257
258 void LoadedModule::set(const char *module_name, uptr base_address) {
259   clear();
260   full_name_ = internal_strdup(module_name);
261   base_address_ = base_address;
262 }
263
264 void LoadedModule::clear() {
265   InternalFree(full_name_);
266   full_name_ = nullptr;
267   while (!ranges_.empty()) {
268     AddressRange *r = ranges_.front();
269     ranges_.pop_front();
270     InternalFree(r);
271   }
272 }
273
274 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
275   void *mem = InternalAlloc(sizeof(AddressRange));
276   AddressRange *r = new(mem) AddressRange(beg, end, executable);
277   ranges_.push_back(r);
278 }
279
280 bool LoadedModule::containsAddress(uptr address) const {
281   for (Iterator iter = ranges(); iter.hasNext();) {
282     const AddressRange *r = iter.next();
283     if (r->beg <= address && address < r->end)
284       return true;
285   }
286   return false;
287 }
288
289 static atomic_uintptr_t g_total_mmaped;
290
291 void 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;
295   // 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);
298 }
299
300 void DecreaseTotalMmap(uptr size) {
301   if (!common_flags()->mmap_limit_mb) return;
302   atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
303 }
304
305 bool 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
347 static char binary_name_cache_str[kMaxPathLength];
348 static const char *binary_basename_cache_str;
349
350 const char *GetBinaryBasename() {
351   return binary_basename_cache_str;
352 }
353
354 // Call once to make sure that binary_name_cache_str is initialized
355 void CacheBinaryName() {
356   if (binary_name_cache_str[0] != '\0')
357     return;
358   ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
359   binary_basename_cache_str = StripModuleName(binary_name_cache_str);
360 }
361
362 uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
363   CacheBinaryName();
364   uptr name_len = internal_strlen(binary_name_cache_str);
365   name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
366   if (buf_len == 0)
367     return 0;
368   internal_memcpy(buf, binary_name_cache_str, name_len);
369   buf[name_len] = '\0';
370   return name_len;
371 }
372
373 }  // namespace __sanitizer
374
375 using namespace __sanitizer;  // NOLINT
376
377 extern "C" {
378 void __sanitizer_set_report_path(const char *path) {
379   report_file.SetReportPath(path);
380 }
381
382 void __sanitizer_report_error_summary(const char *error_summary) {
383   Printf("%s\n", error_summary);
384 }
385
386 SANITIZER_INTERFACE_ATTRIBUTE
387 void __sanitizer_set_death_callback(void (*callback)(void)) {
388   SetUserDieCallback(callback);
389 }
390 }  // extern "C"