xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
168d75effSDimitry Andric //===-- sanitizer_common.cpp ----------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer
1068d75effSDimitry Andric // run-time libraries.
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric 
1368d75effSDimitry Andric #include "sanitizer_common.h"
1481ad6265SDimitry Andric 
1568d75effSDimitry Andric #include "sanitizer_allocator_interface.h"
1668d75effSDimitry Andric #include "sanitizer_allocator_internal.h"
1768d75effSDimitry Andric #include "sanitizer_atomic.h"
1868d75effSDimitry Andric #include "sanitizer_flags.h"
1981ad6265SDimitry Andric #include "sanitizer_interface_internal.h"
2068d75effSDimitry Andric #include "sanitizer_libc.h"
2168d75effSDimitry Andric #include "sanitizer_placement_new.h"
2268d75effSDimitry Andric 
2368d75effSDimitry Andric namespace __sanitizer {
2468d75effSDimitry Andric 
2568d75effSDimitry Andric const char *SanitizerToolName = "SanitizerTool";
2668d75effSDimitry Andric 
2768d75effSDimitry Andric atomic_uint32_t current_verbosity;
2868d75effSDimitry Andric uptr PageSizeCached;
2968d75effSDimitry Andric u32 NumberOfCPUsCached;
3068d75effSDimitry Andric 
3168d75effSDimitry Andric // PID of the tracer task in StopTheWorld. It shares the address space with the
3268d75effSDimitry Andric // main process, but has a different PID and thus requires special handling.
3368d75effSDimitry Andric uptr stoptheworld_tracer_pid = 0;
3468d75effSDimitry Andric // Cached pid of parent process - if the parent process dies, we want to keep
3568d75effSDimitry Andric // writing to the same log file.
3668d75effSDimitry Andric uptr stoptheworld_tracer_ppid = 0;
3768d75effSDimitry Andric 
3868d75effSDimitry Andric void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
3968d75effSDimitry Andric                                       const char *mmap_type, error_t err,
4068d75effSDimitry Andric                                       bool raw_report) {
4168d75effSDimitry Andric   static int recursion_count;
42fe6060f1SDimitry Andric   if (raw_report || recursion_count) {
43fe6060f1SDimitry Andric     // If raw report is requested or we went into recursion just die.  The
44fe6060f1SDimitry Andric     // Report() and CHECK calls below may call mmap recursively and fail.
4568d75effSDimitry Andric     RawWrite("ERROR: Failed to mmap\n");
4668d75effSDimitry Andric     Die();
4768d75effSDimitry Andric   }
4868d75effSDimitry Andric   recursion_count++;
4981ad6265SDimitry Andric   if (ErrorIsOOM(err)) {
5081ad6265SDimitry Andric     ERROR_OOM("failed to %s 0x%zx (%zd) bytes of %s (error code: %d)\n",
5181ad6265SDimitry Andric               mmap_type, size, size, mem_type, err);
5281ad6265SDimitry Andric   } else {
5381ad6265SDimitry Andric     Report(
5481ad6265SDimitry Andric         "ERROR: %s failed to "
5568d75effSDimitry Andric         "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
5668d75effSDimitry Andric         SanitizerToolName, mmap_type, size, size, mem_type, err);
5781ad6265SDimitry Andric   }
5868d75effSDimitry Andric #if !SANITIZER_GO
5968d75effSDimitry Andric   DumpProcessMap();
6068d75effSDimitry Andric #endif
6168d75effSDimitry Andric   UNREACHABLE("unable to mmap");
6268d75effSDimitry Andric }
6368d75effSDimitry Andric 
6406c3fb27SDimitry Andric void NORETURN ReportMunmapFailureAndDie(void *addr, uptr size, error_t err,
6506c3fb27SDimitry Andric                                         bool raw_report) {
6606c3fb27SDimitry Andric   static int recursion_count;
6706c3fb27SDimitry Andric   if (raw_report || recursion_count) {
6806c3fb27SDimitry Andric     // If raw report is requested or we went into recursion just die.  The
6906c3fb27SDimitry Andric     // Report() and CHECK calls below may call munmap recursively and fail.
7006c3fb27SDimitry Andric     RawWrite("ERROR: Failed to munmap\n");
7106c3fb27SDimitry Andric     Die();
7206c3fb27SDimitry Andric   }
7306c3fb27SDimitry Andric   recursion_count++;
7406c3fb27SDimitry Andric   Report(
7506c3fb27SDimitry Andric       "ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p (error "
7606c3fb27SDimitry Andric       "code: %d)\n",
7706c3fb27SDimitry Andric       SanitizerToolName, size, size, addr, err);
7806c3fb27SDimitry Andric #if !SANITIZER_GO
7906c3fb27SDimitry Andric   DumpProcessMap();
8006c3fb27SDimitry Andric #endif
8106c3fb27SDimitry Andric   UNREACHABLE("unable to unmmap");
8206c3fb27SDimitry Andric }
8306c3fb27SDimitry Andric 
8468d75effSDimitry Andric typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
8568d75effSDimitry Andric typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);
8668d75effSDimitry Andric 
8768d75effSDimitry Andric const char *StripPathPrefix(const char *filepath,
8868d75effSDimitry Andric                             const char *strip_path_prefix) {
8968d75effSDimitry Andric   if (!filepath) return nullptr;
9068d75effSDimitry Andric   if (!strip_path_prefix) return filepath;
9168d75effSDimitry Andric   const char *res = filepath;
9268d75effSDimitry Andric   if (const char *pos = internal_strstr(filepath, strip_path_prefix))
9368d75effSDimitry Andric     res = pos + internal_strlen(strip_path_prefix);
9468d75effSDimitry Andric   if (res[0] == '.' && res[1] == '/')
9568d75effSDimitry Andric     res += 2;
9668d75effSDimitry Andric   return res;
9768d75effSDimitry Andric }
9868d75effSDimitry Andric 
9968d75effSDimitry Andric const char *StripModuleName(const char *module) {
10068d75effSDimitry Andric   if (!module)
10168d75effSDimitry Andric     return nullptr;
10268d75effSDimitry Andric   if (SANITIZER_WINDOWS) {
10368d75effSDimitry Andric     // On Windows, both slash and backslash are possible.
10468d75effSDimitry Andric     // Pick the one that goes last.
10568d75effSDimitry Andric     if (const char *bslash_pos = internal_strrchr(module, '\\'))
10668d75effSDimitry Andric       return StripModuleName(bslash_pos + 1);
10768d75effSDimitry Andric   }
10868d75effSDimitry Andric   if (const char *slash_pos = internal_strrchr(module, '/')) {
10968d75effSDimitry Andric     return slash_pos + 1;
11068d75effSDimitry Andric   }
11168d75effSDimitry Andric   return module;
11268d75effSDimitry Andric }
11368d75effSDimitry Andric 
11468d75effSDimitry Andric void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
11568d75effSDimitry Andric   if (!common_flags()->print_summary)
11668d75effSDimitry Andric     return;
117fe6060f1SDimitry Andric   InternalScopedString buff;
1185f757f3fSDimitry Andric   buff.AppendF("SUMMARY: %s: %s",
1195f757f3fSDimitry Andric                alt_tool_name ? alt_tool_name : SanitizerToolName,
1205f757f3fSDimitry Andric                error_message);
12168d75effSDimitry Andric   __sanitizer_report_error_summary(buff.data());
12268d75effSDimitry Andric }
12368d75effSDimitry Andric 
12468d75effSDimitry Andric // Removes the ANSI escape sequences from the input string (in-place).
12568d75effSDimitry Andric void RemoveANSIEscapeSequencesFromString(char *str) {
12668d75effSDimitry Andric   if (!str)
12768d75effSDimitry Andric     return;
12868d75effSDimitry Andric 
12968d75effSDimitry Andric   // We are going to remove the escape sequences in place.
13068d75effSDimitry Andric   char *s = str;
13168d75effSDimitry Andric   char *z = str;
13268d75effSDimitry Andric   while (*s != '\0') {
13368d75effSDimitry Andric     CHECK_GE(s, z);
13468d75effSDimitry Andric     // Skip over ANSI escape sequences with pointer 's'.
13568d75effSDimitry Andric     if (*s == '\033' && *(s + 1) == '[') {
13668d75effSDimitry Andric       s = internal_strchrnul(s, 'm');
13768d75effSDimitry Andric       if (*s == '\0') {
13868d75effSDimitry Andric         break;
13968d75effSDimitry Andric       }
14068d75effSDimitry Andric       s++;
14168d75effSDimitry Andric       continue;
14268d75effSDimitry Andric     }
14368d75effSDimitry Andric     // 's' now points at a character we want to keep. Copy over the buffer
14468d75effSDimitry Andric     // content if the escape sequence has been perviously skipped andadvance
14568d75effSDimitry Andric     // both pointers.
14668d75effSDimitry Andric     if (s != z)
14768d75effSDimitry Andric       *z = *s;
14868d75effSDimitry Andric 
14968d75effSDimitry Andric     // If we have not seen an escape sequence, just advance both pointers.
15068d75effSDimitry Andric     z++;
15168d75effSDimitry Andric     s++;
15268d75effSDimitry Andric   }
15368d75effSDimitry Andric 
15468d75effSDimitry Andric   // Null terminate the string.
15568d75effSDimitry Andric   *z = '\0';
15668d75effSDimitry Andric }
15768d75effSDimitry Andric 
15868d75effSDimitry Andric void LoadedModule::set(const char *module_name, uptr base_address) {
15968d75effSDimitry Andric   clear();
16068d75effSDimitry Andric   full_name_ = internal_strdup(module_name);
16168d75effSDimitry Andric   base_address_ = base_address;
16268d75effSDimitry Andric }
16368d75effSDimitry Andric 
16468d75effSDimitry Andric void LoadedModule::set(const char *module_name, uptr base_address,
16568d75effSDimitry Andric                        ModuleArch arch, u8 uuid[kModuleUUIDSize],
16668d75effSDimitry Andric                        bool instrumented) {
16768d75effSDimitry Andric   set(module_name, base_address);
16868d75effSDimitry Andric   arch_ = arch;
16968d75effSDimitry Andric   internal_memcpy(uuid_, uuid, sizeof(uuid_));
1700eae32dcSDimitry Andric   uuid_size_ = kModuleUUIDSize;
17168d75effSDimitry Andric   instrumented_ = instrumented;
17268d75effSDimitry Andric }
17368d75effSDimitry Andric 
1740eae32dcSDimitry Andric void LoadedModule::setUuid(const char *uuid, uptr size) {
1750eae32dcSDimitry Andric   if (size > kModuleUUIDSize)
1760eae32dcSDimitry Andric     size = kModuleUUIDSize;
1770eae32dcSDimitry Andric   internal_memcpy(uuid_, uuid, size);
1780eae32dcSDimitry Andric   uuid_size_ = size;
1790eae32dcSDimitry Andric }
1800eae32dcSDimitry Andric 
18168d75effSDimitry Andric void LoadedModule::clear() {
18268d75effSDimitry Andric   InternalFree(full_name_);
18368d75effSDimitry Andric   base_address_ = 0;
18481ad6265SDimitry Andric   max_address_ = 0;
18568d75effSDimitry Andric   full_name_ = nullptr;
18668d75effSDimitry Andric   arch_ = kModuleArchUnknown;
18768d75effSDimitry Andric   internal_memset(uuid_, 0, kModuleUUIDSize);
18868d75effSDimitry Andric   instrumented_ = false;
18968d75effSDimitry Andric   while (!ranges_.empty()) {
19068d75effSDimitry Andric     AddressRange *r = ranges_.front();
19168d75effSDimitry Andric     ranges_.pop_front();
19268d75effSDimitry Andric     InternalFree(r);
19368d75effSDimitry Andric   }
19468d75effSDimitry Andric }
19568d75effSDimitry Andric 
19668d75effSDimitry Andric void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,
19768d75effSDimitry Andric                                    bool writable, const char *name) {
19868d75effSDimitry Andric   void *mem = InternalAlloc(sizeof(AddressRange));
19968d75effSDimitry Andric   AddressRange *r =
20068d75effSDimitry Andric       new(mem) AddressRange(beg, end, executable, writable, name);
20168d75effSDimitry Andric   ranges_.push_back(r);
20281ad6265SDimitry Andric   max_address_ = Max(max_address_, end);
20368d75effSDimitry Andric }
20468d75effSDimitry Andric 
20568d75effSDimitry Andric bool LoadedModule::containsAddress(uptr address) const {
20668d75effSDimitry Andric   for (const AddressRange &r : ranges()) {
20768d75effSDimitry Andric     if (r.beg <= address && address < r.end)
20868d75effSDimitry Andric       return true;
20968d75effSDimitry Andric   }
21068d75effSDimitry Andric   return false;
21168d75effSDimitry Andric }
21268d75effSDimitry Andric 
21368d75effSDimitry Andric static atomic_uintptr_t g_total_mmaped;
21468d75effSDimitry Andric 
21568d75effSDimitry Andric void IncreaseTotalMmap(uptr size) {
21668d75effSDimitry Andric   if (!common_flags()->mmap_limit_mb) return;
21768d75effSDimitry Andric   uptr total_mmaped =
21868d75effSDimitry Andric       atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
21968d75effSDimitry Andric   // Since for now mmap_limit_mb is not a user-facing flag, just kill
22068d75effSDimitry Andric   // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
22168d75effSDimitry Andric   RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
22268d75effSDimitry Andric }
22368d75effSDimitry Andric 
22468d75effSDimitry Andric void DecreaseTotalMmap(uptr size) {
22568d75effSDimitry Andric   if (!common_flags()->mmap_limit_mb) return;
22668d75effSDimitry Andric   atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
22768d75effSDimitry Andric }
22868d75effSDimitry Andric 
22968d75effSDimitry Andric bool TemplateMatch(const char *templ, const char *str) {
23068d75effSDimitry Andric   if ((!str) || str[0] == 0)
23168d75effSDimitry Andric     return false;
23268d75effSDimitry Andric   bool start = false;
23368d75effSDimitry Andric   if (templ && templ[0] == '^') {
23468d75effSDimitry Andric     start = true;
23568d75effSDimitry Andric     templ++;
23668d75effSDimitry Andric   }
23768d75effSDimitry Andric   bool asterisk = false;
23868d75effSDimitry Andric   while (templ && templ[0]) {
23968d75effSDimitry Andric     if (templ[0] == '*') {
24068d75effSDimitry Andric       templ++;
24168d75effSDimitry Andric       start = false;
24268d75effSDimitry Andric       asterisk = true;
24368d75effSDimitry Andric       continue;
24468d75effSDimitry Andric     }
24568d75effSDimitry Andric     if (templ[0] == '$')
24668d75effSDimitry Andric       return str[0] == 0 || asterisk;
24768d75effSDimitry Andric     if (str[0] == 0)
24868d75effSDimitry Andric       return false;
24968d75effSDimitry Andric     char *tpos = (char*)internal_strchr(templ, '*');
25068d75effSDimitry Andric     char *tpos1 = (char*)internal_strchr(templ, '$');
25168d75effSDimitry Andric     if ((!tpos) || (tpos1 && tpos1 < tpos))
25268d75effSDimitry Andric       tpos = tpos1;
25368d75effSDimitry Andric     if (tpos)
25468d75effSDimitry Andric       tpos[0] = 0;
25568d75effSDimitry Andric     const char *str0 = str;
25668d75effSDimitry Andric     const char *spos = internal_strstr(str, templ);
25768d75effSDimitry Andric     str = spos + internal_strlen(templ);
25868d75effSDimitry Andric     templ = tpos;
25968d75effSDimitry Andric     if (tpos)
26068d75effSDimitry Andric       tpos[0] = tpos == tpos1 ? '$' : '*';
26168d75effSDimitry Andric     if (!spos)
26268d75effSDimitry Andric       return false;
26368d75effSDimitry Andric     if (start && spos != str0)
26468d75effSDimitry Andric       return false;
26568d75effSDimitry Andric     start = false;
26668d75effSDimitry Andric     asterisk = false;
26768d75effSDimitry Andric   }
26868d75effSDimitry Andric   return true;
26968d75effSDimitry Andric }
27068d75effSDimitry Andric 
27168d75effSDimitry Andric static char binary_name_cache_str[kMaxPathLength];
27268d75effSDimitry Andric static char process_name_cache_str[kMaxPathLength];
27368d75effSDimitry Andric 
27468d75effSDimitry Andric const char *GetProcessName() {
27568d75effSDimitry Andric   return process_name_cache_str;
27668d75effSDimitry Andric }
27768d75effSDimitry Andric 
27868d75effSDimitry Andric static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
27968d75effSDimitry Andric   ReadLongProcessName(buf, buf_len);
28068d75effSDimitry Andric   char *s = const_cast<char *>(StripModuleName(buf));
28168d75effSDimitry Andric   uptr len = internal_strlen(s);
28268d75effSDimitry Andric   if (s != buf) {
28368d75effSDimitry Andric     internal_memmove(buf, s, len);
28468d75effSDimitry Andric     buf[len] = '\0';
28568d75effSDimitry Andric   }
28668d75effSDimitry Andric   return len;
28768d75effSDimitry Andric }
28868d75effSDimitry Andric 
28968d75effSDimitry Andric void UpdateProcessName() {
29068d75effSDimitry Andric   ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
29168d75effSDimitry Andric }
29268d75effSDimitry Andric 
29368d75effSDimitry Andric // Call once to make sure that binary_name_cache_str is initialized
29468d75effSDimitry Andric void CacheBinaryName() {
29568d75effSDimitry Andric   if (binary_name_cache_str[0] != '\0')
29668d75effSDimitry Andric     return;
29768d75effSDimitry Andric   ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
29868d75effSDimitry Andric   ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
29968d75effSDimitry Andric }
30068d75effSDimitry Andric 
30168d75effSDimitry Andric uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
30268d75effSDimitry Andric   CacheBinaryName();
30368d75effSDimitry Andric   uptr name_len = internal_strlen(binary_name_cache_str);
30468d75effSDimitry Andric   name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
30568d75effSDimitry Andric   if (buf_len == 0)
30668d75effSDimitry Andric     return 0;
30768d75effSDimitry Andric   internal_memcpy(buf, binary_name_cache_str, name_len);
30868d75effSDimitry Andric   buf[name_len] = '\0';
30968d75effSDimitry Andric   return name_len;
31068d75effSDimitry Andric }
31168d75effSDimitry Andric 
312fe6060f1SDimitry Andric uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
313fe6060f1SDimitry Andric   ReadBinaryNameCached(buf, buf_len);
314fe6060f1SDimitry Andric   const char *exec_name_pos = StripModuleName(buf);
315fe6060f1SDimitry Andric   uptr name_len = exec_name_pos - buf;
316fe6060f1SDimitry Andric   buf[name_len] = '\0';
317fe6060f1SDimitry Andric   return name_len;
318fe6060f1SDimitry Andric }
319fe6060f1SDimitry Andric 
3205ffd83dbSDimitry Andric #if !SANITIZER_GO
32168d75effSDimitry Andric void PrintCmdline() {
32268d75effSDimitry Andric   char **argv = GetArgv();
32368d75effSDimitry Andric   if (!argv) return;
32468d75effSDimitry Andric   Printf("\nCommand: ");
32568d75effSDimitry Andric   for (uptr i = 0; argv[i]; ++i)
32668d75effSDimitry Andric     Printf("%s ", argv[i]);
32768d75effSDimitry Andric   Printf("\n\n");
32868d75effSDimitry Andric }
3295ffd83dbSDimitry Andric #endif
33068d75effSDimitry Andric 
33168d75effSDimitry Andric // Malloc hooks.
33268d75effSDimitry Andric static const int kMaxMallocFreeHooks = 5;
33368d75effSDimitry Andric struct MallocFreeHook {
33468d75effSDimitry Andric   void (*malloc_hook)(const void *, uptr);
33568d75effSDimitry Andric   void (*free_hook)(const void *);
33668d75effSDimitry Andric };
33768d75effSDimitry Andric 
33868d75effSDimitry Andric static MallocFreeHook MFHooks[kMaxMallocFreeHooks];
33968d75effSDimitry Andric 
34081ad6265SDimitry Andric void RunMallocHooks(void *ptr, uptr size) {
34181ad6265SDimitry Andric   __sanitizer_malloc_hook(ptr, size);
34268d75effSDimitry Andric   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
34368d75effSDimitry Andric     auto hook = MFHooks[i].malloc_hook;
34481ad6265SDimitry Andric     if (!hook)
34581ad6265SDimitry Andric       break;
34668d75effSDimitry Andric     hook(ptr, size);
34768d75effSDimitry Andric   }
34868d75effSDimitry Andric }
34968d75effSDimitry Andric 
350*0fca6ea1SDimitry Andric // Returns '1' if the call to free() should be ignored (based on
351*0fca6ea1SDimitry Andric // __sanitizer_ignore_free_hook), or '0' otherwise.
352*0fca6ea1SDimitry Andric int RunFreeHooks(void *ptr) {
353*0fca6ea1SDimitry Andric   if (__sanitizer_ignore_free_hook(ptr)) {
354*0fca6ea1SDimitry Andric     return 1;
355*0fca6ea1SDimitry Andric   }
356*0fca6ea1SDimitry Andric 
35781ad6265SDimitry Andric   __sanitizer_free_hook(ptr);
35868d75effSDimitry Andric   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
35968d75effSDimitry Andric     auto hook = MFHooks[i].free_hook;
36081ad6265SDimitry Andric     if (!hook)
36181ad6265SDimitry Andric       break;
36268d75effSDimitry Andric     hook(ptr);
36368d75effSDimitry Andric   }
364*0fca6ea1SDimitry Andric 
365*0fca6ea1SDimitry Andric   return 0;
36668d75effSDimitry Andric }
36768d75effSDimitry Andric 
36868d75effSDimitry Andric static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
36968d75effSDimitry Andric                                   void (*free_hook)(const void *)) {
37068d75effSDimitry Andric   if (!malloc_hook || !free_hook) return 0;
37168d75effSDimitry Andric   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
37268d75effSDimitry Andric     if (MFHooks[i].malloc_hook == nullptr) {
37368d75effSDimitry Andric       MFHooks[i].malloc_hook = malloc_hook;
37468d75effSDimitry Andric       MFHooks[i].free_hook = free_hook;
37568d75effSDimitry Andric       return i + 1;
37668d75effSDimitry Andric     }
37768d75effSDimitry Andric   }
37868d75effSDimitry Andric   return 0;
37968d75effSDimitry Andric }
38068d75effSDimitry Andric 
381fe6060f1SDimitry Andric void internal_sleep(unsigned seconds) {
382fe6060f1SDimitry Andric   internal_usleep((u64)seconds * 1000 * 1000);
383fe6060f1SDimitry Andric }
384fe6060f1SDimitry Andric void SleepForSeconds(unsigned seconds) {
385fe6060f1SDimitry Andric   internal_usleep((u64)seconds * 1000 * 1000);
386fe6060f1SDimitry Andric }
387fe6060f1SDimitry Andric void SleepForMillis(unsigned millis) { internal_usleep((u64)millis * 1000); }
388fe6060f1SDimitry Andric 
38981ad6265SDimitry Andric void WaitForDebugger(unsigned seconds, const char *label) {
39081ad6265SDimitry Andric   if (seconds) {
39181ad6265SDimitry Andric     Report("Sleeping for %u second(s) %s\n", seconds, label);
39281ad6265SDimitry Andric     SleepForSeconds(seconds);
39381ad6265SDimitry Andric   }
39481ad6265SDimitry Andric }
39581ad6265SDimitry Andric 
39668d75effSDimitry Andric } // namespace __sanitizer
39768d75effSDimitry Andric 
39868d75effSDimitry Andric using namespace __sanitizer;
39968d75effSDimitry Andric 
40068d75effSDimitry Andric extern "C" {
40168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,
40268d75effSDimitry Andric                              const char *error_summary) {
40368d75effSDimitry Andric   Printf("%s\n", error_summary);
40468d75effSDimitry Andric }
40568d75effSDimitry Andric 
40668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
40768d75effSDimitry Andric int __sanitizer_acquire_crash_state() {
40868d75effSDimitry Andric   static atomic_uint8_t in_crash_state = {};
40968d75effSDimitry Andric   return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed);
41068d75effSDimitry Andric }
41168d75effSDimitry Andric 
41268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
41368d75effSDimitry Andric int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
41468d75effSDimitry Andric                                                                   uptr),
41568d75effSDimitry Andric                                               void (*free_hook)(const void *)) {
41668d75effSDimitry Andric   return InstallMallocFreeHooks(malloc_hook, free_hook);
41768d75effSDimitry Andric }
41881ad6265SDimitry Andric 
41981ad6265SDimitry Andric // Provide default (no-op) implementation of malloc hooks.
42081ad6265SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr,
42181ad6265SDimitry Andric                              uptr size) {
42281ad6265SDimitry Andric   (void)ptr;
42381ad6265SDimitry Andric   (void)size;
42481ad6265SDimitry Andric }
42581ad6265SDimitry Andric 
42681ad6265SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {
42781ad6265SDimitry Andric   (void)ptr;
42881ad6265SDimitry Andric }
42981ad6265SDimitry Andric 
430*0fca6ea1SDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(int, __sanitizer_ignore_free_hook, void *ptr) {
431*0fca6ea1SDimitry Andric   (void)ptr;
432*0fca6ea1SDimitry Andric   return 0;
433*0fca6ea1SDimitry Andric }
434*0fca6ea1SDimitry Andric 
43568d75effSDimitry Andric } // extern "C"
436