1603c4be006d8c53905d736bf1f19a49f5ce98276Alexey Samsonov//===-- tsan_platform_linux.cc --------------------------------------------===// 27ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 37ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// The LLVM Compiler Infrastructure 47ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 57ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is distributed under the University of Illinois Open Source 67ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// License. See LICENSE.TXT for details. 77ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 87ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===// 97ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is a part of ThreadSanitizer (TSan), a race detector. 117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// Linux-specific code. 137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===// 147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1524e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov 1624e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov#include "sanitizer_common/sanitizer_platform.h" 175d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#if SANITIZER_LINUX || SANITIZER_FREEBSD 183f24d6386cea638f5d4bc1694d1de02917988bcdDmitry Vyukov 1984902c716abf9ba0dc6e7b1cd0522759f29b3179Alexey Samsonov#include "sanitizer_common/sanitizer_common.h" 2048aee681c0d800deb6c00f546bfaa377ece37326Alexey Samsonov#include "sanitizer_common/sanitizer_libc.h" 2184902c716abf9ba0dc6e7b1cd0522759f29b3179Alexey Samsonov#include "sanitizer_common/sanitizer_procmaps.h" 2292b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov#include "sanitizer_common/sanitizer_stoptheworld.h" 237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_platform.h" 247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h" 257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_flags.h" 267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <fcntl.h> 287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <pthread.h> 297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <signal.h> 307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <stdio.h> 317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <stdlib.h> 327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <string.h> 337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <stdarg.h> 347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <sys/mman.h> 357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <sys/syscall.h> 362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include <sys/socket.h> 377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <sys/time.h> 387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <sys/types.h> 397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <sys/resource.h> 407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <sys/stat.h> 417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <unistd.h> 427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <errno.h> 437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <sched.h> 447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include <dlfcn.h> 455d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#if SANITIZER_LINUX 4603f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov#define __need_res_state 4703f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov#include <resolv.h> 485d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#endif 497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 5017b0a3c9b28648ca9af1844111447f231f84c180Dmitry Vyukov#ifdef sa_handler 5117b0a3c9b28648ca9af1844111447f231f84c180Dmitry Vyukov# undef sa_handler 5217b0a3c9b28648ca9af1844111447f231f84c180Dmitry Vyukov#endif 5317b0a3c9b28648ca9af1844111447f231f84c180Dmitry Vyukov 5417b0a3c9b28648ca9af1844111447f231f84c180Dmitry Vyukov#ifdef sa_sigaction 5517b0a3c9b28648ca9af1844111447f231f84c180Dmitry Vyukov# undef sa_sigaction 5617b0a3c9b28648ca9af1844111447f231f84c180Dmitry Vyukov#endif 5717b0a3c9b28648ca9af1844111447f231f84c180Dmitry Vyukov 585d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#if SANITIZER_FREEBSD 595d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesextern "C" void *__libc_stack_end; 605d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesvoid *__libc_stack_end = 0; 615d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#endif 627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan { 647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 6582dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukovconst uptr kPageSize = 4096; 6682dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov 675d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesenum { 685d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines MemTotal = 0, 695d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines MemShadow = 1, 705d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines MemMeta = 2, 715d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines MemFile = 3, 725d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines MemMmap = 4, 735d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines MemTrace = 5, 745d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines MemHeap = 6, 755d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines MemOther = 7, 765d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines MemCount = 8, 775d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines}; 785d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines 792e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenkovoid FillProfileCallback(uptr start, uptr rss, bool file, 802e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko uptr *mem, uptr stats_size) { 815d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[MemTotal] += rss; 822e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko start >>= 40; 835d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines if (start < 0x10) 845d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[MemShadow] += rss; 855d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines else if (start >= 0x20 && start < 0x30) 865d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[file ? MemFile : MemMmap] += rss; 875d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines else if (start >= 0x30 && start < 0x40) 885d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[MemMeta] += rss; 895d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines else if (start >= 0x7e) 905d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[file ? MemFile : MemMmap] += rss; 915d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines else if (start >= 0x60 && start < 0x62) 925d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[MemTrace] += rss; 935d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines else if (start >= 0x7d && start < 0x7e) 945d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[MemHeap] += rss; 955d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines else 965d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[MemOther] += rss; 975d72fc796f21fb9714722e0006d72213fb300688Dmitry Vyukov} 985d72fc796f21fb9714722e0006d72213fb300688Dmitry Vyukov 995d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesvoid WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) { 1005d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines uptr mem[MemCount] = {}; 1012e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7); 1025d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines internal_snprintf(buf, buf_size, 1035d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines "RSS %zd MB: shadow:%zd meta:%zd file:%zd mmap:%zd" 1045d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines " trace:%zd heap:%zd other:%zd nthr=%zd/%zd\n", 1055d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[MemTotal] >> 20, mem[MemShadow] >> 20, mem[MemMeta] >> 20, 1065d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[MemFile] >> 20, mem[MemMmap] >> 20, mem[MemTrace] >> 20, 1075d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines mem[MemHeap] >> 20, mem[MemOther] >> 20, 1085d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines nlive, nthread); 10926127735454fddae3495794f38189d57dde6510fDmitry Vyukov} 11026127735454fddae3495794f38189d57dde6510fDmitry Vyukov 11192b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukovuptr GetRSS() { 11292b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov uptr mem[7] = {}; 11392b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7); 11492b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov return mem[6]; 11592b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov} 11692b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov 1175d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#if SANITIZER_LINUX 11892b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukovvoid FlushShadowMemoryCallback( 11992b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov const SuspendedThreadsList &suspended_threads_list, 12092b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov void *argument) { 121a54aec8ca2e372b1a841d605d53cab5e336aeb03Kostya Serebryany FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg); 122adfb65039646774f0f063b538f8fb0aec021f42bDmitry Vyukov} 1235d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#endif 124adfb65039646774f0f063b538f8fb0aec021f42bDmitry Vyukov 12592b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukovvoid FlushShadowMemory() { 1265d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#if SANITIZER_LINUX 12792b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov StopTheWorld(FlushShadowMemoryCallback, 0); 1285d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#endif 12992b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov} 13092b54796149a8b5995fa49c43f43b709b83c5644Dmitry Vyukov 131b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#ifndef TSAN_GO 1327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void ProtectRange(uptr beg, uptr end) { 1337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_LE(beg, end); 1347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (beg == end) 1357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 13684902c716abf9ba0dc6e7b1cd0522759f29b3179Alexey Samsonov if (beg != (uptr)Mprotect(beg, end - beg)) { 137b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end); 138b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("FATAL: Make sure you are not using unlimited stack\n"); 1397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Die(); 1407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 1417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 14382dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov// Mark shadow for .rodata sections with the special kShadowRodata marker. 14482dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov// Accesses to .rodata can't race, so this saves time, memory and trace space. 14582dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukovstatic void MapRodata() { 14682dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov // First create temp file. 14782dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov const char *tmpdir = GetEnv("TMPDIR"); 14882dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov if (tmpdir == 0) 14982dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov tmpdir = GetEnv("TEST_TMPDIR"); 15082dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov#ifdef P_tmpdir 15182dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov if (tmpdir == 0) 15282dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov tmpdir = P_tmpdir; 15382dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov#endif 15482dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov if (tmpdir == 0) 15582dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov return; 1562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines char name[256]; 1572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines internal_snprintf(name, sizeof(name), "%s/tsan.rodata.%d", 1580b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne tmpdir, (int)internal_getpid()); 1592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr openrv = internal_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); 1609578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne if (internal_iserror(openrv)) 16182dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov return; 1622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines internal_unlink(name); // Unlink it now, so that we can reuse the buffer. 1639578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne fd_t fd = openrv; 16482dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov // Fill the file with kShadowRodata. 16582dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov const uptr kMarkerSize = 512 * 1024 / sizeof(u64); 16682dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov InternalScopedBuffer<u64> marker(kMarkerSize); 1672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // volatile to prevent insertion of memset 1682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (volatile u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++) 16982dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov *p = kShadowRodata; 17082dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov internal_write(fd, marker.data(), marker.size()); 17182dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov // Map the file into memory. 1729578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE, 1739578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); 1749578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne if (internal_iserror(page)) { 17582dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov internal_close(fd); 17682dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov return; 17782dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov } 17882dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov // Map the file into shadow of .rodata sections. 1799ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko MemoryMappingLayout proc_maps(/*cache_enabled*/true); 18082dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov uptr start, end, offset, prot; 1812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // Reusing the buffer 'name'. 18282dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) { 18382dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov if (name[0] != 0 && name[0] != '[' 18482dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov && (prot & MemoryMappingLayout::kProtectionRead) 18582dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov && (prot & MemoryMappingLayout::kProtectionExecute) 18682dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov && !(prot & MemoryMappingLayout::kProtectionWrite) 18782dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov && IsAppMem(start)) { 18882dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov // Assume it's .rodata 18982dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov char *shadow_start = (char*)MemToShadow(start); 19082dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov char *shadow_end = (char*)MemToShadow(end); 19182dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov for (char *p = shadow_start; p < shadow_end; p += marker.size()) { 19282dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p), 19382dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0); 19482dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov } 19582dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov } 19682dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov } 19782dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov internal_close(fd); 19882dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov} 19982dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov 2007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid InitializeShadowMemory() { 2015d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines // Map memory shadow. 20284902c716abf9ba0dc6e7b1cd0522759f29b3179Alexey Samsonov uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg, 20384902c716abf9ba0dc6e7b1cd0522759f29b3179Alexey Samsonov kLinuxShadowEnd - kLinuxShadowBeg); 2047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (shadow != kLinuxShadowBeg) { 205b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); 206b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("FATAL: Make sure to compile with -fPIE and " 2072e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg); 2087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Die(); 2097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2105d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines DPrintf("memory shadow: %zx-%zx (%zuGB)\n", 2115d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines kLinuxShadowBeg, kLinuxShadowEnd, 2125d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines (kLinuxShadowEnd - kLinuxShadowBeg) >> 30); 2135d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines 2145d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines // Map meta shadow. 2155d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines if (MemToMeta(kLinuxAppMemBeg) < (u32*)kMetaShadow) { 2165d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines Printf("ThreadSanitizer: bad meta shadow (%p -> %p < %p)\n", 2175d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines kLinuxAppMemBeg, MemToMeta(kLinuxAppMemBeg), kMetaShadow); 2185d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines Die(); 2195d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines } 2205d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines if (MemToMeta(kLinuxAppMemEnd) >= (u32*)(kMetaShadow + kMetaSize)) { 2215d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines Printf("ThreadSanitizer: bad meta shadow (%p -> %p >= %p)\n", 2225d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines kLinuxAppMemEnd, MemToMeta(kLinuxAppMemEnd), kMetaShadow + kMetaSize); 2235d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines Die(); 2245d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines } 2255d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines uptr meta = (uptr)MmapFixedNoReserve(kMetaShadow, kMetaSize); 2265d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines if (meta != kMetaShadow) { 2275d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); 2285d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines Printf("FATAL: Make sure to compile with -fPIE and " 2295d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines "to link with -pie (%p, %p).\n", meta, kMetaShadow); 2305d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines Die(); 2315d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines } 2325d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines DPrintf("meta shadow: %zx-%zx (%zuGB)\n", 2335d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines kMetaShadow, kMetaShadow + kMetaSize, kMetaSize >> 30); 2345d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines 2355d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines // Protect gaps. 236b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov const uptr kClosedLowBeg = 0x200000; 237b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov const uptr kClosedLowEnd = kLinuxShadowBeg - 1; 238b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov const uptr kClosedMidBeg = kLinuxShadowEnd + 1; 2395d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines const uptr kClosedMidEnd = min(min(kLinuxAppMemBeg, kTraceMemBegin), 2405d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines kMetaShadow); 2415d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines 2427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ProtectRange(kClosedLowBeg, kClosedLowEnd); 2437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ProtectRange(kClosedMidBeg, kClosedMidEnd); 2445d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines VPrintf(2, "kClosedLow %zx-%zx (%zuGB)\n", 2457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30); 2465d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines VPrintf(2, "kClosedMid %zx-%zx (%zuGB)\n", 2477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30); 2485d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines VPrintf(2, "app mem: %zx-%zx (%zuGB)\n", 2497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany kLinuxAppMemBeg, kLinuxAppMemEnd, 2507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30); 2515d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines VPrintf(2, "stack: %zx\n", (uptr)&shadow); 25282dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov 25382dbc5195ceedba0e1a9aab92d436614cc4b7ff9Dmitry Vyukov MapRodata(); 2547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 255a05fcc1e3e045097f2f1a20798cbe038bbb1d6a9Dmitry Vyukov#endif 2567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 2570c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukovstatic uptr g_data_start; 2580c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukovstatic uptr g_data_end; 2590c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov 260b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#ifndef TSAN_GO 2617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void CheckPIE() { 2627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // Ensure that the binary is indeed compiled with -pie. 2639ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko MemoryMappingLayout proc_maps(true); 26484902c716abf9ba0dc6e7b1cd0522759f29b3179Alexey Samsonov uptr start, end; 26584902c716abf9ba0dc6e7b1cd0522759f29b3179Alexey Samsonov if (proc_maps.Next(&start, &end, 26645717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov /*offset*/0, /*filename*/0, /*filename_size*/0, 26745717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov /*protection*/0)) { 26884902c716abf9ba0dc6e7b1cd0522759f29b3179Alexey Samsonov if ((u64)start < kLinuxAppMemBeg) { 269b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("FATAL: ThreadSanitizer can not mmap the shadow memory (" 270e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov "something is mapped at 0x%zx < 0x%zx)\n", 27184902c716abf9ba0dc6e7b1cd0522759f29b3179Alexey Samsonov start, kLinuxAppMemBeg); 272b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov Printf("FATAL: Make sure to compile with -fPIE" 2737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany " and to link with -pie.\n"); 2747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany Die(); 2757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 2777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 2787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 2790c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukovstatic void InitDataSeg() { 2809ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko MemoryMappingLayout proc_maps(true); 2810c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov uptr start, end, offset; 2820c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov char name[128]; 2830c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov bool prev_is_data = false; 28445717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), 28545717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov /*protection*/ 0)) { 2860c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov DPrintf("%p-%p %p %s\n", start, end, offset, name); 2870c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov bool is_data = offset != 0 && name[0] != 0; 28897dac9e9a15722f94724a9f61b29518698867ee8Evgeniy Stepanov // BSS may get merged with [heap] in /proc/self/maps. This is not very 28997dac9e9a15722f94724a9f61b29518698867ee8Evgeniy Stepanov // reliable. 29097dac9e9a15722f94724a9f61b29518698867ee8Evgeniy Stepanov bool is_bss = offset == 0 && 29197dac9e9a15722f94724a9f61b29518698867ee8Evgeniy Stepanov (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data; 2920c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov if (g_data_start == 0 && is_data) 2930c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov g_data_start = start; 2940c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov if (is_bss) 2950c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov g_data_end = end; 2960c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov prev_is_data = is_data; 2970c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov } 2980c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov DPrintf("guessed data_start=%p data_end=%p\n", g_data_start, g_data_end); 2990c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov CHECK_LT(g_data_start, g_data_end); 3000c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov CHECK_GE((uptr)&g_data_start, g_data_start); 3010c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov CHECK_LT((uptr)&g_data_start, g_data_end); 3020c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov} 303b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov 304b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#endif // #ifndef TSAN_GO 3057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 306d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukovstatic rlim_t getlim(int res) { 307d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov rlimit rlim; 308d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov CHECK_EQ(0, getrlimit(res, &rlim)); 309d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov return rlim.rlim_cur; 310d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov} 311d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov 312d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukovstatic void setlim(int res, rlim_t lim) { 313d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov // The following magic is to prevent clang from replacing it with memset. 314d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov volatile rlimit rlim; 315d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov rlim.rlim_cur = lim; 316d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov rlim.rlim_max = lim; 317d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov setrlimit(res, (rlimit*)&rlim); 318d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov} 319d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov 3207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyconst char *InitializePlatform() { 3217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany void *p = 0; 3227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (sizeof(p) == 8) { 3237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // Disable core dumps, dumping of 16TB usually takes a bit long. 324d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov setlim(RLIMIT_CORE, 0); 3257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 3267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3274de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov // Go maps shadow memory lazily and works fine with limited address space. 3284de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov // Unlimited stack is not a problem as well, because the executable 3294de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov // is not compiled with -pie. 3304de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov if (kCppMode) { 3314de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov bool reexec = false; 3324de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov // TSan doesn't play well with unlimited stack size (as stack 3334de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov // overlaps with shadow memory). If we detect unlimited stack size, 3344de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov // we re-exec the program with limited stack size as a best effort. 3354de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov if (getlim(RLIMIT_STACK) == (rlim_t)-1) { 3364de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov const uptr kMaxStackSize = 32 * 1024 * 1024; 3372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines VReport(1, "Program is run with unlimited stack size, which wouldn't " 3382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "work with ThreadSanitizer.\n" 3392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "Re-execing with stack size limited to %zd bytes.\n", 3402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines kMaxStackSize); 3414de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov SetStackSizeLimitInBytes(kMaxStackSize); 3424de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov reexec = true; 3434de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov } 344d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov 3454de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov if (getlim(RLIMIT_AS) != (rlim_t)-1) { 3464dc30820d34372c419fd44dda2bdb6383a480ce7Dmitry Vyukov Report("WARNING: Program is run with limited virtual address space," 3474dc30820d34372c419fd44dda2bdb6383a480ce7Dmitry Vyukov " which wouldn't work with ThreadSanitizer.\n"); 3484de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov Report("Re-execing with unlimited virtual address space.\n"); 3494de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov setlim(RLIMIT_AS, -1); 3504de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov reexec = true; 3514de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov } 3524de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov if (reexec) 3534de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov ReExec(); 3544de5864fa631dbba52670dea2503b8540390f176Dmitry Vyukov } 355d698edc4f74a17048eef3342a9fa42b3ebba802aDmitry Vyukov 356b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#ifndef TSAN_GO 3577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CheckPIE(); 358b114ed83859d8d4964ac2284584733bcd2acf4f6Evgeniy Stepanov InitTlsSize(); 3590c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov InitDataSeg(); 360b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov#endif 361ce44055cdde85554aa9d18f8a7166bf5df6f9bb3Kostya Serebryany return GetEnv(kTsanOptionsEnv); 3627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 3637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 3640c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukovbool IsGlobalVar(uptr addr) { 3650c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov return g_data_start && addr >= g_data_start && addr < g_data_end; 3660c2feef1067818db0ede4531a2e71c9b5595d57aDmitry Vyukov} 367b78caa645f70eff2f037f1f8bb43ca9129dbd8d9Dmitry Vyukov 36803f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov#ifndef TSAN_GO 3692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// Extract file descriptors passed to glibc internal __res_iclose function. 3702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// This is required to properly "close" the fds, because we do not see internal 3712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// closes within glibc. The code is a pure hack. 37203f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukovint ExtractResolvFDs(void *state, int *fds, int nfd) { 3735d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#if SANITIZER_LINUX 37403f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov int cnt = 0; 37503f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov __res_state *statp = (__res_state*)state; 37603f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov for (int i = 0; i < MAXNS && cnt < nfd; i++) { 37703f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1) 37803f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov fds[cnt++] = statp->_u._ext.nssocks[i]; 37903f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov } 38003f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov return cnt; 3815d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#else 3825d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines return 0; 3835d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines#endif 38403f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov} 38503f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov 3862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// Extract file descriptors passed via UNIX domain sockets. 3872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// This is requried to properly handle "open" of these fds. 3882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// see 'man recvmsg' and 'man 3 cmsg'. 3892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesint ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) { 3902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines int res = 0; 3912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines msghdr *msg = (msghdr*)msgp; 3922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); 3932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { 3942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) 3952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines continue; 3962d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]); 3972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (int i = 0; i < n; i++) { 3982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines fds[res++] = ((int*)CMSG_DATA(cmsg))[i]; 3992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (res == nfd) 4002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return res; 4012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 4022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 4032d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return res; 4042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 4052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 4062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesint call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m, 4072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines void *abstime), void *c, void *m, void *abstime, 4082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines void(*cleanup)(void *arg), void *arg) { 4092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // pthread_cleanup_push/pop are hardcore macros mess. 4102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // We can't intercept nor call them w/o including pthread.h. 4112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines int res; 4122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines pthread_cleanup_push(cleanup, arg); 4132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines res = fn(c, m, abstime); 4142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines pthread_cleanup_pop(0); 4152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return res; 4162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 4172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif 41803f224835f46801a0e22cc2951d21b67304e0457Dmitry Vyukov 4197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} // namespace __tsan 4203f24d6386cea638f5d4bc1694d1de02917988bcdDmitry Vyukov 42130e110edf92303237d471f1cb8e3ad07954fb145Evgeniy Stepanov#endif // SANITIZER_LINUX 422