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 
GetPageSizeCached()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 
RawWrite(const char * buffer)38 void RawWrite(const char *buffer) {
39   report_file.Write(buffer, internal_strlen(buffer));
40 }
41 
ReopenIfNecessary()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   internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
61   fd = OpenFile(full_path, WrOnly);
62   if (fd == kInvalidFd) {
63     const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
64     WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
65     WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
66     Die();
67   }
68   fd_pid = pid;
69 }
70 
SetReportPath(const char * path)71 void ReportFile::SetReportPath(const char *path) {
72   if (!path)
73     return;
74   uptr len = internal_strlen(path);
75   if (len > sizeof(path_prefix) - 100) {
76     Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
77            path[0], path[1], path[2], path[3],
78            path[4], path[5], path[6], path[7]);
79     Die();
80   }
81 
82   SpinMutexLock l(mu);
83   if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
84     CloseFile(fd);
85   fd = kInvalidFd;
86   if (internal_strcmp(path, "stdout") == 0) {
87     fd = kStdoutFd;
88   } else if (internal_strcmp(path, "stderr") == 0) {
89     fd = kStderrFd;
90   } else {
91     internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
92   }
93 }
94 
95 // PID of the tracer task in StopTheWorld. It shares the address space with the
96 // main process, but has a different PID and thus requires special handling.
97 uptr stoptheworld_tracer_pid = 0;
98 // Cached pid of parent process - if the parent process dies, we want to keep
99 // writing to the same log file.
100 uptr stoptheworld_tracer_ppid = 0;
101 
102 static DieCallbackType InternalDieCallback, UserDieCallback;
SetDieCallback(DieCallbackType callback)103 void SetDieCallback(DieCallbackType callback) {
104   InternalDieCallback = callback;
105 }
SetUserDieCallback(DieCallbackType callback)106 void SetUserDieCallback(DieCallbackType callback) {
107   UserDieCallback = callback;
108 }
109 
GetDieCallback()110 DieCallbackType GetDieCallback() {
111   return InternalDieCallback;
112 }
113 
Die()114 void NORETURN Die() {
115   if (UserDieCallback)
116     UserDieCallback();
117   if (InternalDieCallback)
118     InternalDieCallback();
119   internal__exit(1);
120 }
121 
122 static CheckFailedCallbackType CheckFailedCallback;
SetCheckFailedCallback(CheckFailedCallbackType callback)123 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
124   CheckFailedCallback = callback;
125 }
126 
CheckFailed(const char * file,int line,const char * cond,u64 v1,u64 v2)127 void NORETURN CheckFailed(const char *file, int line, const char *cond,
128                           u64 v1, u64 v2) {
129   if (CheckFailedCallback) {
130     CheckFailedCallback(file, line, cond, v1, v2);
131   }
132   Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
133                                                             v1, v2);
134   Die();
135 }
136 
ReadFileToBuffer(const char * file_name,char ** buff,uptr * buff_size,uptr max_len,error_t * errno_p)137 uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
138                       uptr max_len, error_t *errno_p) {
139   uptr PageSize = GetPageSizeCached();
140   uptr kMinFileLen = PageSize;
141   uptr read_len = 0;
142   *buff = 0;
143   *buff_size = 0;
144   // The files we usually open are not seekable, so try different buffer sizes.
145   for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
146     fd_t fd = OpenFile(file_name, RdOnly, errno_p);
147     if (fd == kInvalidFd) return 0;
148     UnmapOrDie(*buff, *buff_size);
149     *buff = (char*)MmapOrDie(size, __func__);
150     *buff_size = size;
151     // Read up to one page at a time.
152     read_len = 0;
153     bool reached_eof = false;
154     while (read_len + PageSize <= size) {
155       uptr just_read;
156       if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) {
157         UnmapOrDie(*buff, *buff_size);
158         return 0;
159       }
160       if (just_read == 0) {
161         reached_eof = true;
162         break;
163       }
164       read_len += just_read;
165     }
166     CloseFile(fd);
167     if (reached_eof)  // We've read the whole file.
168       break;
169   }
170   return read_len;
171 }
172 
173 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
174 
175 template<class T>
CompareLess(const T & a,const T & b)176 static inline bool CompareLess(const T &a, const T &b) {
177   return a < b;
178 }
179 
SortArray(uptr * array,uptr size)180 void SortArray(uptr *array, uptr size) {
181   InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
182 }
183 
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.
MmapAlignedOrDie(uptr size,uptr alignment,const char * mem_type)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;
194   uptr res = map_res;
195   if (res & (alignment - 1))  // Not aligned.
196     res = (map_res + alignment) & ~(alignment - 1);
197   uptr end = res + size;
198   if (res != map_res)
199     UnmapOrDie((void*)map_res, res - map_res);
200   if (end != map_end)
201     UnmapOrDie((void*)end, map_end - end);
202   return (void*)res;
203 }
204 
StripPathPrefix(const char * filepath,const char * strip_path_prefix)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 *res = filepath;
210   if (const char *pos = internal_strstr(filepath, strip_path_prefix))
211     res = pos + internal_strlen(strip_path_prefix);
212   if (res[0] == '.' && res[1] == '/')
213     res += 2;
214   return res;
215 }
216 
StripModuleName(const char * module)217 const char *StripModuleName(const char *module) {
218   if (module == 0)
219     return 0;
220   if (SANITIZER_WINDOWS) {
221     // On Windows, both slash and backslash are possible.
222     // Pick the one that goes last.
223     if (const char *bslash_pos = internal_strrchr(module, '\\'))
224       return StripModuleName(bslash_pos + 1);
225   }
226   if (const char *slash_pos = internal_strrchr(module, '/')) {
227     return slash_pos + 1;
228   }
229   return module;
230 }
231 
ReportErrorSummary(const char * error_message)232 void ReportErrorSummary(const char *error_message) {
233   if (!common_flags()->print_summary)
234     return;
235   InternalScopedString buff(kMaxSummaryLength);
236   buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
237   __sanitizer_report_error_summary(buff.data());
238 }
239 
240 #ifndef SANITIZER_GO
ReportErrorSummary(const char * error_type,const AddressInfo & info)241 void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
242   if (!common_flags()->print_summary)
243     return;
244   InternalScopedString buff(kMaxSummaryLength);
245   buff.append("%s ", error_type);
246   RenderFrame(&buff, "%L %F", 0, info, common_flags()->strip_path_prefix);
247   ReportErrorSummary(buff.data());
248 }
249 #endif
250 
set(const char * module_name,uptr base_address)251 void LoadedModule::set(const char *module_name, uptr base_address) {
252   clear();
253   full_name_ = internal_strdup(module_name);
254   base_address_ = base_address;
255 }
256 
clear()257 void LoadedModule::clear() {
258   InternalFree(full_name_);
259   full_name_ = nullptr;
260   while (!ranges_.empty()) {
261     AddressRange *r = ranges_.front();
262     ranges_.pop_front();
263     InternalFree(r);
264   }
265 }
266 
addAddressRange(uptr beg,uptr end,bool executable)267 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
268   void *mem = InternalAlloc(sizeof(AddressRange));
269   AddressRange *r = new(mem) AddressRange(beg, end, executable);
270   ranges_.push_back(r);
271 }
272 
containsAddress(uptr address) const273 bool LoadedModule::containsAddress(uptr address) const {
274   for (Iterator iter = ranges(); iter.hasNext();) {
275     const AddressRange *r = iter.next();
276     if (r->beg <= address && address < r->end)
277       return true;
278   }
279   return false;
280 }
281 
282 static atomic_uintptr_t g_total_mmaped;
283 
IncreaseTotalMmap(uptr size)284 void IncreaseTotalMmap(uptr size) {
285   if (!common_flags()->mmap_limit_mb) return;
286   uptr total_mmaped =
287       atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
288   // Since for now mmap_limit_mb is not a user-facing flag, just kill
289   // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
290   RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
291 }
292 
DecreaseTotalMmap(uptr size)293 void DecreaseTotalMmap(uptr size) {
294   if (!common_flags()->mmap_limit_mb) return;
295   atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
296 }
297 
TemplateMatch(const char * templ,const char * str)298 bool TemplateMatch(const char *templ, const char *str) {
299   if (str == 0 || str[0] == 0)
300     return false;
301   bool start = false;
302   if (templ && templ[0] == '^') {
303     start = true;
304     templ++;
305   }
306   bool asterisk = false;
307   while (templ && templ[0]) {
308     if (templ[0] == '*') {
309       templ++;
310       start = false;
311       asterisk = true;
312       continue;
313     }
314     if (templ[0] == '$')
315       return str[0] == 0 || asterisk;
316     if (str[0] == 0)
317       return false;
318     char *tpos = (char*)internal_strchr(templ, '*');
319     char *tpos1 = (char*)internal_strchr(templ, '$');
320     if (tpos == 0 || (tpos1 && tpos1 < tpos))
321       tpos = tpos1;
322     if (tpos != 0)
323       tpos[0] = 0;
324     const char *str0 = str;
325     const char *spos = internal_strstr(str, templ);
326     str = spos + internal_strlen(templ);
327     templ = tpos;
328     if (tpos)
329       tpos[0] = tpos == tpos1 ? '$' : '*';
330     if (spos == 0)
331       return false;
332     if (start && spos != str0)
333       return false;
334     start = false;
335     asterisk = false;
336   }
337   return true;
338 }
339 
340 }  // namespace __sanitizer
341 
342 using namespace __sanitizer;  // NOLINT
343 
344 extern "C" {
__sanitizer_set_report_path(const char * path)345 void __sanitizer_set_report_path(const char *path) {
346   report_file.SetReportPath(path);
347 }
348 
__sanitizer_report_error_summary(const char * error_summary)349 void __sanitizer_report_error_summary(const char *error_summary) {
350   Printf("%s\n", error_summary);
351 }
352 
353 SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_set_death_callback(void (* callback)(void))354 void __sanitizer_set_death_callback(void (*callback)(void)) {
355   SetUserDieCallback(callback);
356 }
357 }  // extern "C"
358