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 //===----------------------------------------------------------------------===//
15 #include "sanitizer_common/sanitizer_common.h"
16 #include "sanitizer_common/sanitizer_libc.h"
17 #include "sanitizer_common/sanitizer_procmaps.h"
18 #include "tsan_platform.h"
20 #include "tsan_flags.h"
22 #include <asm/prctl.h>
31 #include <sys/prctl.h>
32 #include <sys/syscall.h>
34 #include <sys/types.h>
35 #include <sys/resource.h>
42 extern "C" int arch_prctl(int code
, __sanitizer::uptr
*addr
);
47 ScopedInRtl::ScopedInRtl()
48 : thr_(cur_thread()) {
49 in_rtl_
= thr_
->in_rtl
;
54 ScopedInRtl::~ScopedInRtl() {
57 CHECK_EQ(in_rtl_
, thr_
->in_rtl
);
60 ScopedInRtl::ScopedInRtl() {
63 ScopedInRtl::~ScopedInRtl() {
67 uptr
GetShadowMemoryConsumption() {
71 void FlushShadowMemory() {
72 madvise((void*)kLinuxShadowBeg
,
73 kLinuxShadowEnd
- kLinuxShadowBeg
,
78 static void ProtectRange(uptr beg
, uptr end
) {
83 if (beg
!= (uptr
)Mprotect(beg
, end
- beg
)) {
84 Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg
, end
);
85 Printf("FATAL: Make sure you are not using unlimited stack\n");
92 void InitializeShadowMemory() {
93 uptr shadow
= (uptr
)MmapFixedNoReserve(kLinuxShadowBeg
,
94 kLinuxShadowEnd
- kLinuxShadowBeg
);
95 if (shadow
!= kLinuxShadowBeg
) {
96 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
97 Printf("FATAL: Make sure to compile with -fPIE and "
98 "to link with -pie (%p, %p).\n", shadow
, kLinuxShadowBeg
);
101 const uptr kClosedLowBeg
= 0x200000;
102 const uptr kClosedLowEnd
= kLinuxShadowBeg
- 1;
103 const uptr kClosedMidBeg
= kLinuxShadowEnd
+ 1;
104 const uptr kClosedMidEnd
= min(kLinuxAppMemBeg
, kTraceMemBegin
);
105 ProtectRange(kClosedLowBeg
, kClosedLowEnd
);
106 ProtectRange(kClosedMidBeg
, kClosedMidEnd
);
107 DPrintf("kClosedLow %zx-%zx (%zuGB)\n",
108 kClosedLowBeg
, kClosedLowEnd
, (kClosedLowEnd
- kClosedLowBeg
) >> 30);
109 DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
110 kLinuxShadowBeg
, kLinuxShadowEnd
,
111 (kLinuxShadowEnd
- kLinuxShadowBeg
) >> 30);
112 DPrintf("kClosedMid %zx-%zx (%zuGB)\n",
113 kClosedMidBeg
, kClosedMidEnd
, (kClosedMidEnd
- kClosedMidBeg
) >> 30);
114 DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
115 kLinuxAppMemBeg
, kLinuxAppMemEnd
,
116 (kLinuxAppMemEnd
- kLinuxAppMemBeg
) >> 30);
117 DPrintf("stack %zx\n", (uptr
)&shadow
);
121 void MapThreadTrace(uptr addr
, uptr size
) {
122 DPrintf("Mapping trace at %p-%p(0x%zx)\n", addr
, addr
+ size
, size
);
123 CHECK_GE(addr
, kTraceMemBegin
);
124 CHECK_LE(addr
+ size
, kTraceMemBegin
+ kTraceMemSize
);
125 if (addr
!= (uptr
)MmapFixedNoReserve(addr
, size
)) {
126 Printf("FATAL: ThreadSanitizer can not mmap thread trace\n");
131 static uptr g_data_start
;
132 static uptr g_data_end
;
135 static void CheckPIE() {
136 // Ensure that the binary is indeed compiled with -pie.
137 MemoryMappingLayout proc_maps
;
139 if (proc_maps
.Next(&start
, &end
,
140 /*offset*/0, /*filename*/0, /*filename_size*/0)) {
141 if ((u64
)start
< kLinuxAppMemBeg
) {
142 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
143 "something is mapped at 0x%zx < 0x%zx)\n",
144 start
, kLinuxAppMemBeg
);
145 Printf("FATAL: Make sure to compile with -fPIE"
146 " and to link with -pie.\n");
152 static void InitDataSeg() {
153 MemoryMappingLayout proc_maps
;
154 uptr start
, end
, offset
;
156 bool prev_is_data
= false;
157 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
))) {
158 DPrintf("%p-%p %p %s\n", start
, end
, offset
, name
);
159 bool is_data
= offset
!= 0 && name
[0] != 0;
160 // BSS may get merged with [heap] in /proc/self/maps. This is not very
162 bool is_bss
= offset
== 0 &&
163 (name
[0] == 0 || internal_strcmp(name
, "[heap]") == 0) && prev_is_data
;
164 if (g_data_start
== 0 && is_data
)
165 g_data_start
= start
;
168 prev_is_data
= is_data
;
170 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start
, g_data_end
);
171 CHECK_LT(g_data_start
, g_data_end
);
172 CHECK_GE((uptr
)&g_data_start
, g_data_start
);
173 CHECK_LT((uptr
)&g_data_start
, g_data_end
);
176 static uptr g_tls_size
;
179 # define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
181 # define INTERNAL_FUNCTION
183 extern "C" void _dl_get_tls_static_info(size_t*, size_t*)
184 __attribute__((weak
)) INTERNAL_FUNCTION
;
186 static int InitTlsSize() {
187 typedef void (*get_tls_func
)(size_t*, size_t*) INTERNAL_FUNCTION
;
188 get_tls_func get_tls
= &_dl_get_tls_static_info
;
190 void *get_tls_static_info_ptr
= dlsym(RTLD_NEXT
, "_dl_get_tls_static_info");
191 CHECK_EQ(sizeof(get_tls
), sizeof(get_tls_static_info_ptr
));
192 internal_memcpy(&get_tls
, &get_tls_static_info_ptr
,
193 sizeof(get_tls_static_info_ptr
));
195 CHECK_NE(get_tls
, 0);
197 size_t tls_align
= 0;
198 get_tls(&tls_size
, &tls_align
);
201 #endif // #ifndef TSAN_GO
203 static rlim_t
getlim(int res
) {
205 CHECK_EQ(0, getrlimit(res
, &rlim
));
206 return rlim
.rlim_cur
;
209 static void setlim(int res
, rlim_t lim
) {
210 // The following magic is to prevent clang from replacing it with memset.
211 volatile rlimit rlim
;
214 setrlimit(res
, (rlimit
*)&rlim
);
217 const char *InitializePlatform() {
219 if (sizeof(p
) == 8) {
220 // Disable core dumps, dumping of 16TB usually takes a bit long.
221 setlim(RLIMIT_CORE
, 0);
224 // TSan doesn't play well with unlimited stack size (as stack
225 // overlaps with shadow memory). If we detect unlimited stack size,
226 // we re-exec the program with limited stack size as a best effort.
227 if (getlim(RLIMIT_STACK
) == (rlim_t
)-1) {
228 const uptr kMaxStackSize
= 32 * 1024 * 1024;
229 Report("WARNING: Program is run with unlimited stack size, which "
230 "wouldn't work with ThreadSanitizer.\n");
231 Report("Re-execing with stack size limited to %zd bytes.\n", kMaxStackSize
);
232 SetStackSizeLimitInBytes(kMaxStackSize
);
236 if (getlim(RLIMIT_AS
) != (rlim_t
)-1) {
237 Report("WARNING: Program is run with limited virtual address space, which "
238 "wouldn't work with ThreadSanitizer.\n");
239 Report("Re-execing with unlimited virtual address space.\n");
240 setlim(RLIMIT_AS
, -1);
249 g_tls_size
= (uptr
)InitTlsSize();
252 return getenv(kTsanOptionsEnv
);
255 void FinalizePlatform() {
267 void GetThreadStackAndTls(bool main
, uptr
*stk_addr
, uptr
*stk_size
,
268 uptr
*tls_addr
, uptr
*tls_size
) {
270 arch_prctl(ARCH_GET_FS
, tls_addr
);
271 *tls_addr
-= g_tls_size
;
272 *tls_size
= g_tls_size
;
274 uptr stack_top
, stack_bottom
;
275 GetThreadStackTopAndBottom(main
, &stack_top
, &stack_bottom
);
276 *stk_addr
= stack_bottom
;
277 *stk_size
= stack_top
- stack_bottom
;
280 // If stack and tls intersect, make them non-intersecting.
281 if (*tls_addr
> *stk_addr
&& *tls_addr
< *stk_addr
+ *stk_size
) {
282 CHECK_GT(*tls_addr
+ *tls_size
, *stk_addr
);
283 CHECK_LE(*tls_addr
+ *tls_size
, *stk_addr
+ *stk_size
);
284 *stk_size
-= *tls_size
;
285 *tls_addr
= *stk_addr
+ *stk_size
;
296 bool IsGlobalVar(uptr addr
) {
297 return g_data_start
&& addr
>= g_data_start
&& addr
< g_data_end
;
300 } // namespace __tsan
302 #endif // #ifdef __linux__