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 //===----------------------------------------------------------------------===//
17 #include "sanitizer_common/sanitizer_common.h"
18 #include "sanitizer_common/sanitizer_libc.h"
19 #include "sanitizer_common/sanitizer_procmaps.h"
20 #include "tsan_platform.h"
22 #include "tsan_flags.h"
24 #include <asm/prctl.h>
33 #include <sys/prctl.h>
34 #include <sys/syscall.h>
36 #include <sys/types.h>
37 #include <sys/resource.h>
44 extern "C" int arch_prctl(int code
, __sanitizer::uptr
*addr
);
49 ScopedInRtl::ScopedInRtl()
50 : thr_(cur_thread()) {
51 in_rtl_
= thr_
->in_rtl
;
56 ScopedInRtl::~ScopedInRtl() {
59 CHECK_EQ(in_rtl_
, thr_
->in_rtl
);
62 ScopedInRtl::ScopedInRtl() {
65 ScopedInRtl::~ScopedInRtl() {
69 uptr
GetShadowMemoryConsumption() {
73 void FlushShadowMemory() {
74 madvise((void*)kLinuxShadowBeg
,
75 kLinuxShadowEnd
- kLinuxShadowBeg
,
80 static void ProtectRange(uptr beg
, uptr end
) {
85 if (beg
!= (uptr
)Mprotect(beg
, end
- beg
)) {
86 Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg
, end
);
87 Printf("FATAL: Make sure you are not using unlimited stack\n");
94 void InitializeShadowMemory() {
95 uptr shadow
= (uptr
)MmapFixedNoReserve(kLinuxShadowBeg
,
96 kLinuxShadowEnd
- kLinuxShadowBeg
);
97 if (shadow
!= kLinuxShadowBeg
) {
98 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
99 Printf("FATAL: Make sure to compile with -fPIE and "
100 "to link with -pie (%p, %p).\n", shadow
, kLinuxShadowBeg
);
103 const uptr kClosedLowBeg
= 0x200000;
104 const uptr kClosedLowEnd
= kLinuxShadowBeg
- 1;
105 const uptr kClosedMidBeg
= kLinuxShadowEnd
+ 1;
106 const uptr kClosedMidEnd
= min(kLinuxAppMemBeg
, kTraceMemBegin
);
107 ProtectRange(kClosedLowBeg
, kClosedLowEnd
);
108 ProtectRange(kClosedMidBeg
, kClosedMidEnd
);
109 DPrintf("kClosedLow %zx-%zx (%zuGB)\n",
110 kClosedLowBeg
, kClosedLowEnd
, (kClosedLowEnd
- kClosedLowBeg
) >> 30);
111 DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
112 kLinuxShadowBeg
, kLinuxShadowEnd
,
113 (kLinuxShadowEnd
- kLinuxShadowBeg
) >> 30);
114 DPrintf("kClosedMid %zx-%zx (%zuGB)\n",
115 kClosedMidBeg
, kClosedMidEnd
, (kClosedMidEnd
- kClosedMidBeg
) >> 30);
116 DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
117 kLinuxAppMemBeg
, kLinuxAppMemEnd
,
118 (kLinuxAppMemEnd
- kLinuxAppMemBeg
) >> 30);
119 DPrintf("stack %zx\n", (uptr
)&shadow
);
123 static uptr g_data_start
;
124 static uptr g_data_end
;
127 static void CheckPIE() {
128 // Ensure that the binary is indeed compiled with -pie.
129 MemoryMappingLayout proc_maps
;
131 if (proc_maps
.Next(&start
, &end
,
132 /*offset*/0, /*filename*/0, /*filename_size*/0)) {
133 if ((u64
)start
< kLinuxAppMemBeg
) {
134 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
135 "something is mapped at 0x%zx < 0x%zx)\n",
136 start
, kLinuxAppMemBeg
);
137 Printf("FATAL: Make sure to compile with -fPIE"
138 " and to link with -pie.\n");
144 static void InitDataSeg() {
145 MemoryMappingLayout proc_maps
;
146 uptr start
, end
, offset
;
148 bool prev_is_data
= false;
149 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
))) {
150 DPrintf("%p-%p %p %s\n", start
, end
, offset
, name
);
151 bool is_data
= offset
!= 0 && name
[0] != 0;
152 // BSS may get merged with [heap] in /proc/self/maps. This is not very
154 bool is_bss
= offset
== 0 &&
155 (name
[0] == 0 || internal_strcmp(name
, "[heap]") == 0) && prev_is_data
;
156 if (g_data_start
== 0 && is_data
)
157 g_data_start
= start
;
160 prev_is_data
= is_data
;
162 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start
, g_data_end
);
163 CHECK_LT(g_data_start
, g_data_end
);
164 CHECK_GE((uptr
)&g_data_start
, g_data_start
);
165 CHECK_LT((uptr
)&g_data_start
, g_data_end
);
168 static uptr g_tls_size
;
171 # define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
173 # define INTERNAL_FUNCTION
175 extern "C" void _dl_get_tls_static_info(size_t*, size_t*)
176 __attribute__((weak
)) INTERNAL_FUNCTION
;
178 static int InitTlsSize() {
179 typedef void (*get_tls_func
)(size_t*, size_t*) INTERNAL_FUNCTION
;
180 get_tls_func get_tls
= &_dl_get_tls_static_info
;
182 void *get_tls_static_info_ptr
= dlsym(RTLD_NEXT
, "_dl_get_tls_static_info");
183 CHECK_EQ(sizeof(get_tls
), sizeof(get_tls_static_info_ptr
));
184 internal_memcpy(&get_tls
, &get_tls_static_info_ptr
,
185 sizeof(get_tls_static_info_ptr
));
187 CHECK_NE(get_tls
, 0);
189 size_t tls_align
= 0;
190 get_tls(&tls_size
, &tls_align
);
193 #endif // #ifndef TSAN_GO
195 static rlim_t
getlim(int res
) {
197 CHECK_EQ(0, getrlimit(res
, &rlim
));
198 return rlim
.rlim_cur
;
201 static void setlim(int res
, rlim_t lim
) {
202 // The following magic is to prevent clang from replacing it with memset.
203 volatile rlimit rlim
;
206 setrlimit(res
, (rlimit
*)&rlim
);
209 const char *InitializePlatform() {
211 if (sizeof(p
) == 8) {
212 // Disable core dumps, dumping of 16TB usually takes a bit long.
213 setlim(RLIMIT_CORE
, 0);
216 // TSan doesn't play well with unlimited stack size (as stack
217 // overlaps with shadow memory). If we detect unlimited stack size,
218 // we re-exec the program with limited stack size as a best effort.
219 if (getlim(RLIMIT_STACK
) == (rlim_t
)-1) {
220 const uptr kMaxStackSize
= 32 * 1024 * 1024;
221 Report("WARNING: Program is run with unlimited stack size, which "
222 "wouldn't work with ThreadSanitizer.\n");
223 Report("Re-execing with stack size limited to %zd bytes.\n", kMaxStackSize
);
224 SetStackSizeLimitInBytes(kMaxStackSize
);
228 if (getlim(RLIMIT_AS
) != (rlim_t
)-1) {
229 Report("WARNING: Program is run with limited virtual address space, which "
230 "wouldn't work with ThreadSanitizer.\n");
231 Report("Re-execing with unlimited virtual address space.\n");
232 setlim(RLIMIT_AS
, -1);
241 g_tls_size
= (uptr
)InitTlsSize();
244 return getenv(kTsanOptionsEnv
);
247 void FinalizePlatform() {
259 void GetThreadStackAndTls(bool main
, uptr
*stk_addr
, uptr
*stk_size
,
260 uptr
*tls_addr
, uptr
*tls_size
) {
262 arch_prctl(ARCH_GET_FS
, tls_addr
);
263 *tls_addr
-= g_tls_size
;
264 *tls_size
= g_tls_size
;
266 uptr stack_top
, stack_bottom
;
267 GetThreadStackTopAndBottom(main
, &stack_top
, &stack_bottom
);
268 *stk_addr
= stack_bottom
;
269 *stk_size
= stack_top
- stack_bottom
;
272 // If stack and tls intersect, make them non-intersecting.
273 if (*tls_addr
> *stk_addr
&& *tls_addr
< *stk_addr
+ *stk_size
) {
274 CHECK_GT(*tls_addr
+ *tls_size
, *stk_addr
);
275 CHECK_LE(*tls_addr
+ *tls_size
, *stk_addr
+ *stk_size
);
276 *stk_size
-= *tls_size
;
277 *tls_addr
= *stk_addr
+ *stk_size
;
288 bool IsGlobalVar(uptr addr
) {
289 return g_data_start
&& addr
>= g_data_start
&& addr
< g_data_end
;
292 } // namespace __tsan
294 #endif // #ifdef __linux__