1 //===-- tsan_platform_linux.cc --------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 // Linux-specific code.
11 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common/sanitizer_platform.h"
17 #include "sanitizer_common/sanitizer_common.h"
18 #include "sanitizer_common/sanitizer_libc.h"
19 #include "sanitizer_common/sanitizer_procmaps.h"
20 #include "sanitizer_common/sanitizer_stoptheworld.h"
21 #include "tsan_platform.h"
23 #include "tsan_flags.h"
33 #include <sys/prctl.h>
34 #include <sys/syscall.h>
35 #include <sys/socket.h>
37 #include <sys/types.h>
38 #include <sys/resource.h>
44 #define __need_res_state
56 extern "C" struct mallinfo
__libc_mallinfo();
60 const uptr kPageSize
= 4096;
62 void FillProfileCallback(uptr start
, uptr rss
, bool file
,
63 uptr
*mem
, uptr stats_size
) {
64 CHECK_EQ(7, stats_size
);
65 mem
[6] += rss
; // total
67 if (start
< 0x10) // shadow
69 else if (start
>= 0x20 && start
< 0x30) // compat modules
70 mem
[file
? 1 : 2] += rss
;
71 else if (start
>= 0x7e) // modules
72 mem
[file
? 1 : 2] += rss
;
73 else if (start
>= 0x60 && start
< 0x62) // traces
75 else if (start
>= 0x7d && start
< 0x7e) // heap
81 void WriteMemoryProfile(char *buf
, uptr buf_size
) {
83 __sanitizer::GetMemoryProfile(FillProfileCallback
, mem
, 7);
85 char *buf_end
= buf
+ buf_size
;
86 buf_pos
+= internal_snprintf(buf_pos
, buf_end
- buf_pos
,
87 "RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n",
88 mem
[6] >> 20, mem
[0] >> 20, mem
[1] >> 20, mem
[2] >> 20,
89 mem
[3] >> 20, mem
[4] >> 20, mem
[5] >> 20);
90 struct mallinfo mi
= __libc_mallinfo();
91 buf_pos
+= internal_snprintf(buf_pos
, buf_end
- buf_pos
,
92 "mallinfo: arena=%d mmap=%d fordblks=%d keepcost=%d\n",
93 mi
.arena
>> 20, mi
.hblkhd
>> 20, mi
.fordblks
>> 20, mi
.keepcost
>> 20);
98 __sanitizer::GetMemoryProfile(FillProfileCallback
, mem
, 7);
103 void FlushShadowMemoryCallback(
104 const SuspendedThreadsList
&suspended_threads_list
,
106 FlushUnneededShadowMemory(kLinuxShadowBeg
, kLinuxShadowEnd
- kLinuxShadowBeg
);
109 void FlushShadowMemory() {
110 StopTheWorld(FlushShadowMemoryCallback
, 0);
114 static void ProtectRange(uptr beg
, uptr end
) {
118 if (beg
!= (uptr
)Mprotect(beg
, end
- beg
)) {
119 Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg
, end
);
120 Printf("FATAL: Make sure you are not using unlimited stack\n");
127 // Mark shadow for .rodata sections with the special kShadowRodata marker.
128 // Accesses to .rodata can't race, so this saves time, memory and trace space.
129 static void MapRodata() {
130 // First create temp file.
131 const char *tmpdir
= GetEnv("TMPDIR");
133 tmpdir
= GetEnv("TEST_TMPDIR");
141 internal_snprintf(name
, sizeof(name
), "%s/tsan.rodata.%d",
142 tmpdir
, (int)internal_getpid());
143 uptr openrv
= internal_open(name
, O_RDWR
| O_CREAT
| O_EXCL
, 0600);
144 if (internal_iserror(openrv
))
146 internal_unlink(name
); // Unlink it now, so that we can reuse the buffer.
148 // Fill the file with kShadowRodata.
149 const uptr kMarkerSize
= 512 * 1024 / sizeof(u64
);
150 InternalScopedBuffer
<u64
> marker(kMarkerSize
);
151 // volatile to prevent insertion of memset
152 for (volatile u64
*p
= marker
.data(); p
< marker
.data() + kMarkerSize
; p
++)
154 internal_write(fd
, marker
.data(), marker
.size());
155 // Map the file into memory.
156 uptr page
= internal_mmap(0, kPageSize
, PROT_READ
| PROT_WRITE
,
157 MAP_PRIVATE
| MAP_ANONYMOUS
, fd
, 0);
158 if (internal_iserror(page
)) {
162 // Map the file into shadow of .rodata sections.
163 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
164 uptr start
, end
, offset
, prot
;
165 // Reusing the buffer 'name'.
166 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
), &prot
)) {
167 if (name
[0] != 0 && name
[0] != '['
168 && (prot
& MemoryMappingLayout::kProtectionRead
)
169 && (prot
& MemoryMappingLayout::kProtectionExecute
)
170 && !(prot
& MemoryMappingLayout::kProtectionWrite
)
171 && IsAppMem(start
)) {
172 // Assume it's .rodata
173 char *shadow_start
= (char*)MemToShadow(start
);
174 char *shadow_end
= (char*)MemToShadow(end
);
175 for (char *p
= shadow_start
; p
< shadow_end
; p
+= marker
.size()) {
176 internal_mmap(p
, Min
<uptr
>(marker
.size(), shadow_end
- p
),
177 PROT_READ
, MAP_PRIVATE
| MAP_FIXED
, fd
, 0);
184 void InitializeShadowMemory() {
185 uptr shadow
= (uptr
)MmapFixedNoReserve(kLinuxShadowBeg
,
186 kLinuxShadowEnd
- kLinuxShadowBeg
);
187 if (shadow
!= kLinuxShadowBeg
) {
188 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
189 Printf("FATAL: Make sure to compile with -fPIE and "
190 "to link with -pie (%p, %p).\n", shadow
, kLinuxShadowBeg
);
193 const uptr kClosedLowBeg
= 0x200000;
194 const uptr kClosedLowEnd
= kLinuxShadowBeg
- 1;
195 const uptr kClosedMidBeg
= kLinuxShadowEnd
+ 1;
196 const uptr kClosedMidEnd
= min(kLinuxAppMemBeg
, kTraceMemBegin
);
197 ProtectRange(kClosedLowBeg
, kClosedLowEnd
);
198 ProtectRange(kClosedMidBeg
, kClosedMidEnd
);
199 DPrintf("kClosedLow %zx-%zx (%zuGB)\n",
200 kClosedLowBeg
, kClosedLowEnd
, (kClosedLowEnd
- kClosedLowBeg
) >> 30);
201 DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
202 kLinuxShadowBeg
, kLinuxShadowEnd
,
203 (kLinuxShadowEnd
- kLinuxShadowBeg
) >> 30);
204 DPrintf("kClosedMid %zx-%zx (%zuGB)\n",
205 kClosedMidBeg
, kClosedMidEnd
, (kClosedMidEnd
- kClosedMidBeg
) >> 30);
206 DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
207 kLinuxAppMemBeg
, kLinuxAppMemEnd
,
208 (kLinuxAppMemEnd
- kLinuxAppMemBeg
) >> 30);
209 DPrintf("stack %zx\n", (uptr
)&shadow
);
215 static uptr g_data_start
;
216 static uptr g_data_end
;
219 static void CheckPIE() {
220 // Ensure that the binary is indeed compiled with -pie.
221 MemoryMappingLayout
proc_maps(true);
223 if (proc_maps
.Next(&start
, &end
,
224 /*offset*/0, /*filename*/0, /*filename_size*/0,
226 if ((u64
)start
< kLinuxAppMemBeg
) {
227 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
228 "something is mapped at 0x%zx < 0x%zx)\n",
229 start
, kLinuxAppMemBeg
);
230 Printf("FATAL: Make sure to compile with -fPIE"
231 " and to link with -pie.\n");
237 static void InitDataSeg() {
238 MemoryMappingLayout
proc_maps(true);
239 uptr start
, end
, offset
;
241 bool prev_is_data
= false;
242 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
),
244 DPrintf("%p-%p %p %s\n", start
, end
, offset
, name
);
245 bool is_data
= offset
!= 0 && name
[0] != 0;
246 // BSS may get merged with [heap] in /proc/self/maps. This is not very
248 bool is_bss
= offset
== 0 &&
249 (name
[0] == 0 || internal_strcmp(name
, "[heap]") == 0) && prev_is_data
;
250 if (g_data_start
== 0 && is_data
)
251 g_data_start
= start
;
254 prev_is_data
= is_data
;
256 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start
, g_data_end
);
257 CHECK_LT(g_data_start
, g_data_end
);
258 CHECK_GE((uptr
)&g_data_start
, g_data_start
);
259 CHECK_LT((uptr
)&g_data_start
, g_data_end
);
262 #endif // #ifndef TSAN_GO
264 static rlim_t
getlim(int res
) {
266 CHECK_EQ(0, getrlimit(res
, &rlim
));
267 return rlim
.rlim_cur
;
270 static void setlim(int res
, rlim_t lim
) {
271 // The following magic is to prevent clang from replacing it with memset.
272 volatile rlimit rlim
;
275 setrlimit(res
, (rlimit
*)&rlim
);
278 const char *InitializePlatform() {
280 if (sizeof(p
) == 8) {
281 // Disable core dumps, dumping of 16TB usually takes a bit long.
282 setlim(RLIMIT_CORE
, 0);
285 // Go maps shadow memory lazily and works fine with limited address space.
286 // Unlimited stack is not a problem as well, because the executable
287 // is not compiled with -pie.
290 // TSan doesn't play well with unlimited stack size (as stack
291 // overlaps with shadow memory). If we detect unlimited stack size,
292 // we re-exec the program with limited stack size as a best effort.
293 if (getlim(RLIMIT_STACK
) == (rlim_t
)-1) {
294 const uptr kMaxStackSize
= 32 * 1024 * 1024;
295 VReport(1, "Program is run with unlimited stack size, which wouldn't "
296 "work with ThreadSanitizer.\n"
297 "Re-execing with stack size limited to %zd bytes.\n",
299 SetStackSizeLimitInBytes(kMaxStackSize
);
303 if (getlim(RLIMIT_AS
) != (rlim_t
)-1) {
304 Report("WARNING: Program is run with limited virtual address space,"
305 " which wouldn't work with ThreadSanitizer.\n");
306 Report("Re-execing with unlimited virtual address space.\n");
307 setlim(RLIMIT_AS
, -1);
319 return GetEnv(kTsanOptionsEnv
);
322 bool IsGlobalVar(uptr addr
) {
323 return g_data_start
&& addr
>= g_data_start
&& addr
< g_data_end
;
327 // Extract file descriptors passed to glibc internal __res_iclose function.
328 // This is required to properly "close" the fds, because we do not see internal
329 // closes within glibc. The code is a pure hack.
330 int ExtractResolvFDs(void *state
, int *fds
, int nfd
) {
332 __res_state
*statp
= (__res_state
*)state
;
333 for (int i
= 0; i
< MAXNS
&& cnt
< nfd
; i
++) {
334 if (statp
->_u
._ext
.nsaddrs
[i
] && statp
->_u
._ext
.nssocks
[i
] != -1)
335 fds
[cnt
++] = statp
->_u
._ext
.nssocks
[i
];
340 // Extract file descriptors passed via UNIX domain sockets.
341 // This is requried to properly handle "open" of these fds.
342 // see 'man recvmsg' and 'man 3 cmsg'.
343 int ExtractRecvmsgFDs(void *msgp
, int *fds
, int nfd
) {
345 msghdr
*msg
= (msghdr
*)msgp
;
346 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR(msg
);
347 for (; cmsg
; cmsg
= CMSG_NXTHDR(msg
, cmsg
)) {
348 if (cmsg
->cmsg_level
!= SOL_SOCKET
|| cmsg
->cmsg_type
!= SCM_RIGHTS
)
350 int n
= (cmsg
->cmsg_len
- CMSG_LEN(0)) / sizeof(fds
[0]);
351 for (int i
= 0; i
< n
; i
++) {
352 fds
[res
++] = ((int*)CMSG_DATA(cmsg
))[i
];
360 int call_pthread_cancel_with_cleanup(int(*fn
)(void *c
, void *m
,
361 void *abstime
), void *c
, void *m
, void *abstime
,
362 void(*cleanup
)(void *arg
), void *arg
) {
363 // pthread_cleanup_push/pop are hardcore macros mess.
364 // We can't intercept nor call them w/o including pthread.h.
366 pthread_cleanup_push(cleanup
, arg
);
367 res
= fn(c
, m
, abstime
);
368 pthread_cleanup_pop(0);
373 } // namespace __tsan
375 #endif // SANITIZER_LINUX