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