]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc
Merge clang 7.0.1 and several follow-up changes
[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_interface.h"
16 #include "sanitizer_allocator_internal.h"
17 #include "sanitizer_atomic.h"
18 #include "sanitizer_flags.h"
19 #include "sanitizer_libc.h"
20 #include "sanitizer_placement_new.h"
21
22 namespace __sanitizer {
23
24 const char *SanitizerToolName = "SanitizerTool";
25
26 atomic_uint32_t current_verbosity;
27 uptr PageSizeCached;
28 u32 NumberOfCPUsCached;
29
30 // PID of the tracer task in StopTheWorld. It shares the address space with the
31 // main process, but has a different PID and thus requires special handling.
32 uptr stoptheworld_tracer_pid = 0;
33 // Cached pid of parent process - if the parent process dies, we want to keep
34 // writing to the same log file.
35 uptr stoptheworld_tracer_ppid = 0;
36
37 void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
38                                       const char *mmap_type, error_t err,
39                                       bool raw_report) {
40   static int recursion_count;
41   if (SANITIZER_RTEMS || raw_report || recursion_count) {
42     // If we are on RTEMS or raw report is requested or we went into recursion,
43     // just die.  The Report() and CHECK calls below may call mmap recursively
44     // and fail.
45     RawWrite("ERROR: Failed to mmap\n");
46     Die();
47   }
48   recursion_count++;
49   Report("ERROR: %s failed to "
50          "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
51          SanitizerToolName, mmap_type, size, size, mem_type, err);
52 #if !SANITIZER_GO
53   DumpProcessMap();
54 #endif
55   UNREACHABLE("unable to mmap");
56 }
57
58 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
59 typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);
60
61 const char *StripPathPrefix(const char *filepath,
62                             const char *strip_path_prefix) {
63   if (!filepath) return nullptr;
64   if (!strip_path_prefix) return filepath;
65   const char *res = filepath;
66   if (const char *pos = internal_strstr(filepath, strip_path_prefix))
67     res = pos + internal_strlen(strip_path_prefix);
68   if (res[0] == '.' && res[1] == '/')
69     res += 2;
70   return res;
71 }
72
73 const char *StripModuleName(const char *module) {
74   if (!module)
75     return nullptr;
76   if (SANITIZER_WINDOWS) {
77     // On Windows, both slash and backslash are possible.
78     // Pick the one that goes last.
79     if (const char *bslash_pos = internal_strrchr(module, '\\'))
80       return StripModuleName(bslash_pos + 1);
81   }
82   if (const char *slash_pos = internal_strrchr(module, '/')) {
83     return slash_pos + 1;
84   }
85   return module;
86 }
87
88 void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
89   if (!common_flags()->print_summary)
90     return;
91   InternalScopedString buff(kMaxSummaryLength);
92   buff.append("SUMMARY: %s: %s",
93               alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
94   __sanitizer_report_error_summary(buff.data());
95 }
96
97 // Removes the ANSI escape sequences from the input string (in-place).
98 void RemoveANSIEscapeSequencesFromString(char *str) {
99   if (!str)
100     return;
101
102   // We are going to remove the escape sequences in place.
103   char *s = str;
104   char *z = str;
105   while (*s != '\0') {
106     CHECK_GE(s, z);
107     // Skip over ANSI escape sequences with pointer 's'.
108     if (*s == '\033' && *(s + 1) == '[') {
109       s = internal_strchrnul(s, 'm');
110       if (*s == '\0') {
111         break;
112       }
113       s++;
114       continue;
115     }
116     // 's' now points at a character we want to keep. Copy over the buffer
117     // content if the escape sequence has been perviously skipped andadvance
118     // both pointers.
119     if (s != z)
120       *z = *s;
121
122     // If we have not seen an escape sequence, just advance both pointers.
123     z++;
124     s++;
125   }
126
127   // Null terminate the string.
128   *z = '\0';
129 }
130
131 void LoadedModule::set(const char *module_name, uptr base_address) {
132   clear();
133   full_name_ = internal_strdup(module_name);
134   base_address_ = base_address;
135 }
136
137 void LoadedModule::set(const char *module_name, uptr base_address,
138                        ModuleArch arch, u8 uuid[kModuleUUIDSize],
139                        bool instrumented) {
140   set(module_name, base_address);
141   arch_ = arch;
142   internal_memcpy(uuid_, uuid, sizeof(uuid_));
143   instrumented_ = instrumented;
144 }
145
146 void LoadedModule::clear() {
147   InternalFree(full_name_);
148   base_address_ = 0;
149   max_executable_address_ = 0;
150   full_name_ = nullptr;
151   arch_ = kModuleArchUnknown;
152   internal_memset(uuid_, 0, kModuleUUIDSize);
153   instrumented_ = false;
154   while (!ranges_.empty()) {
155     AddressRange *r = ranges_.front();
156     ranges_.pop_front();
157     InternalFree(r);
158   }
159 }
160
161 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,
162                                    bool writable, const char *name) {
163   void *mem = InternalAlloc(sizeof(AddressRange));
164   AddressRange *r =
165       new(mem) AddressRange(beg, end, executable, writable, name);
166   ranges_.push_back(r);
167   if (executable && end > max_executable_address_)
168     max_executable_address_ = end;
169 }
170
171 bool LoadedModule::containsAddress(uptr address) const {
172   for (const AddressRange &r : ranges()) {
173     if (r.beg <= address && address < r.end)
174       return true;
175   }
176   return false;
177 }
178
179 static atomic_uintptr_t g_total_mmaped;
180
181 void IncreaseTotalMmap(uptr size) {
182   if (!common_flags()->mmap_limit_mb) return;
183   uptr total_mmaped =
184       atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
185   // Since for now mmap_limit_mb is not a user-facing flag, just kill
186   // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
187   RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
188 }
189
190 void DecreaseTotalMmap(uptr size) {
191   if (!common_flags()->mmap_limit_mb) return;
192   atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
193 }
194
195 bool TemplateMatch(const char *templ, const char *str) {
196   if ((!str) || str[0] == 0)
197     return false;
198   bool start = false;
199   if (templ && templ[0] == '^') {
200     start = true;
201     templ++;
202   }
203   bool asterisk = false;
204   while (templ && templ[0]) {
205     if (templ[0] == '*') {
206       templ++;
207       start = false;
208       asterisk = true;
209       continue;
210     }
211     if (templ[0] == '$')
212       return str[0] == 0 || asterisk;
213     if (str[0] == 0)
214       return false;
215     char *tpos = (char*)internal_strchr(templ, '*');
216     char *tpos1 = (char*)internal_strchr(templ, '$');
217     if ((!tpos) || (tpos1 && tpos1 < tpos))
218       tpos = tpos1;
219     if (tpos)
220       tpos[0] = 0;
221     const char *str0 = str;
222     const char *spos = internal_strstr(str, templ);
223     str = spos + internal_strlen(templ);
224     templ = tpos;
225     if (tpos)
226       tpos[0] = tpos == tpos1 ? '$' : '*';
227     if (!spos)
228       return false;
229     if (start && spos != str0)
230       return false;
231     start = false;
232     asterisk = false;
233   }
234   return true;
235 }
236
237 static char binary_name_cache_str[kMaxPathLength];
238 static char process_name_cache_str[kMaxPathLength];
239
240 const char *GetProcessName() {
241   return process_name_cache_str;
242 }
243
244 static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
245   ReadLongProcessName(buf, buf_len);
246   char *s = const_cast<char *>(StripModuleName(buf));
247   uptr len = internal_strlen(s);
248   if (s != buf) {
249     internal_memmove(buf, s, len);
250     buf[len] = '\0';
251   }
252   return len;
253 }
254
255 void UpdateProcessName() {
256   ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
257 }
258
259 // Call once to make sure that binary_name_cache_str is initialized
260 void CacheBinaryName() {
261   if (binary_name_cache_str[0] != '\0')
262     return;
263   ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
264   ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
265 }
266
267 uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
268   CacheBinaryName();
269   uptr name_len = internal_strlen(binary_name_cache_str);
270   name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
271   if (buf_len == 0)
272     return 0;
273   internal_memcpy(buf, binary_name_cache_str, name_len);
274   buf[name_len] = '\0';
275   return name_len;
276 }
277
278 void PrintCmdline() {
279   char **argv = GetArgv();
280   if (!argv) return;
281   Printf("\nCommand: ");
282   for (uptr i = 0; argv[i]; ++i)
283     Printf("%s ", argv[i]);
284   Printf("\n\n");
285 }
286
287 // Malloc hooks.
288 static const int kMaxMallocFreeHooks = 5;
289 struct MallocFreeHook {
290   void (*malloc_hook)(const void *, uptr);
291   void (*free_hook)(const void *);
292 };
293
294 static MallocFreeHook MFHooks[kMaxMallocFreeHooks];
295
296 void RunMallocHooks(const void *ptr, uptr size) {
297   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
298     auto hook = MFHooks[i].malloc_hook;
299     if (!hook) return;
300     hook(ptr, size);
301   }
302 }
303
304 void RunFreeHooks(const void *ptr) {
305   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
306     auto hook = MFHooks[i].free_hook;
307     if (!hook) return;
308     hook(ptr);
309   }
310 }
311
312 static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
313                                   void (*free_hook)(const void *)) {
314   if (!malloc_hook || !free_hook) return 0;
315   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
316     if (MFHooks[i].malloc_hook == nullptr) {
317       MFHooks[i].malloc_hook = malloc_hook;
318       MFHooks[i].free_hook = free_hook;
319       return i + 1;
320     }
321   }
322   return 0;
323 }
324
325 } // namespace __sanitizer
326
327 using namespace __sanitizer;  // NOLINT
328
329 extern "C" {
330 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,
331                              const char *error_summary) {
332   Printf("%s\n", error_summary);
333 }
334
335 SANITIZER_INTERFACE_ATTRIBUTE
336 int __sanitizer_acquire_crash_state() {
337   static atomic_uint8_t in_crash_state = {};
338   return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed);
339 }
340
341 SANITIZER_INTERFACE_ATTRIBUTE
342 void __sanitizer_set_death_callback(void (*callback)(void)) {
343   SetUserDieCallback(callback);
344 }
345
346 SANITIZER_INTERFACE_ATTRIBUTE
347 int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
348                                                                   uptr),
349                                               void (*free_hook)(const void *)) {
350   return InstallMallocFreeHooks(malloc_hook, free_hook);
351 }
352 } // extern "C"