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