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- and FreeBSD-specific code.
11 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common/sanitizer_platform.h"
15 #if SANITIZER_LINUX || SANITIZER_FREEBSD
17 #include "sanitizer_common/sanitizer_common.h"
18 #include "sanitizer_common/sanitizer_libc.h"
19 #include "sanitizer_common/sanitizer_posix.h"
20 #include "sanitizer_common/sanitizer_procmaps.h"
21 #include "sanitizer_common/sanitizer_stoptheworld.h"
22 #include "sanitizer_common/sanitizer_stackdepot.h"
23 #include "tsan_platform.h"
25 #include "tsan_flags.h"
35 #include <sys/syscall.h>
36 #include <sys/socket.h>
38 #include <sys/types.h>
39 #include <sys/resource.h>
46 #define __need_res_state
59 extern "C" void *__libc_stack_end
;
60 void *__libc_stack_end
= 0;
63 #if SANITIZER_LINUX && defined(__aarch64__)
64 void InitializeGuardPtr() __attribute__((visibility("hidden")));
69 static uptr g_data_start
;
70 static uptr g_data_end
;
84 void FillProfileCallback(uptr p
, uptr rss
, bool file
,
85 uptr
*mem
, uptr stats_size
) {
87 if (p
>= kShadowBeg
&& p
< kShadowEnd
)
88 mem
[MemShadow
] += rss
;
89 else if (p
>= kMetaShadowBeg
&& p
< kMetaShadowEnd
)
92 else if (p
>= kHeapMemBeg
&& p
< kHeapMemEnd
)
94 else if (p
>= kLoAppMemBeg
&& p
< kLoAppMemEnd
)
95 mem
[file
? MemFile
: MemMmap
] += rss
;
96 else if (p
>= kHiAppMemBeg
&& p
< kHiAppMemEnd
)
97 mem
[file
? MemFile
: MemMmap
] += rss
;
99 else if (p
>= kAppMemBeg
&& p
< kAppMemEnd
)
100 mem
[file
? MemFile
: MemMmap
] += rss
;
102 else if (p
>= kTraceMemBeg
&& p
< kTraceMemEnd
)
103 mem
[MemTrace
] += rss
;
105 mem
[MemOther
] += rss
;
108 void WriteMemoryProfile(char *buf
, uptr buf_size
, uptr nthread
, uptr nlive
) {
109 uptr mem
[MemCount
] = {};
110 __sanitizer::GetMemoryProfile(FillProfileCallback
, mem
, 7);
111 StackDepotStats
*stacks
= StackDepotGetStats();
112 internal_snprintf(buf
, buf_size
,
113 "RSS %zd MB: shadow:%zd meta:%zd file:%zd mmap:%zd"
114 " trace:%zd heap:%zd other:%zd stacks=%zd[%zd] nthr=%zd/%zd\n",
115 mem
[MemTotal
] >> 20, mem
[MemShadow
] >> 20, mem
[MemMeta
] >> 20,
116 mem
[MemFile
] >> 20, mem
[MemMmap
] >> 20, mem
[MemTrace
] >> 20,
117 mem
[MemHeap
] >> 20, mem
[MemOther
] >> 20,
118 stacks
->allocated
>> 20, stacks
->n_uniq_ids
,
123 void FlushShadowMemoryCallback(
124 const SuspendedThreadsList
&suspended_threads_list
,
126 FlushUnneededShadowMemory(kShadowBeg
, kShadowEnd
- kShadowBeg
);
130 void FlushShadowMemory() {
132 StopTheWorld(FlushShadowMemoryCallback
, 0);
137 // Mark shadow for .rodata sections with the special kShadowRodata marker.
138 // Accesses to .rodata can't race, so this saves time, memory and trace space.
139 static void MapRodata() {
140 // First create temp file.
141 const char *tmpdir
= GetEnv("TMPDIR");
143 tmpdir
= GetEnv("TEST_TMPDIR");
151 internal_snprintf(name
, sizeof(name
), "%s/tsan.rodata.%d",
152 tmpdir
, (int)internal_getpid());
153 uptr openrv
= internal_open(name
, O_RDWR
| O_CREAT
| O_EXCL
, 0600);
154 if (internal_iserror(openrv
))
156 internal_unlink(name
); // Unlink it now, so that we can reuse the buffer.
158 // Fill the file with kShadowRodata.
159 const uptr kMarkerSize
= 512 * 1024 / sizeof(u64
);
160 InternalScopedBuffer
<u64
> marker(kMarkerSize
);
161 // volatile to prevent insertion of memset
162 for (volatile u64
*p
= marker
.data(); p
< marker
.data() + kMarkerSize
; p
++)
164 internal_write(fd
, marker
.data(), marker
.size());
165 // Map the file into memory.
166 uptr page
= internal_mmap(0, GetPageSizeCached(), PROT_READ
| PROT_WRITE
,
167 MAP_PRIVATE
| MAP_ANONYMOUS
, fd
, 0);
168 if (internal_iserror(page
)) {
172 // Map the file into shadow of .rodata sections.
173 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
174 uptr start
, end
, offset
, prot
;
175 // Reusing the buffer 'name'.
176 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
), &prot
)) {
177 if (name
[0] != 0 && name
[0] != '['
178 && (prot
& MemoryMappingLayout::kProtectionRead
)
179 && (prot
& MemoryMappingLayout::kProtectionExecute
)
180 && !(prot
& MemoryMappingLayout::kProtectionWrite
)
181 && IsAppMem(start
)) {
182 // Assume it's .rodata
183 char *shadow_start
= (char*)MemToShadow(start
);
184 char *shadow_end
= (char*)MemToShadow(end
);
185 for (char *p
= shadow_start
; p
< shadow_end
; p
+= marker
.size()) {
186 internal_mmap(p
, Min
<uptr
>(marker
.size(), shadow_end
- p
),
187 PROT_READ
, MAP_PRIVATE
| MAP_FIXED
, fd
, 0);
194 void InitializeShadowMemoryPlatform() {
198 static void InitDataSeg() {
199 MemoryMappingLayout
proc_maps(true);
200 uptr start
, end
, offset
;
202 #if SANITIZER_FREEBSD
203 // On FreeBSD BSS is usually the last block allocated within the
204 // low range and heap is the last block allocated within the range
205 // 0x800000000-0x8ffffffff.
206 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
),
208 DPrintf("%p-%p %p %s\n", start
, end
, offset
, name
);
209 if ((start
& 0xffff00000000ULL
) == 0 && (end
& 0xffff00000000ULL
) == 0 &&
211 g_data_start
= start
;
216 bool prev_is_data
= false;
217 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
),
219 DPrintf("%p-%p %p %s\n", start
, end
, offset
, name
);
220 bool is_data
= offset
!= 0 && name
[0] != 0;
221 // BSS may get merged with [heap] in /proc/self/maps. This is not very
223 bool is_bss
= offset
== 0 &&
224 (name
[0] == 0 || internal_strcmp(name
, "[heap]") == 0) && prev_is_data
;
225 if (g_data_start
== 0 && is_data
)
226 g_data_start
= start
;
229 prev_is_data
= is_data
;
232 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start
, g_data_end
);
233 CHECK_LT(g_data_start
, g_data_end
);
234 CHECK_GE((uptr
)&g_data_start
, g_data_start
);
235 CHECK_LT((uptr
)&g_data_start
, g_data_end
);
238 #endif // #ifndef SANITIZER_GO
240 void InitializePlatform() {
241 DisableCoreDumperIfNecessary();
243 // Go maps shadow memory lazily and works fine with limited address space.
244 // Unlimited stack is not a problem as well, because the executable
245 // is not compiled with -pie.
248 // TSan doesn't play well with unlimited stack size (as stack
249 // overlaps with shadow memory). If we detect unlimited stack size,
250 // we re-exec the program with limited stack size as a best effort.
251 if (StackSizeIsUnlimited()) {
252 const uptr kMaxStackSize
= 32 * 1024 * 1024;
253 VReport(1, "Program is run with unlimited stack size, which wouldn't "
254 "work with ThreadSanitizer.\n"
255 "Re-execing with stack size limited to %zd bytes.\n",
257 SetStackSizeLimitInBytes(kMaxStackSize
);
261 if (!AddressSpaceIsUnlimited()) {
262 Report("WARNING: Program is run with limited virtual address space,"
263 " which wouldn't work with ThreadSanitizer.\n");
264 Report("Re-execing with unlimited virtual address space.\n");
265 SetAddressSpaceUnlimited();
268 #if SANITIZER_LINUX && defined(__aarch64__)
269 // Initialize the guard pointer used in {sig}{set,long}jump.
270 InitializeGuardPtr();
283 bool IsGlobalVar(uptr addr
) {
284 return g_data_start
&& addr
>= g_data_start
&& addr
< g_data_end
;
288 // Extract file descriptors passed to glibc internal __res_iclose function.
289 // This is required to properly "close" the fds, because we do not see internal
290 // closes within glibc. The code is a pure hack.
291 int ExtractResolvFDs(void *state
, int *fds
, int nfd
) {
294 __res_state
*statp
= (__res_state
*)state
;
295 for (int i
= 0; i
< MAXNS
&& cnt
< nfd
; i
++) {
296 if (statp
->_u
._ext
.nsaddrs
[i
] && statp
->_u
._ext
.nssocks
[i
] != -1)
297 fds
[cnt
++] = statp
->_u
._ext
.nssocks
[i
];
305 // Extract file descriptors passed via UNIX domain sockets.
306 // This is requried to properly handle "open" of these fds.
307 // see 'man recvmsg' and 'man 3 cmsg'.
308 int ExtractRecvmsgFDs(void *msgp
, int *fds
, int nfd
) {
310 msghdr
*msg
= (msghdr
*)msgp
;
311 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR(msg
);
312 for (; cmsg
; cmsg
= CMSG_NXTHDR(msg
, cmsg
)) {
313 if (cmsg
->cmsg_level
!= SOL_SOCKET
|| cmsg
->cmsg_type
!= SCM_RIGHTS
)
315 int n
= (cmsg
->cmsg_len
- CMSG_LEN(0)) / sizeof(fds
[0]);
316 for (int i
= 0; i
< n
; i
++) {
317 fds
[res
++] = ((int*)CMSG_DATA(cmsg
))[i
];
325 // Note: this function runs with async signals enabled,
326 // so it must not touch any tsan state.
327 int call_pthread_cancel_with_cleanup(int(*fn
)(void *c
, void *m
,
328 void *abstime
), void *c
, void *m
, void *abstime
,
329 void(*cleanup
)(void *arg
), void *arg
) {
330 // pthread_cleanup_push/pop are hardcore macros mess.
331 // We can't intercept nor call them w/o including pthread.h.
333 pthread_cleanup_push(cleanup
, arg
);
334 res
= fn(c
, m
, abstime
);
335 pthread_cleanup_pop(0);
341 void ReplaceSystemMalloc() { }
344 } // namespace __tsan
346 #endif // SANITIZER_LINUX || SANITIZER_FREEBSD