1 //===-- tsan_platform_linux.cc --------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of ThreadSanitizer (TSan), a race detector.
12 // Linux-specific code.
13 //===----------------------------------------------------------------------===//
16 #include "sanitizer_common/sanitizer_platform.h"
19 #include "sanitizer_common/sanitizer_common.h"
20 #include "sanitizer_common/sanitizer_libc.h"
21 #include "sanitizer_common/sanitizer_procmaps.h"
22 #include "sanitizer_common/sanitizer_stoptheworld.h"
23 #include "tsan_platform.h"
25 #include "tsan_flags.h"
35 #include <sys/prctl.h>
36 #include <sys/syscall.h>
37 #include <sys/socket.h>
39 #include <sys/types.h>
40 #include <sys/resource.h>
46 #define __need_res_state
58 extern "C" struct mallinfo
__libc_mallinfo();
62 const uptr kPageSize
= 4096;
64 void FillProfileCallback(uptr start
, uptr rss
, bool file
,
65 uptr
*mem
, uptr stats_size
) {
66 CHECK_EQ(7, stats_size
);
67 mem
[6] += rss
; // total
69 if (start
< 0x10) // shadow
71 else if (start
>= 0x20 && start
< 0x30) // compat modules
72 mem
[file
? 1 : 2] += rss
;
73 else if (start
>= 0x7e) // modules
74 mem
[file
? 1 : 2] += rss
;
75 else if (start
>= 0x60 && start
< 0x62) // traces
77 else if (start
>= 0x7d && start
< 0x7e) // heap
83 void WriteMemoryProfile(char *buf
, uptr buf_size
) {
85 __sanitizer::GetMemoryProfile(FillProfileCallback
, mem
, 7);
87 char *buf_end
= buf
+ buf_size
;
88 buf_pos
+= internal_snprintf(buf_pos
, buf_end
- buf_pos
,
89 "RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n",
90 mem
[6] >> 20, mem
[0] >> 20, mem
[1] >> 20, mem
[2] >> 20,
91 mem
[3] >> 20, mem
[4] >> 20, mem
[5] >> 20);
92 struct mallinfo mi
= __libc_mallinfo();
93 buf_pos
+= internal_snprintf(buf_pos
, buf_end
- buf_pos
,
94 "mallinfo: arena=%d mmap=%d fordblks=%d keepcost=%d\n",
95 mi
.arena
>> 20, mi
.hblkhd
>> 20, mi
.fordblks
>> 20, mi
.keepcost
>> 20);
100 __sanitizer::GetMemoryProfile(FillProfileCallback
, mem
, 7);
105 void FlushShadowMemoryCallback(
106 const SuspendedThreadsList
&suspended_threads_list
,
108 FlushUnneededShadowMemory(kLinuxShadowBeg
, kLinuxShadowEnd
- kLinuxShadowBeg
);
111 void FlushShadowMemory() {
112 StopTheWorld(FlushShadowMemoryCallback
, 0);
116 static void ProtectRange(uptr beg
, uptr end
) {
120 if (beg
!= (uptr
)Mprotect(beg
, end
- beg
)) {
121 Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg
, end
);
122 Printf("FATAL: Make sure you are not using unlimited stack\n");
129 // Mark shadow for .rodata sections with the special kShadowRodata marker.
130 // Accesses to .rodata can't race, so this saves time, memory and trace space.
131 static void MapRodata() {
132 // First create temp file.
133 const char *tmpdir
= GetEnv("TMPDIR");
135 tmpdir
= GetEnv("TEST_TMPDIR");
143 internal_snprintf(name
, sizeof(name
), "%s/tsan.rodata.%d",
144 tmpdir
, (int)internal_getpid());
145 uptr openrv
= internal_open(name
, O_RDWR
| O_CREAT
| O_EXCL
, 0600);
146 if (internal_iserror(openrv
))
148 internal_unlink(name
); // Unlink it now, so that we can reuse the buffer.
150 // Fill the file with kShadowRodata.
151 const uptr kMarkerSize
= 512 * 1024 / sizeof(u64
);
152 InternalScopedBuffer
<u64
> marker(kMarkerSize
);
153 for (u64
*p
= marker
.data(); p
< marker
.data() + kMarkerSize
; p
++)
155 internal_write(fd
, marker
.data(), marker
.size());
156 // Map the file into memory.
157 uptr page
= internal_mmap(0, kPageSize
, PROT_READ
| PROT_WRITE
,
158 MAP_PRIVATE
| MAP_ANONYMOUS
, fd
, 0);
159 if (internal_iserror(page
)) {
163 // Map the file into shadow of .rodata sections.
164 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
165 uptr start
, end
, offset
, prot
;
166 // Reusing the buffer 'name'.
167 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
), &prot
)) {
168 if (name
[0] != 0 && name
[0] != '['
169 && (prot
& MemoryMappingLayout::kProtectionRead
)
170 && (prot
& MemoryMappingLayout::kProtectionExecute
)
171 && !(prot
& MemoryMappingLayout::kProtectionWrite
)
172 && IsAppMem(start
)) {
173 // Assume it's .rodata
174 char *shadow_start
= (char*)MemToShadow(start
);
175 char *shadow_end
= (char*)MemToShadow(end
);
176 for (char *p
= shadow_start
; p
< shadow_end
; p
+= marker
.size()) {
177 internal_mmap(p
, Min
<uptr
>(marker
.size(), shadow_end
- p
),
178 PROT_READ
, MAP_PRIVATE
| MAP_FIXED
, fd
, 0);
185 void InitializeShadowMemory() {
186 uptr shadow
= (uptr
)MmapFixedNoReserve(kLinuxShadowBeg
,
187 kLinuxShadowEnd
- kLinuxShadowBeg
);
188 if (shadow
!= kLinuxShadowBeg
) {
189 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
190 Printf("FATAL: Make sure to compile with -fPIE and "
191 "to link with -pie (%p, %p).\n", shadow
, kLinuxShadowBeg
);
194 const uptr kClosedLowBeg
= 0x200000;
195 const uptr kClosedLowEnd
= kLinuxShadowBeg
- 1;
196 const uptr kClosedMidBeg
= kLinuxShadowEnd
+ 1;
197 const uptr kClosedMidEnd
= min(kLinuxAppMemBeg
, kTraceMemBegin
);
198 ProtectRange(kClosedLowBeg
, kClosedLowEnd
);
199 ProtectRange(kClosedMidBeg
, kClosedMidEnd
);
200 DPrintf("kClosedLow %zx-%zx (%zuGB)\n",
201 kClosedLowBeg
, kClosedLowEnd
, (kClosedLowEnd
- kClosedLowBeg
) >> 30);
202 DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
203 kLinuxShadowBeg
, kLinuxShadowEnd
,
204 (kLinuxShadowEnd
- kLinuxShadowBeg
) >> 30);
205 DPrintf("kClosedMid %zx-%zx (%zuGB)\n",
206 kClosedMidBeg
, kClosedMidEnd
, (kClosedMidEnd
- kClosedMidBeg
) >> 30);
207 DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
208 kLinuxAppMemBeg
, kLinuxAppMemEnd
,
209 (kLinuxAppMemEnd
- kLinuxAppMemBeg
) >> 30);
210 DPrintf("stack %zx\n", (uptr
)&shadow
);
216 static uptr g_data_start
;
217 static uptr g_data_end
;
220 static void CheckPIE() {
221 // Ensure that the binary is indeed compiled with -pie.
222 MemoryMappingLayout
proc_maps(true);
224 if (proc_maps
.Next(&start
, &end
,
225 /*offset*/0, /*filename*/0, /*filename_size*/0,
227 if ((u64
)start
< kLinuxAppMemBeg
) {
228 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
229 "something is mapped at 0x%zx < 0x%zx)\n",
230 start
, kLinuxAppMemBeg
);
231 Printf("FATAL: Make sure to compile with -fPIE"
232 " and to link with -pie.\n");
238 static void InitDataSeg() {
239 MemoryMappingLayout
proc_maps(true);
240 uptr start
, end
, offset
;
242 bool prev_is_data
= false;
243 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
),
245 DPrintf("%p-%p %p %s\n", start
, end
, offset
, name
);
246 bool is_data
= offset
!= 0 && name
[0] != 0;
247 // BSS may get merged with [heap] in /proc/self/maps. This is not very
249 bool is_bss
= offset
== 0 &&
250 (name
[0] == 0 || internal_strcmp(name
, "[heap]") == 0) && prev_is_data
;
251 if (g_data_start
== 0 && is_data
)
252 g_data_start
= start
;
255 prev_is_data
= is_data
;
257 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start
, g_data_end
);
258 CHECK_LT(g_data_start
, g_data_end
);
259 CHECK_GE((uptr
)&g_data_start
, g_data_start
);
260 CHECK_LT((uptr
)&g_data_start
, g_data_end
);
263 #endif // #ifndef TSAN_GO
265 static rlim_t
getlim(int res
) {
267 CHECK_EQ(0, getrlimit(res
, &rlim
));
268 return rlim
.rlim_cur
;
271 static void setlim(int res
, rlim_t lim
) {
272 // The following magic is to prevent clang from replacing it with memset.
273 volatile rlimit rlim
;
276 setrlimit(res
, (rlimit
*)&rlim
);
279 const char *InitializePlatform() {
281 if (sizeof(p
) == 8) {
282 // Disable core dumps, dumping of 16TB usually takes a bit long.
283 setlim(RLIMIT_CORE
, 0);
286 // Go maps shadow memory lazily and works fine with limited address space.
287 // Unlimited stack is not a problem as well, because the executable
288 // is not compiled with -pie.
291 // TSan doesn't play well with unlimited stack size (as stack
292 // overlaps with shadow memory). If we detect unlimited stack size,
293 // we re-exec the program with limited stack size as a best effort.
294 if (getlim(RLIMIT_STACK
) == (rlim_t
)-1) {
295 const uptr kMaxStackSize
= 32 * 1024 * 1024;
296 VReport(1, "Program is run with unlimited stack size, which wouldn't "
297 "work with ThreadSanitizer.\n"
298 "Re-execing with stack size limited to %zd bytes.\n",
300 SetStackSizeLimitInBytes(kMaxStackSize
);
304 if (getlim(RLIMIT_AS
) != (rlim_t
)-1) {
305 Report("WARNING: Program is run with limited virtual address space,"
306 " which wouldn't work with ThreadSanitizer.\n");
307 Report("Re-execing with unlimited virtual address space.\n");
308 setlim(RLIMIT_AS
, -1);
320 return GetEnv(kTsanOptionsEnv
);
323 bool IsGlobalVar(uptr addr
) {
324 return g_data_start
&& addr
>= g_data_start
&& addr
< g_data_end
;
328 // Extract file descriptors passed to glibc internal __res_iclose function.
329 // This is required to properly "close" the fds, because we do not see internal
330 // closes within glibc. The code is a pure hack.
331 int ExtractResolvFDs(void *state
, int *fds
, int nfd
) {
333 __res_state
*statp
= (__res_state
*)state
;
334 for (int i
= 0; i
< MAXNS
&& cnt
< nfd
; i
++) {
335 if (statp
->_u
._ext
.nsaddrs
[i
] && statp
->_u
._ext
.nssocks
[i
] != -1)
336 fds
[cnt
++] = statp
->_u
._ext
.nssocks
[i
];
341 // Extract file descriptors passed via UNIX domain sockets.
342 // This is requried to properly handle "open" of these fds.
343 // see 'man recvmsg' and 'man 3 cmsg'.
344 int ExtractRecvmsgFDs(void *msgp
, int *fds
, int nfd
) {
346 msghdr
*msg
= (msghdr
*)msgp
;
347 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR(msg
);
348 for (; cmsg
; cmsg
= CMSG_NXTHDR(msg
, cmsg
)) {
349 if (cmsg
->cmsg_level
!= SOL_SOCKET
|| cmsg
->cmsg_type
!= SCM_RIGHTS
)
351 int n
= (cmsg
->cmsg_len
- CMSG_LEN(0)) / sizeof(fds
[0]);
352 for (int i
= 0; i
< n
; i
++) {
353 fds
[res
++] = ((int*)CMSG_DATA(cmsg
))[i
];
363 } // namespace __tsan
365 #endif // SANITIZER_LINUX