brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.7 KiB · c974f54 Raw
709 lines · cpp
1//===-- tsan_platform_linux.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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of ThreadSanitizer (TSan), a race detector.10//11// Linux- and BSD-specific code.12//===----------------------------------------------------------------------===//13 14#include "sanitizer_common/sanitizer_platform.h"15#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD16 17#include "sanitizer_common/sanitizer_common.h"18#include "sanitizer_common/sanitizer_libc.h"19#include "sanitizer_common/sanitizer_linux.h"20#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"21#include "sanitizer_common/sanitizer_platform_limits_posix.h"22#include "sanitizer_common/sanitizer_posix.h"23#include "sanitizer_common/sanitizer_procmaps.h"24#include "sanitizer_common/sanitizer_stackdepot.h"25#include "sanitizer_common/sanitizer_stoptheworld.h"26#include "tsan_flags.h"27#include "tsan_platform.h"28#include "tsan_rtl.h"29 30#include <fcntl.h>31#include <pthread.h>32#include <signal.h>33#include <stdio.h>34#include <stdlib.h>35#include <string.h>36#include <stdarg.h>37#include <sys/mman.h>38#if SANITIZER_LINUX39#include <sys/personality.h>40#include <setjmp.h>41#endif42#include <sys/syscall.h>43#include <sys/socket.h>44#include <sys/time.h>45#include <sys/types.h>46#include <sys/resource.h>47#include <sys/stat.h>48#include <unistd.h>49#include <sched.h>50#include <dlfcn.h>51#if SANITIZER_LINUX52#define __need_res_state53#include <resolv.h>54#endif55 56#ifdef sa_handler57# undef sa_handler58#endif59 60#ifdef sa_sigaction61# undef sa_sigaction62#endif63 64#if SANITIZER_FREEBSD65extern "C" void *__libc_stack_end;66void *__libc_stack_end = 0;67#endif68 69#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64)) && \70    !SANITIZER_GO71# define INIT_LONGJMP_XOR_KEY 172#else73# define INIT_LONGJMP_XOR_KEY 074#endif75 76#if INIT_LONGJMP_XOR_KEY77#include "interception/interception.h"78// Must be declared outside of other namespaces.79DECLARE_REAL(int, _setjmp, void *env)80#endif81 82namespace __tsan {83 84#if INIT_LONGJMP_XOR_KEY85static void InitializeLongjmpXorKey();86static uptr longjmp_xor_key;87#endif88 89// Runtime detected VMA size.90uptr vmaSize;91 92enum {93  MemTotal,94  MemShadow,95  MemMeta,96  MemFile,97  MemMmap,98  MemHeap,99  MemOther,100  MemCount,101};102 103void FillProfileCallback(uptr p, uptr rss, bool file, uptr *mem) {104  mem[MemTotal] += rss;105  if (p >= ShadowBeg() && p < ShadowEnd())106    mem[MemShadow] += rss;107  else if (p >= MetaShadowBeg() && p < MetaShadowEnd())108    mem[MemMeta] += rss;109  else if ((p >= LoAppMemBeg() && p < LoAppMemEnd()) ||110           (p >= MidAppMemBeg() && p < MidAppMemEnd()) ||111           (p >= HiAppMemBeg() && p < HiAppMemEnd()))112    mem[file ? MemFile : MemMmap] += rss;113  else if (p >= HeapMemBeg() && p < HeapMemEnd())114    mem[MemHeap] += rss;115  else116    mem[MemOther] += rss;117}118 119void WriteMemoryProfile(char *buf, uptr buf_size, u64 uptime_ns) {120  uptr mem[MemCount];121  internal_memset(mem, 0, sizeof(mem));122  GetMemoryProfile(FillProfileCallback, mem);123  auto meta = ctx->metamap.GetMemoryStats();124  StackDepotStats stacks = StackDepotGetStats();125  uptr nthread, nlive;126  ctx->thread_registry.GetNumberOfThreads(&nthread, &nlive);127  uptr trace_mem;128  {129    Lock l(&ctx->slot_mtx);130    trace_mem = ctx->trace_part_total_allocated * sizeof(TracePart);131  }132  uptr internal_stats[AllocatorStatCount];133  internal_allocator()->GetStats(internal_stats);134  // All these are allocated from the common mmap region.135  mem[MemMmap] -= meta.mem_block + meta.sync_obj + trace_mem +136                  stacks.allocated + internal_stats[AllocatorStatMapped];137  if (s64(mem[MemMmap]) < 0)138    mem[MemMmap] = 0;139  internal_snprintf(140      buf, buf_size,141      "==%zu== %llus [%zu]: RSS %zd MB: shadow:%zd meta:%zd file:%zd"142      " mmap:%zd heap:%zd other:%zd intalloc:%zd memblocks:%zd syncobj:%zu"143      " trace:%zu stacks=%zd threads=%zu/%zu\n",144      internal_getpid(), uptime_ns / (1000 * 1000 * 1000), ctx->global_epoch,145      mem[MemTotal] >> 20, mem[MemShadow] >> 20, mem[MemMeta] >> 20,146      mem[MemFile] >> 20, mem[MemMmap] >> 20, mem[MemHeap] >> 20,147      mem[MemOther] >> 20, internal_stats[AllocatorStatMapped] >> 20,148      meta.mem_block >> 20, meta.sync_obj >> 20, trace_mem >> 20,149      stacks.allocated >> 20, nlive, nthread);150}151 152#if !SANITIZER_GO153// Mark shadow for .rodata sections with the special Shadow::kRodata marker.154// Accesses to .rodata can't race, so this saves time, memory and trace space.155static NOINLINE void MapRodata(char* buffer, uptr size) {156  // First create temp file.157  const char *tmpdir = GetEnv("TMPDIR");158  if (tmpdir == 0)159    tmpdir = GetEnv("TEST_TMPDIR");160#ifdef P_tmpdir161  if (tmpdir == 0)162    tmpdir = P_tmpdir;163#endif164  if (tmpdir == 0)165    return;166  internal_snprintf(buffer, size, "%s/tsan.rodata.%d",167                    tmpdir, (int)internal_getpid());168  uptr openrv = internal_open(buffer, O_RDWR | O_CREAT | O_EXCL, 0600);169  if (internal_iserror(openrv))170    return;171  internal_unlink(buffer);  // Unlink it now, so that we can reuse the buffer.172  fd_t fd = openrv;173  // Fill the file with Shadow::kRodata.174  const uptr kMarkerSize = 512 * 1024 / sizeof(RawShadow);175  InternalMmapVector<RawShadow> marker(kMarkerSize);176  // volatile to prevent insertion of memset177  for (volatile RawShadow *p = marker.data(); p < marker.data() + kMarkerSize;178       p++)179    *p = Shadow::kRodata;180  internal_write(fd, marker.data(), marker.size() * sizeof(RawShadow));181  // Map the file into memory.182  uptr page = internal_mmap(0, GetPageSizeCached(), PROT_READ | PROT_WRITE,183                            MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);184  if (internal_iserror(page)) {185    internal_close(fd);186    return;187  }188  // Map the file into shadow of .rodata sections.189  MemoryMappingLayout proc_maps(/*cache_enabled*/true);190  // Reusing the buffer 'buffer'.191  MemoryMappedSegment segment(buffer, size);192  while (proc_maps.Next(&segment)) {193    if (segment.filename[0] != 0 && segment.filename[0] != '[' &&194        segment.IsReadable() && segment.IsExecutable() &&195        !segment.IsWritable() && IsAppMem(segment.start)) {196      // Assume it's .rodata197      char *shadow_start = (char *)MemToShadow(segment.start);198      char *shadow_end = (char *)MemToShadow(segment.end);199      for (char *p = shadow_start; p < shadow_end;200           p += marker.size() * sizeof(RawShadow)) {201        internal_mmap(202            p, Min<uptr>(marker.size() * sizeof(RawShadow), shadow_end - p),203            PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);204      }205    }206  }207  internal_close(fd);208}209 210void InitializeShadowMemoryPlatform() {211  char buffer[256];  // Keep in a different frame.212  MapRodata(buffer, sizeof(buffer));213}214 215#endif  // #if !SANITIZER_GO216 217#  if !SANITIZER_GO218static void ReExecIfNeeded(bool ignore_heap) {219  // Go maps shadow memory lazily and works fine with limited address space.220  // Unlimited stack is not a problem as well, because the executable221  // is not compiled with -pie.222  bool reexec = false;223  // TSan doesn't play well with unlimited stack size (as stack224  // overlaps with shadow memory). If we detect unlimited stack size,225  // we re-exec the program with limited stack size as a best effort.226  if (StackSizeIsUnlimited()) {227    const uptr kMaxStackSize = 32 * 1024 * 1024;228    VReport(1,229            "Program is run with unlimited stack size, which wouldn't "230            "work with ThreadSanitizer.\n"231            "Re-execing with stack size limited to %zd bytes.\n",232            kMaxStackSize);233    SetStackSizeLimitInBytes(kMaxStackSize);234    reexec = true;235  }236 237  if (!AddressSpaceIsUnlimited()) {238    Report(239        "WARNING: Program is run with limited virtual address space,"240        " which wouldn't work with ThreadSanitizer.\n");241    Report("Re-execing with unlimited virtual address space.\n");242    SetAddressSpaceUnlimited();243    reexec = true;244  }245 246#    if SANITIZER_LINUX247#      if SANITIZER_ANDROID && (defined(__aarch64__) || defined(__x86_64__))248  // ASLR personality check.249  int old_personality = personality(0xffffffff);250  bool aslr_on =251      (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);252 253  // After patch "arm64: mm: support ARCH_MMAP_RND_BITS." is introduced in254  // linux kernel, the random gap between stack and mapped area is increased255  // from 128M to 36G on 39-bit aarch64. As it is almost impossible to cover256  // this big range, we should disable randomized virtual space on aarch64.257  if (aslr_on) {258    VReport(1,259            "WARNING: Program is run with randomized virtual address "260            "space, which wouldn't work with ThreadSanitizer on Android.\n"261            "Re-execing with fixed virtual address space.\n");262 263    if (personality(old_personality | ADDR_NO_RANDOMIZE) == -1) {264      Printf(265          "FATAL: ThreadSanitizer: unable to disable ASLR (perhaps "266          "sandboxing is enabled?).\n");267      Printf("FATAL: Please rerun without sandboxing and/or ASLR.\n");268      Die();269    }270 271    reexec = true;272  }273#      endif274 275  if (reexec) {276    // Don't check the address space since we're going to re-exec anyway.277  } else if (!CheckAndProtect(false, ignore_heap, false)) {278    // ASLR personality check.279    // N.B. 'personality' is sometimes forbidden by sandboxes, so we only call280    // this as a last resort (when the memory mapping is incompatible and TSan281    // would fail anyway).282    int old_personality = personality(0xffffffff);283    bool aslr_on =284        (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);285 286    if (aslr_on) {287      // Disable ASLR if the memory layout was incompatible.288      // Alternatively, we could just keep re-execing until we get lucky289      // with a compatible randomized layout, but the risk is that if it's290      // not an ASLR-related issue, we will be stuck in an infinite loop of291      // re-execing (unless we change ReExec to pass a parameter of the292      // number of retries allowed.)293      VReport(1,294              "WARNING: ThreadSanitizer: memory layout is incompatible, "295              "possibly due to high-entropy ASLR.\n"296              "Re-execing with fixed virtual address space.\n"297              "N.B. reducing ASLR entropy is preferable.\n");298 299      if (personality(old_personality | ADDR_NO_RANDOMIZE) == -1) {300        Printf(301            "FATAL: ThreadSanitizer: encountered an incompatible memory "302            "layout but was unable to disable ASLR (perhaps sandboxing is "303            "enabled?).\n");304        Printf(305            "FATAL: Please rerun with lower ASLR entropy, ASLR disabled, "306            "and/or sandboxing disabled.\n");307        Die();308      }309 310      reexec = true;311    } else {312      Printf(313          "FATAL: ThreadSanitizer: memory layout is incompatible, "314          "even though ASLR is disabled.\n"315          "Please file a bug.\n");316      DumpProcessMap();317      Die();318    }319  }320#    endif  // SANITIZER_LINUX321 322  if (reexec)323    ReExec();324}325#  endif326 327void InitializePlatformEarly() {328  vmaSize =329    (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);330#if defined(__aarch64__)331# if !SANITIZER_GO332  if (vmaSize != 39 && vmaSize != 42 && vmaSize != 48) {333    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");334    Printf("FATAL: Found %zd - Supported 39, 42 and 48\n", vmaSize);335    Die();336  }337#else338  if (vmaSize != 48) {339    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");340    Printf("FATAL: Found %zd - Supported 48\n", vmaSize);341    Die();342  }343#endif344#elif SANITIZER_LOONGARCH64345# if !SANITIZER_GO346  if (vmaSize != 47) {347    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");348    Printf("FATAL: Found %zd - Supported 47\n", vmaSize);349    Die();350  }351#    else352  if (vmaSize != 47) {353    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");354    Printf("FATAL: Found %zd - Supported 47\n", vmaSize);355    Die();356  }357#    endif358#elif defined(__powerpc64__)359# if !SANITIZER_GO360  if (vmaSize != 44 && vmaSize != 46 && vmaSize != 47) {361    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");362    Printf("FATAL: Found %zd - Supported 44, 46, and 47\n", vmaSize);363    Die();364  }365# else366  if (vmaSize != 46 && vmaSize != 47) {367    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");368    Printf("FATAL: Found %zd - Supported 46, and 47\n", vmaSize);369    Die();370  }371# endif372#elif defined(__mips64)373# if !SANITIZER_GO374  if (vmaSize != 40) {375    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");376    Printf("FATAL: Found %zd - Supported 40\n", vmaSize);377    Die();378  }379# else380  if (vmaSize != 47) {381    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");382    Printf("FATAL: Found %zd - Supported 47\n", vmaSize);383    Die();384  }385# endif386#  elif SANITIZER_RISCV64387  // the bottom half of vma is allocated for userspace388  vmaSize = vmaSize + 1;389#    if !SANITIZER_GO390  if (vmaSize != 39 && vmaSize != 48) {391    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");392    Printf("FATAL: Found %zd - Supported 39 and 48\n", vmaSize);393    Die();394  }395#    else396  if (vmaSize != 39 && vmaSize != 48) {397    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");398    Printf("FATAL: Found %zd - Supported 39 and 48\n", vmaSize);399    Die();400  }401#    endif402#  endif403 404#  if !SANITIZER_GO405  // Heap has not been allocated yet406  ReExecIfNeeded(false);407#  endif408}409 410void InitializePlatform() {411  DisableCoreDumperIfNecessary();412 413  // Go maps shadow memory lazily and works fine with limited address space.414  // Unlimited stack is not a problem as well, because the executable415  // is not compiled with -pie.416#if !SANITIZER_GO417  {418#    if INIT_LONGJMP_XOR_KEY419    // Initialize the xor key used in {sig}{set,long}jump.420    InitializeLongjmpXorKey();421#    endif422  }423 424  // We called ReExecIfNeeded() in InitializePlatformEarly(), but there are425  // intervening allocations that result in an edge case:426  // 1) InitializePlatformEarly(): memory layout is compatible427  // 2) Intervening allocations happen428  // 3) InitializePlatform(): memory layout is incompatible and fails429  //    CheckAndProtect()430#    if !SANITIZER_GO431  // Heap has already been allocated432  ReExecIfNeeded(true);433#    endif434 435  // Earlier initialization steps already re-exec'ed until we got a compatible436  // memory layout, so we don't expect any more issues here.437  if (!CheckAndProtect(true, true, true)) {438    Printf(439        "FATAL: ThreadSanitizer: unexpectedly found incompatible memory "440        "layout.\n");441    Printf("FATAL: Please file a bug.\n");442    DumpProcessMap();443    Die();444  }445 446#endif  // !SANITIZER_GO447}448 449#if !SANITIZER_GO450// Extract file descriptors passed to glibc internal __res_iclose function.451// This is required to properly "close" the fds, because we do not see internal452// closes within glibc. The code is a pure hack.453int ExtractResolvFDs(void *state, int *fds, int nfd) {454#if SANITIZER_LINUX && !SANITIZER_ANDROID455  int cnt = 0;456  struct __res_state *statp = (struct __res_state*)state;457  for (int i = 0; i < MAXNS && cnt < nfd; i++) {458    if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1)459      fds[cnt++] = statp->_u._ext.nssocks[i];460  }461  return cnt;462#else463  return 0;464#endif465}466 467// Extract file descriptors passed via UNIX domain sockets.468// This is required to properly handle "open" of these fds.469// see 'man recvmsg' and 'man 3 cmsg'.470int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {471  int res = 0;472  msghdr *msg = (msghdr*)msgp;473  struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);474  for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {475    if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)476      continue;477    int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]);478    for (int i = 0; i < n; i++) {479      fds[res++] = ((int*)CMSG_DATA(cmsg))[i];480      if (res == nfd)481        return res;482    }483  }484  return res;485}486 487// Reverse operation of libc stack pointer mangling488static uptr UnmangleLongJmpSp(uptr mangled_sp) {489#    if SANITIZER_ANDROID && INIT_LONGJMP_XOR_KEY490  if (longjmp_xor_key == 0) {491    // bionic libc initialization process: __libc_init_globals ->492    // __libc_init_vdso (calls strcmp) -> __libc_init_setjmp_cookie. strcmp is493    // intercepted by TSan, so during TSan initialization the setjmp_cookie494    // remains uninitialized. On Android, longjmp_xor_key must be set on first495    // use.496    InitializeLongjmpXorKey();497    CHECK_NE(longjmp_xor_key, 0);498  }499#    endif500 501#    if defined(__x86_64__)502#      if SANITIZER_LINUX503  // Reverse of:504  //   xor  %fs:0x30, %rsi505  //   rol  $0x11, %rsi506  uptr sp;507  asm("ror  $0x11,     %0 \n"508      "xor  %%fs:0x30, %0 \n"509      : "=r" (sp)510      : "0" (mangled_sp));511  return sp;512# else513  return mangled_sp;514# endif515#elif defined(__aarch64__)516# if SANITIZER_LINUX517  return mangled_sp ^ longjmp_xor_key;518# else519  return mangled_sp;520# endif521#elif defined(__loongarch_lp64)522  return mangled_sp ^ longjmp_xor_key;523#elif defined(__powerpc64__)524  // Reverse of:525  //   ld   r4, -28696(r13)526  //   xor  r4, r3, r4527  uptr xor_key;528  asm("ld  %0, -28696(%%r13)" : "=r" (xor_key));529  return mangled_sp ^ xor_key;530#elif defined(__mips__)531  return mangled_sp;532#    elif SANITIZER_RISCV64533  return mangled_sp;534#    elif defined(__s390x__)535  // tcbhead_t.stack_guard536  uptr xor_key = ((uptr *)__builtin_thread_pointer())[5];537  return mangled_sp ^ xor_key;538#    else539#      error "Unknown platform"540#    endif541}542 543#if SANITIZER_NETBSD544# ifdef __x86_64__545#  define LONG_JMP_SP_ENV_SLOT 6546# else547#  error unsupported548# endif549#elif defined(__powerpc__)550# define LONG_JMP_SP_ENV_SLOT 0551#elif SANITIZER_FREEBSD552# ifdef __aarch64__553#  define LONG_JMP_SP_ENV_SLOT 1554# else555#  define LONG_JMP_SP_ENV_SLOT 2556# endif557#    elif SANITIZER_ANDROID558#      ifdef __aarch64__559#        define LONG_JMP_SP_ENV_SLOT 3560#      elif SANITIZER_RISCV64561#        define LONG_JMP_SP_ENV_SLOT 3562#      elif defined(__x86_64__)563#        define LONG_JMP_SP_ENV_SLOT 6564#      else565#        error unsupported566#      endif567#    elif SANITIZER_LINUX568#      ifdef __aarch64__569#        define LONG_JMP_SP_ENV_SLOT 13570#      elif defined(__loongarch__)571#        define LONG_JMP_SP_ENV_SLOT 1572#      elif defined(__mips64)573#        define LONG_JMP_SP_ENV_SLOT 1574#      elif SANITIZER_RISCV64575#        define LONG_JMP_SP_ENV_SLOT 13576#      elif defined(__s390x__)577#        define LONG_JMP_SP_ENV_SLOT 9578#      else579#        define LONG_JMP_SP_ENV_SLOT 6580#      endif581#    endif582 583uptr ExtractLongJmpSp(uptr *env) {584  uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT];585  return UnmangleLongJmpSp(mangled_sp);586}587 588#if INIT_LONGJMP_XOR_KEY589// GLIBC mangles the function pointers in jmp_buf (used in {set,long}*jmp590// functions) by XORing them with a random key.  For AArch64 it is a global591// variable rather than a TCB one (as for x86_64/powerpc).  We obtain the key by592// issuing a setjmp and XORing the SP pointer values to derive the key.593static void InitializeLongjmpXorKey() {594  // 1. Call REAL(setjmp), which stores the mangled SP in env.595  jmp_buf env;596  REAL(_setjmp)(env);597 598  // 2. Retrieve vanilla/mangled SP.599  uptr sp;600#ifdef __loongarch__601  asm("move  %0, $sp" : "=r" (sp));602#else603  asm("mov  %0, sp" : "=r" (sp));604#endif605  uptr mangled_sp = ((uptr *)&env)[LONG_JMP_SP_ENV_SLOT];606 607  // 3. xor SPs to obtain key.608  longjmp_xor_key = mangled_sp ^ sp;609}610#endif611 612extern "C" void __tsan_tls_initialization() {}613 614void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {615  // Check that the thr object is in tls;616  const uptr thr_beg = (uptr)thr;617  const uptr thr_end = (uptr)thr + sizeof(*thr);618  CHECK_GE(thr_beg, tls_addr);619  CHECK_LE(thr_beg, tls_addr + tls_size);620  CHECK_GE(thr_end, tls_addr);621  CHECK_LE(thr_end, tls_addr + tls_size);622  // Since the thr object is huge, skip it.623  const uptr pc = StackTrace::GetNextInstructionPc(624      reinterpret_cast<uptr>(__tsan_tls_initialization));625  MemoryRangeImitateWrite(thr, pc, tls_addr, thr_beg - tls_addr);626  MemoryRangeImitateWrite(thr, pc, thr_end, tls_addr + tls_size - thr_end);627}628 629// Note: this function runs with async signals enabled,630// so it must not touch any tsan state.631int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),632                                     void (*cleanup)(void *arg), void *arg) {633  // pthread_cleanup_push/pop are hardcore macros mess.634  // We can't intercept nor call them w/o including pthread.h.635  int res;636  pthread_cleanup_push(cleanup, arg);637  res = fn(arg);638  pthread_cleanup_pop(0);639  return res;640}641#endif  // !SANITIZER_GO642 643#if !SANITIZER_GO644void ReplaceSystemMalloc() { }645#endif646 647#if !SANITIZER_GO648#if SANITIZER_ANDROID649// On Android, one thread can call intercepted functions after650// DestroyThreadState(), so add a fake thread state for "dead" threads.651static ThreadState *dead_thread_state = nullptr;652 653ThreadState *cur_thread() {654  ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());655  if (thr == nullptr) {656    __sanitizer_sigset_t emptyset;657    internal_sigfillset(&emptyset);658    __sanitizer_sigset_t oldset;659    CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));660    thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());661    if (thr == nullptr) {662      thr = reinterpret_cast<ThreadState*>(MmapOrDie(sizeof(ThreadState),663                                                     "ThreadState"));664      *get_android_tls_ptr() = reinterpret_cast<uptr>(thr);665      if (dead_thread_state == nullptr) {666        dead_thread_state = reinterpret_cast<ThreadState*>(667            MmapOrDie(sizeof(ThreadState), "ThreadState"));668        dead_thread_state->fast_state.SetIgnoreBit();669        dead_thread_state->ignore_interceptors = 1;670        dead_thread_state->is_dead = true;671        *const_cast<u32*>(&dead_thread_state->tid) = -1;672        CHECK_EQ(0, internal_mprotect(dead_thread_state, sizeof(ThreadState),673                                      PROT_READ));674      }675    }676    CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));677  }678 679  // Skia calls mallopt(M_THREAD_DISABLE_MEM_INIT, 1), which sets the least680  // significant bit of TLS_SLOT_SANITIZER to 1. Scudo allocator uses this bit681  // as a flag to disable memory initialization. This is a workaround to get the682  // correct ThreadState pointer.683  uptr addr = reinterpret_cast<uptr>(thr);684  return reinterpret_cast<ThreadState*>(addr & ~1ULL);685}686 687void set_cur_thread(ThreadState *thr) {688  *get_android_tls_ptr() = reinterpret_cast<uptr>(thr);689}690 691void cur_thread_finalize() {692  __sanitizer_sigset_t emptyset;693  internal_sigfillset(&emptyset);694  __sanitizer_sigset_t oldset;695  CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));696  ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());697  if (thr != dead_thread_state) {698    *get_android_tls_ptr() = reinterpret_cast<uptr>(dead_thread_state);699    UnmapOrDie(thr, sizeof(ThreadState));700  }701  CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));702}703#endif  // SANITIZER_ANDROID704#endif  // if !SANITIZER_GO705 706}  // namespace __tsan707 708#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD709