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