1 //===-- sanitizer_common.cpp ----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is shared between AddressSanitizer and ThreadSanitizer
10 // run-time libraries.
11 //===----------------------------------------------------------------------===//
12 
13 #include "sanitizer_common.h"
14 
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_interface_internal.h"
20 #include "sanitizer_libc.h"
21 #include "sanitizer_placement_new.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.  The
44     // 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 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;
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   uuid_size_ = kModuleUUIDSize;
144   instrumented_ = instrumented;
145 }
146 
147 void LoadedModule::setUuid(const char *uuid, uptr size) {
148   if (size > kModuleUUIDSize)
149     size = kModuleUUIDSize;
150   internal_memcpy(uuid_, uuid, size);
151   uuid_size_ = size;
152 }
153 
154 void LoadedModule::clear() {
155   InternalFree(full_name_);
156   base_address_ = 0;
157   max_address_ = 0;
158   full_name_ = nullptr;
159   arch_ = kModuleArchUnknown;
160   internal_memset(uuid_, 0, kModuleUUIDSize);
161   instrumented_ = false;
162   while (!ranges_.empty()) {
163     AddressRange *r = ranges_.front();
164     ranges_.pop_front();
165     InternalFree(r);
166   }
167 }
168 
169 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,
170                                    bool writable, const char *name) {
171   void *mem = InternalAlloc(sizeof(AddressRange));
172   AddressRange *r =
173       new(mem) AddressRange(beg, end, executable, writable, name);
174   ranges_.push_back(r);
175   max_address_ = Max(max_address_, end);
176 }
177 
178 bool LoadedModule::containsAddress(uptr address) const {
179   for (const AddressRange &r : ranges()) {
180     if (r.beg <= address && address < r.end)
181       return true;
182   }
183   return false;
184 }
185 
186 static atomic_uintptr_t g_total_mmaped;
187 
188 void IncreaseTotalMmap(uptr size) {
189   if (!common_flags()->mmap_limit_mb) return;
190   uptr total_mmaped =
191       atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
192   // Since for now mmap_limit_mb is not a user-facing flag, just kill
193   // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
194   RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
195 }
196 
197 void DecreaseTotalMmap(uptr size) {
198   if (!common_flags()->mmap_limit_mb) return;
199   atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
200 }
201 
202 bool TemplateMatch(const char *templ, const char *str) {
203   if ((!str) || str[0] == 0)
204     return false;
205   bool start = false;
206   if (templ && templ[0] == '^') {
207     start = true;
208     templ++;
209   }
210   bool asterisk = false;
211   while (templ && templ[0]) {
212     if (templ[0] == '*') {
213       templ++;
214       start = false;
215       asterisk = true;
216       continue;
217     }
218     if (templ[0] == '$')
219       return str[0] == 0 || asterisk;
220     if (str[0] == 0)
221       return false;
222     char *tpos = (char*)internal_strchr(templ, '*');
223     char *tpos1 = (char*)internal_strchr(templ, '$');
224     if ((!tpos) || (tpos1 && tpos1 < tpos))
225       tpos = tpos1;
226     if (tpos)
227       tpos[0] = 0;
228     const char *str0 = str;
229     const char *spos = internal_strstr(str, templ);
230     str = spos + internal_strlen(templ);
231     templ = tpos;
232     if (tpos)
233       tpos[0] = tpos == tpos1 ? '$' : '*';
234     if (!spos)
235       return false;
236     if (start && spos != str0)
237       return false;
238     start = false;
239     asterisk = false;
240   }
241   return true;
242 }
243 
244 static char binary_name_cache_str[kMaxPathLength];
245 static char process_name_cache_str[kMaxPathLength];
246 
247 const char *GetProcessName() {
248   return process_name_cache_str;
249 }
250 
251 static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
252   ReadLongProcessName(buf, buf_len);
253   char *s = const_cast<char *>(StripModuleName(buf));
254   uptr len = internal_strlen(s);
255   if (s != buf) {
256     internal_memmove(buf, s, len);
257     buf[len] = '\0';
258   }
259   return len;
260 }
261 
262 void UpdateProcessName() {
263   ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
264 }
265 
266 // Call once to make sure that binary_name_cache_str is initialized
267 void CacheBinaryName() {
268   if (binary_name_cache_str[0] != '\0')
269     return;
270   ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
271   ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
272 }
273 
274 uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
275   CacheBinaryName();
276   uptr name_len = internal_strlen(binary_name_cache_str);
277   name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
278   if (buf_len == 0)
279     return 0;
280   internal_memcpy(buf, binary_name_cache_str, name_len);
281   buf[name_len] = '\0';
282   return name_len;
283 }
284 
285 uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
286   ReadBinaryNameCached(buf, buf_len);
287   const char *exec_name_pos = StripModuleName(buf);
288   uptr name_len = exec_name_pos - buf;
289   buf[name_len] = '\0';
290   return name_len;
291 }
292 
293 #if !SANITIZER_GO
294 void PrintCmdline() {
295   char **argv = GetArgv();
296   if (!argv) return;
297   Printf("\nCommand: ");
298   for (uptr i = 0; argv[i]; ++i)
299     Printf("%s ", argv[i]);
300   Printf("\n\n");
301 }
302 #endif
303 
304 // Malloc hooks.
305 static const int kMaxMallocFreeHooks = 5;
306 struct MallocFreeHook {
307   void (*malloc_hook)(const void *, uptr);
308   void (*free_hook)(const void *);
309 };
310 
311 static MallocFreeHook MFHooks[kMaxMallocFreeHooks];
312 
313 void RunMallocHooks(void *ptr, uptr size) {
314   __sanitizer_malloc_hook(ptr, size);
315   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
316     auto hook = MFHooks[i].malloc_hook;
317     if (!hook)
318       break;
319     hook(ptr, size);
320   }
321 }
322 
323 void RunFreeHooks(void *ptr) {
324   __sanitizer_free_hook(ptr);
325   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
326     auto hook = MFHooks[i].free_hook;
327     if (!hook)
328       break;
329     hook(ptr);
330   }
331 }
332 
333 static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
334                                   void (*free_hook)(const void *)) {
335   if (!malloc_hook || !free_hook) return 0;
336   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
337     if (MFHooks[i].malloc_hook == nullptr) {
338       MFHooks[i].malloc_hook = malloc_hook;
339       MFHooks[i].free_hook = free_hook;
340       return i + 1;
341     }
342   }
343   return 0;
344 }
345 
346 void internal_sleep(unsigned seconds) {
347   internal_usleep((u64)seconds * 1000 * 1000);
348 }
349 void SleepForSeconds(unsigned seconds) {
350   internal_usleep((u64)seconds * 1000 * 1000);
351 }
352 void SleepForMillis(unsigned millis) { internal_usleep((u64)millis * 1000); }
353 
354 } // namespace __sanitizer
355 
356 using namespace __sanitizer;
357 
358 extern "C" {
359 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,
360                              const char *error_summary) {
361   Printf("%s\n", error_summary);
362 }
363 
364 SANITIZER_INTERFACE_ATTRIBUTE
365 int __sanitizer_acquire_crash_state() {
366   static atomic_uint8_t in_crash_state = {};
367   return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed);
368 }
369 
370 SANITIZER_INTERFACE_ATTRIBUTE
371 int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
372                                                                   uptr),
373                                               void (*free_hook)(const void *)) {
374   return InstallMallocFreeHooks(malloc_hook, free_hook);
375 }
376 
377 // Provide default (no-op) implementation of malloc hooks.
378 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr,
379                              uptr size) {
380   (void)ptr;
381   (void)size;
382 }
383 
384 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {
385   (void)ptr;
386 }
387 
388 } // extern "C"
389