blob: 53ecfc628dbcdedcf55fa6256854c413bd8d80f8 [file] [log] [blame]
Alexey Samsonov603c4be2012-06-04 13:55:19 +00001//===-- tsan_platform_linux.cc --------------------------------------------===//
Kostya Serebryany7ac41482012-05-10 13:48:04 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer (TSan), a race detector.
11//
12// Linux-specific code.
13//===----------------------------------------------------------------------===//
14
Evgeniy Stepanov24e13722013-03-19 14:33:38 +000015
16#include "sanitizer_common/sanitizer_platform.h"
Stephen Hines6a211c52014-07-21 00:49:56 -070017#if SANITIZER_LINUX || SANITIZER_FREEBSD
Dmitry Vyukov3f24d632012-07-16 13:25:47 +000018
Alexey Samsonov84902c72012-06-18 09:42:39 +000019#include "sanitizer_common/sanitizer_common.h"
Alexey Samsonov48aee682012-06-05 06:19:00 +000020#include "sanitizer_common/sanitizer_libc.h"
Alexey Samsonov84902c72012-06-18 09:42:39 +000021#include "sanitizer_common/sanitizer_procmaps.h"
Dmitry Vyukov92b54792013-10-03 17:14:35 +000022#include "sanitizer_common/sanitizer_stoptheworld.h"
Kostya Serebryany7ac41482012-05-10 13:48:04 +000023#include "tsan_platform.h"
24#include "tsan_rtl.h"
25#include "tsan_flags.h"
26
Kostya Serebryany7ac41482012-05-10 13:48:04 +000027#include <fcntl.h>
28#include <pthread.h>
29#include <signal.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <stdarg.h>
34#include <sys/mman.h>
Kostya Serebryany7ac41482012-05-10 13:48:04 +000035#include <sys/syscall.h>
Stephen Hines2d1fdb22014-05-28 23:58:16 -070036#include <sys/socket.h>
Kostya Serebryany7ac41482012-05-10 13:48:04 +000037#include <sys/time.h>
38#include <sys/types.h>
39#include <sys/resource.h>
40#include <sys/stat.h>
41#include <unistd.h>
42#include <errno.h>
43#include <sched.h>
44#include <dlfcn.h>
Stephen Hines6a211c52014-07-21 00:49:56 -070045#if SANITIZER_LINUX
Dmitry Vyukov03f22482013-02-07 15:27:45 +000046#define __need_res_state
47#include <resolv.h>
Stephen Hines6a211c52014-07-21 00:49:56 -070048#endif
Kostya Serebryany7ac41482012-05-10 13:48:04 +000049
Dmitry Vyukov17b0a3c2013-10-15 13:03:06 +000050#ifdef sa_handler
51# undef sa_handler
52#endif
53
54#ifdef sa_sigaction
55# undef sa_sigaction
56#endif
57
Stephen Hines6a211c52014-07-21 00:49:56 -070058#if SANITIZER_FREEBSD
59extern "C" void *__libc_stack_end;
60void *__libc_stack_end = 0;
61#endif
Kostya Serebryany7ac41482012-05-10 13:48:04 +000062
63namespace __tsan {
64
Dmitry Vyukov82dbc512013-03-20 13:21:50 +000065const uptr kPageSize = 4096;
66
Stephen Hines6a211c52014-07-21 00:49:56 -070067enum {
68 MemTotal = 0,
69 MemShadow = 1,
70 MemMeta = 2,
71 MemFile = 3,
72 MemMmap = 4,
73 MemTrace = 5,
74 MemHeap = 6,
75 MemOther = 7,
76 MemCount = 8,
77};
78
Alexander Potapenko2e13ca82013-09-03 11:09:16 +000079void FillProfileCallback(uptr start, uptr rss, bool file,
80 uptr *mem, uptr stats_size) {
Stephen Hines6a211c52014-07-21 00:49:56 -070081 mem[MemTotal] += rss;
Alexander Potapenko2e13ca82013-09-03 11:09:16 +000082 start >>= 40;
Stephen Hines6a211c52014-07-21 00:49:56 -070083 if (start < 0x10)
84 mem[MemShadow] += rss;
85 else if (start >= 0x20 && start < 0x30)
86 mem[file ? MemFile : MemMmap] += rss;
87 else if (start >= 0x30 && start < 0x40)
88 mem[MemMeta] += rss;
89 else if (start >= 0x7e)
90 mem[file ? MemFile : MemMmap] += rss;
91 else if (start >= 0x60 && start < 0x62)
92 mem[MemTrace] += rss;
93 else if (start >= 0x7d && start < 0x7e)
94 mem[MemHeap] += rss;
95 else
96 mem[MemOther] += rss;
Dmitry Vyukov5d72fc72013-03-18 13:55:33 +000097}
98
Stephen Hines6a211c52014-07-21 00:49:56 -070099void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
100 uptr mem[MemCount] = {};
Alexander Potapenko2e13ca82013-09-03 11:09:16 +0000101 __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
Stephen Hines6a211c52014-07-21 00:49:56 -0700102 internal_snprintf(buf, buf_size,
103 "RSS %zd MB: shadow:%zd meta:%zd file:%zd mmap:%zd"
104 " trace:%zd heap:%zd other:%zd nthr=%zd/%zd\n",
105 mem[MemTotal] >> 20, mem[MemShadow] >> 20, mem[MemMeta] >> 20,
106 mem[MemFile] >> 20, mem[MemMmap] >> 20, mem[MemTrace] >> 20,
107 mem[MemHeap] >> 20, mem[MemOther] >> 20,
108 nlive, nthread);
Dmitry Vyukov26127732012-05-22 11:33:03 +0000109}
110
Dmitry Vyukov92b54792013-10-03 17:14:35 +0000111uptr GetRSS() {
112 uptr mem[7] = {};
113 __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
114 return mem[6];
115}
116
Stephen Hines6a211c52014-07-21 00:49:56 -0700117#if SANITIZER_LINUX
Dmitry Vyukov92b54792013-10-03 17:14:35 +0000118void FlushShadowMemoryCallback(
119 const SuspendedThreadsList &suspended_threads_list,
120 void *argument) {
Kostya Serebryanya54aec82012-12-27 07:37:24 +0000121 FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
Dmitry Vyukovadfb6502012-05-22 18:07:45 +0000122}
Stephen Hines6a211c52014-07-21 00:49:56 -0700123#endif
Dmitry Vyukovadfb6502012-05-22 18:07:45 +0000124
Dmitry Vyukov92b54792013-10-03 17:14:35 +0000125void FlushShadowMemory() {
Stephen Hines6a211c52014-07-21 00:49:56 -0700126#if SANITIZER_LINUX
Dmitry Vyukov92b54792013-10-03 17:14:35 +0000127 StopTheWorld(FlushShadowMemoryCallback, 0);
Stephen Hines6a211c52014-07-21 00:49:56 -0700128#endif
Dmitry Vyukov92b54792013-10-03 17:14:35 +0000129}
130
Dmitry Vyukovb78caa62012-07-05 16:18:28 +0000131#ifndef TSAN_GO
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000132static void ProtectRange(uptr beg, uptr end) {
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000133 CHECK_LE(beg, end);
134 if (beg == end)
135 return;
Alexey Samsonov84902c72012-06-18 09:42:39 +0000136 if (beg != (uptr)Mprotect(beg, end - beg)) {
Alexey Samsonovb1fe3022012-11-02 12:17:51 +0000137 Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
138 Printf("FATAL: Make sure you are not using unlimited stack\n");
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000139 Die();
140 }
141}
142
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000143// Mark shadow for .rodata sections with the special kShadowRodata marker.
144// Accesses to .rodata can't race, so this saves time, memory and trace space.
145static void MapRodata() {
146 // First create temp file.
147 const char *tmpdir = GetEnv("TMPDIR");
148 if (tmpdir == 0)
149 tmpdir = GetEnv("TEST_TMPDIR");
150#ifdef P_tmpdir
151 if (tmpdir == 0)
152 tmpdir = P_tmpdir;
153#endif
154 if (tmpdir == 0)
155 return;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700156 char name[256];
157 internal_snprintf(name, sizeof(name), "%s/tsan.rodata.%d",
Peter Collingbourne0b694fc2013-05-17 16:56:53 +0000158 tmpdir, (int)internal_getpid());
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700159 uptr openrv = internal_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
Peter Collingbourne9578a3e2013-05-08 14:43:49 +0000160 if (internal_iserror(openrv))
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000161 return;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700162 internal_unlink(name); // Unlink it now, so that we can reuse the buffer.
Peter Collingbourne9578a3e2013-05-08 14:43:49 +0000163 fd_t fd = openrv;
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000164 // Fill the file with kShadowRodata.
165 const uptr kMarkerSize = 512 * 1024 / sizeof(u64);
166 InternalScopedBuffer<u64> marker(kMarkerSize);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700167 // volatile to prevent insertion of memset
168 for (volatile u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++)
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000169 *p = kShadowRodata;
170 internal_write(fd, marker.data(), marker.size());
171 // Map the file into memory.
Peter Collingbourne9578a3e2013-05-08 14:43:49 +0000172 uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE,
173 MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
174 if (internal_iserror(page)) {
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000175 internal_close(fd);
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000176 return;
177 }
178 // Map the file into shadow of .rodata sections.
Alexander Potapenko9ae28832013-03-26 10:34:37 +0000179 MemoryMappingLayout proc_maps(/*cache_enabled*/true);
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000180 uptr start, end, offset, prot;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700181 // Reusing the buffer 'name'.
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000182 while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) {
183 if (name[0] != 0 && name[0] != '['
184 && (prot & MemoryMappingLayout::kProtectionRead)
185 && (prot & MemoryMappingLayout::kProtectionExecute)
186 && !(prot & MemoryMappingLayout::kProtectionWrite)
187 && IsAppMem(start)) {
188 // Assume it's .rodata
189 char *shadow_start = (char*)MemToShadow(start);
190 char *shadow_end = (char*)MemToShadow(end);
191 for (char *p = shadow_start; p < shadow_end; p += marker.size()) {
192 internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p),
193 PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
194 }
195 }
196 }
197 internal_close(fd);
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000198}
199
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000200void InitializeShadowMemory() {
Stephen Hines6a211c52014-07-21 00:49:56 -0700201 // Map memory shadow.
Alexey Samsonov84902c72012-06-18 09:42:39 +0000202 uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
203 kLinuxShadowEnd - kLinuxShadowBeg);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000204 if (shadow != kLinuxShadowBeg) {
Alexey Samsonovb1fe3022012-11-02 12:17:51 +0000205 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
206 Printf("FATAL: Make sure to compile with -fPIE and "
Dmitry Vyukov2e870512012-08-15 15:35:15 +0000207 "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000208 Die();
209 }
Stephen Hines6a211c52014-07-21 00:49:56 -0700210 DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
211 kLinuxShadowBeg, kLinuxShadowEnd,
212 (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
213
214 // Map meta shadow.
215 if (MemToMeta(kLinuxAppMemBeg) < (u32*)kMetaShadow) {
216 Printf("ThreadSanitizer: bad meta shadow (%p -> %p < %p)\n",
217 kLinuxAppMemBeg, MemToMeta(kLinuxAppMemBeg), kMetaShadow);
218 Die();
219 }
220 if (MemToMeta(kLinuxAppMemEnd) >= (u32*)(kMetaShadow + kMetaSize)) {
221 Printf("ThreadSanitizer: bad meta shadow (%p -> %p >= %p)\n",
222 kLinuxAppMemEnd, MemToMeta(kLinuxAppMemEnd), kMetaShadow + kMetaSize);
223 Die();
224 }
225 uptr meta = (uptr)MmapFixedNoReserve(kMetaShadow, kMetaSize);
226 if (meta != kMetaShadow) {
227 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
228 Printf("FATAL: Make sure to compile with -fPIE and "
229 "to link with -pie (%p, %p).\n", meta, kMetaShadow);
230 Die();
231 }
232 DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
233 kMetaShadow, kMetaShadow + kMetaSize, kMetaSize >> 30);
234
235 // Protect gaps.
Dmitry Vyukovb78caa62012-07-05 16:18:28 +0000236 const uptr kClosedLowBeg = 0x200000;
237 const uptr kClosedLowEnd = kLinuxShadowBeg - 1;
238 const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
Stephen Hines6a211c52014-07-21 00:49:56 -0700239 const uptr kClosedMidEnd = min(min(kLinuxAppMemBeg, kTraceMemBegin),
240 kMetaShadow);
241
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000242 ProtectRange(kClosedLowBeg, kClosedLowEnd);
243 ProtectRange(kClosedMidBeg, kClosedMidEnd);
Stephen Hines6a211c52014-07-21 00:49:56 -0700244 VPrintf(2, "kClosedLow %zx-%zx (%zuGB)\n",
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000245 kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
Stephen Hines6a211c52014-07-21 00:49:56 -0700246 VPrintf(2, "kClosedMid %zx-%zx (%zuGB)\n",
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000247 kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
Stephen Hines6a211c52014-07-21 00:49:56 -0700248 VPrintf(2, "app mem: %zx-%zx (%zuGB)\n",
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000249 kLinuxAppMemBeg, kLinuxAppMemEnd,
250 (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
Stephen Hines6a211c52014-07-21 00:49:56 -0700251 VPrintf(2, "stack: %zx\n", (uptr)&shadow);
Dmitry Vyukov82dbc512013-03-20 13:21:50 +0000252
253 MapRodata();
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000254}
Dmitry Vyukova05fcc12012-11-06 16:00:16 +0000255#endif
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000256
Dmitry Vyukov0c2feef2012-09-07 18:08:02 +0000257static uptr g_data_start;
258static uptr g_data_end;
259
Dmitry Vyukovb78caa62012-07-05 16:18:28 +0000260#ifndef TSAN_GO
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000261static void CheckPIE() {
262 // Ensure that the binary is indeed compiled with -pie.
Alexander Potapenko9ae28832013-03-26 10:34:37 +0000263 MemoryMappingLayout proc_maps(true);
Alexey Samsonov84902c72012-06-18 09:42:39 +0000264 uptr start, end;
265 if (proc_maps.Next(&start, &end,
Alexey Samsonov45717c92013-03-13 06:51:02 +0000266 /*offset*/0, /*filename*/0, /*filename_size*/0,
267 /*protection*/0)) {
Alexey Samsonov84902c72012-06-18 09:42:39 +0000268 if ((u64)start < kLinuxAppMemBeg) {
Alexey Samsonovb1fe3022012-11-02 12:17:51 +0000269 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
Alexey Samsonove9541012012-06-06 13:11:29 +0000270 "something is mapped at 0x%zx < 0x%zx)\n",
Alexey Samsonov84902c72012-06-18 09:42:39 +0000271 start, kLinuxAppMemBeg);
Alexey Samsonovb1fe3022012-11-02 12:17:51 +0000272 Printf("FATAL: Make sure to compile with -fPIE"
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000273 " and to link with -pie.\n");
274 Die();
275 }
276 }
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000277}
278
Dmitry Vyukov0c2feef2012-09-07 18:08:02 +0000279static void InitDataSeg() {
Alexander Potapenko9ae28832013-03-26 10:34:37 +0000280 MemoryMappingLayout proc_maps(true);
Dmitry Vyukov0c2feef2012-09-07 18:08:02 +0000281 uptr start, end, offset;
282 char name[128];
283 bool prev_is_data = false;
Alexey Samsonov45717c92013-03-13 06:51:02 +0000284 while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
285 /*protection*/ 0)) {
Dmitry Vyukov0c2feef2012-09-07 18:08:02 +0000286 DPrintf("%p-%p %p %s\n", start, end, offset, name);
287 bool is_data = offset != 0 && name[0] != 0;
Evgeniy Stepanov97dac9e2012-09-27 13:20:40 +0000288 // BSS may get merged with [heap] in /proc/self/maps. This is not very
289 // reliable.
290 bool is_bss = offset == 0 &&
291 (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data;
Dmitry Vyukov0c2feef2012-09-07 18:08:02 +0000292 if (g_data_start == 0 && is_data)
293 g_data_start = start;
294 if (is_bss)
295 g_data_end = end;
296 prev_is_data = is_data;
297 }
298 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start, g_data_end);
299 CHECK_LT(g_data_start, g_data_end);
300 CHECK_GE((uptr)&g_data_start, g_data_start);
301 CHECK_LT((uptr)&g_data_start, g_data_end);
302}
Dmitry Vyukovb78caa62012-07-05 16:18:28 +0000303
Dmitry Vyukovb78caa62012-07-05 16:18:28 +0000304#endif // #ifndef TSAN_GO
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000305
Dmitry Vyukovd698edc2012-11-28 12:19:50 +0000306static rlim_t getlim(int res) {
307 rlimit rlim;
308 CHECK_EQ(0, getrlimit(res, &rlim));
309 return rlim.rlim_cur;
310}
311
312static void setlim(int res, rlim_t lim) {
313 // The following magic is to prevent clang from replacing it with memset.
314 volatile rlimit rlim;
315 rlim.rlim_cur = lim;
316 rlim.rlim_max = lim;
317 setrlimit(res, (rlimit*)&rlim);
318}
319
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000320const char *InitializePlatform() {
321 void *p = 0;
322 if (sizeof(p) == 8) {
323 // Disable core dumps, dumping of 16TB usually takes a bit long.
Dmitry Vyukovd698edc2012-11-28 12:19:50 +0000324 setlim(RLIMIT_CORE, 0);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000325 }
326
Dmitry Vyukov4de58642012-12-21 10:45:01 +0000327 // Go maps shadow memory lazily and works fine with limited address space.
328 // Unlimited stack is not a problem as well, because the executable
329 // is not compiled with -pie.
330 if (kCppMode) {
331 bool reexec = false;
332 // TSan doesn't play well with unlimited stack size (as stack
333 // overlaps with shadow memory). If we detect unlimited stack size,
334 // we re-exec the program with limited stack size as a best effort.
335 if (getlim(RLIMIT_STACK) == (rlim_t)-1) {
336 const uptr kMaxStackSize = 32 * 1024 * 1024;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700337 VReport(1, "Program is run with unlimited stack size, which wouldn't "
338 "work with ThreadSanitizer.\n"
339 "Re-execing with stack size limited to %zd bytes.\n",
340 kMaxStackSize);
Dmitry Vyukov4de58642012-12-21 10:45:01 +0000341 SetStackSizeLimitInBytes(kMaxStackSize);
342 reexec = true;
343 }
Dmitry Vyukovd698edc2012-11-28 12:19:50 +0000344
Dmitry Vyukov4de58642012-12-21 10:45:01 +0000345 if (getlim(RLIMIT_AS) != (rlim_t)-1) {
Dmitry Vyukov4dc30822012-12-21 10:47:48 +0000346 Report("WARNING: Program is run with limited virtual address space,"
347 " which wouldn't work with ThreadSanitizer.\n");
Dmitry Vyukov4de58642012-12-21 10:45:01 +0000348 Report("Re-execing with unlimited virtual address space.\n");
349 setlim(RLIMIT_AS, -1);
350 reexec = true;
351 }
352 if (reexec)
353 ReExec();
354 }
Dmitry Vyukovd698edc2012-11-28 12:19:50 +0000355
Dmitry Vyukovb78caa62012-07-05 16:18:28 +0000356#ifndef TSAN_GO
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000357 CheckPIE();
Evgeniy Stepanovb114ed82013-03-13 08:19:53 +0000358 InitTlsSize();
Dmitry Vyukov0c2feef2012-09-07 18:08:02 +0000359 InitDataSeg();
Dmitry Vyukovb78caa62012-07-05 16:18:28 +0000360#endif
Kostya Serebryanyce440552013-02-19 08:19:13 +0000361 return GetEnv(kTsanOptionsEnv);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000362}
363
Dmitry Vyukov0c2feef2012-09-07 18:08:02 +0000364bool IsGlobalVar(uptr addr) {
365 return g_data_start && addr >= g_data_start && addr < g_data_end;
366}
Dmitry Vyukovb78caa62012-07-05 16:18:28 +0000367
Dmitry Vyukov03f22482013-02-07 15:27:45 +0000368#ifndef TSAN_GO
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700369// Extract file descriptors passed to glibc internal __res_iclose function.
370// This is required to properly "close" the fds, because we do not see internal
371// closes within glibc. The code is a pure hack.
Dmitry Vyukov03f22482013-02-07 15:27:45 +0000372int ExtractResolvFDs(void *state, int *fds, int nfd) {
Stephen Hines6a211c52014-07-21 00:49:56 -0700373#if SANITIZER_LINUX
Dmitry Vyukov03f22482013-02-07 15:27:45 +0000374 int cnt = 0;
375 __res_state *statp = (__res_state*)state;
376 for (int i = 0; i < MAXNS && cnt < nfd; i++) {
377 if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1)
378 fds[cnt++] = statp->_u._ext.nssocks[i];
379 }
380 return cnt;
Stephen Hines6a211c52014-07-21 00:49:56 -0700381#else
382 return 0;
383#endif
Dmitry Vyukov03f22482013-02-07 15:27:45 +0000384}
Dmitry Vyukov03f22482013-02-07 15:27:45 +0000385
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700386// Extract file descriptors passed via UNIX domain sockets.
387// This is requried to properly handle "open" of these fds.
388// see 'man recvmsg' and 'man 3 cmsg'.
389int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
390 int res = 0;
391 msghdr *msg = (msghdr*)msgp;
392 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
393 for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
394 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
395 continue;
396 int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]);
397 for (int i = 0; i < n; i++) {
398 fds[res++] = ((int*)CMSG_DATA(cmsg))[i];
399 if (res == nfd)
400 return res;
401 }
402 }
403 return res;
404}
405
406int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
407 void *abstime), void *c, void *m, void *abstime,
408 void(*cleanup)(void *arg), void *arg) {
409 // pthread_cleanup_push/pop are hardcore macros mess.
410 // We can't intercept nor call them w/o including pthread.h.
411 int res;
412 pthread_cleanup_push(cleanup, arg);
413 res = fn(c, m, abstime);
414 pthread_cleanup_pop(0);
415 return res;
416}
417#endif
Dmitry Vyukov03f22482013-02-07 15:27:45 +0000418
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000419} // namespace __tsan
Dmitry Vyukov3f24d632012-07-16 13:25:47 +0000420
Evgeniy Stepanov30e110e2013-03-19 14:54:17 +0000421#endif // SANITIZER_LINUX