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 FlushUnneededShadowMemory(kLinuxShadowBeg
, kLinuxShadowEnd
- kLinuxShadowBeg
);
76 static void ProtectRange(uptr beg
, uptr end
) {
81 if (beg
!= (uptr
)Mprotect(beg
, end
- beg
)) {
82 Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg
, end
);
83 Printf("FATAL: Make sure you are not using unlimited stack\n");
90 void InitializeShadowMemory() {
91 uptr shadow
= (uptr
)MmapFixedNoReserve(kLinuxShadowBeg
,
92 kLinuxShadowEnd
- kLinuxShadowBeg
);
93 if (shadow
!= kLinuxShadowBeg
) {
94 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
95 Printf("FATAL: Make sure to compile with -fPIE and "
96 "to link with -pie (%p, %p).\n", shadow
, kLinuxShadowBeg
);
99 const uptr kClosedLowBeg
= 0x200000;
100 const uptr kClosedLowEnd
= kLinuxShadowBeg
- 1;
101 const uptr kClosedMidBeg
= kLinuxShadowEnd
+ 1;
102 const uptr kClosedMidEnd
= min(kLinuxAppMemBeg
, kTraceMemBegin
);
103 ProtectRange(kClosedLowBeg
, kClosedLowEnd
);
104 ProtectRange(kClosedMidBeg
, kClosedMidEnd
);
105 DPrintf("kClosedLow %zx-%zx (%zuGB)\n",
106 kClosedLowBeg
, kClosedLowEnd
, (kClosedLowEnd
- kClosedLowBeg
) >> 30);
107 DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
108 kLinuxShadowBeg
, kLinuxShadowEnd
,
109 (kLinuxShadowEnd
- kLinuxShadowBeg
) >> 30);
110 DPrintf("kClosedMid %zx-%zx (%zuGB)\n",
111 kClosedMidBeg
, kClosedMidEnd
, (kClosedMidEnd
- kClosedMidBeg
) >> 30);
112 DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
113 kLinuxAppMemBeg
, kLinuxAppMemEnd
,
114 (kLinuxAppMemEnd
- kLinuxAppMemBeg
) >> 30);
115 DPrintf("stack %zx\n", (uptr
)&shadow
);
119 static uptr g_data_start
;
120 static uptr g_data_end
;
123 static void CheckPIE() {
124 // Ensure that the binary is indeed compiled with -pie.
125 MemoryMappingLayout proc_maps
;
127 if (proc_maps
.Next(&start
, &end
,
128 /*offset*/0, /*filename*/0, /*filename_size*/0)) {
129 if ((u64
)start
< kLinuxAppMemBeg
) {
130 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
131 "something is mapped at 0x%zx < 0x%zx)\n",
132 start
, kLinuxAppMemBeg
);
133 Printf("FATAL: Make sure to compile with -fPIE"
134 " and to link with -pie.\n");
140 static void InitDataSeg() {
141 MemoryMappingLayout proc_maps
;
142 uptr start
, end
, offset
;
144 bool prev_is_data
= false;
145 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
))) {
146 DPrintf("%p-%p %p %s\n", start
, end
, offset
, name
);
147 bool is_data
= offset
!= 0 && name
[0] != 0;
148 // BSS may get merged with [heap] in /proc/self/maps. This is not very
150 bool is_bss
= offset
== 0 &&
151 (name
[0] == 0 || internal_strcmp(name
, "[heap]") == 0) && prev_is_data
;
152 if (g_data_start
== 0 && is_data
)
153 g_data_start
= start
;
156 prev_is_data
= is_data
;
158 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start
, g_data_end
);
159 CHECK_LT(g_data_start
, g_data_end
);
160 CHECK_GE((uptr
)&g_data_start
, g_data_start
);
161 CHECK_LT((uptr
)&g_data_start
, g_data_end
);
164 static uptr g_tls_size
;
167 # define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
169 # define INTERNAL_FUNCTION
172 static int InitTlsSize() {
173 typedef void (*get_tls_func
)(size_t*, size_t*) INTERNAL_FUNCTION
;
174 get_tls_func get_tls
;
175 void *get_tls_static_info_ptr
= dlsym(RTLD_NEXT
, "_dl_get_tls_static_info");
176 CHECK_EQ(sizeof(get_tls
), sizeof(get_tls_static_info_ptr
));
177 internal_memcpy(&get_tls
, &get_tls_static_info_ptr
,
178 sizeof(get_tls_static_info_ptr
));
179 CHECK_NE(get_tls
, 0);
181 size_t tls_align
= 0;
182 get_tls(&tls_size
, &tls_align
);
185 #endif // #ifndef TSAN_GO
187 static rlim_t
getlim(int res
) {
189 CHECK_EQ(0, getrlimit(res
, &rlim
));
190 return rlim
.rlim_cur
;
193 static void setlim(int res
, rlim_t lim
) {
194 // The following magic is to prevent clang from replacing it with memset.
195 volatile rlimit rlim
;
198 setrlimit(res
, (rlimit
*)&rlim
);
201 const char *InitializePlatform() {
203 if (sizeof(p
) == 8) {
204 // Disable core dumps, dumping of 16TB usually takes a bit long.
205 setlim(RLIMIT_CORE
, 0);
208 // Go maps shadow memory lazily and works fine with limited address space.
209 // Unlimited stack is not a problem as well, because the executable
210 // is not compiled with -pie.
213 // TSan doesn't play well with unlimited stack size (as stack
214 // overlaps with shadow memory). If we detect unlimited stack size,
215 // we re-exec the program with limited stack size as a best effort.
216 if (getlim(RLIMIT_STACK
) == (rlim_t
)-1) {
217 const uptr kMaxStackSize
= 32 * 1024 * 1024;
218 Report("WARNING: Program is run with unlimited stack size, which "
219 "wouldn't work with ThreadSanitizer.\n");
220 Report("Re-execing with stack size limited to %zd bytes.\n",
222 SetStackSizeLimitInBytes(kMaxStackSize
);
226 if (getlim(RLIMIT_AS
) != (rlim_t
)-1) {
227 Report("WARNING: Program is run with limited virtual address space,"
228 " which wouldn't work with ThreadSanitizer.\n");
229 Report("Re-execing with unlimited virtual address space.\n");
230 setlim(RLIMIT_AS
, -1);
239 g_tls_size
= (uptr
)InitTlsSize();
242 return getenv(kTsanOptionsEnv
);
245 void FinalizePlatform() {
257 void GetThreadStackAndTls(bool main
, uptr
*stk_addr
, uptr
*stk_size
,
258 uptr
*tls_addr
, uptr
*tls_size
) {
260 arch_prctl(ARCH_GET_FS
, tls_addr
);
261 *tls_addr
-= g_tls_size
;
262 *tls_size
= g_tls_size
;
264 uptr stack_top
, stack_bottom
;
265 GetThreadStackTopAndBottom(main
, &stack_top
, &stack_bottom
);
266 *stk_addr
= stack_bottom
;
267 *stk_size
= stack_top
- stack_bottom
;
270 // If stack and tls intersect, make them non-intersecting.
271 if (*tls_addr
> *stk_addr
&& *tls_addr
< *stk_addr
+ *stk_size
) {
272 CHECK_GT(*tls_addr
+ *tls_size
, *stk_addr
);
273 CHECK_LE(*tls_addr
+ *tls_size
, *stk_addr
+ *stk_size
);
274 *stk_size
-= *tls_size
;
275 *tls_addr
= *stk_addr
+ *stk_size
;
286 bool IsGlobalVar(uptr addr
) {
287 return g_data_start
&& addr
>= g_data_start
&& addr
< g_data_end
;
290 } // namespace __tsan
292 #endif // #ifdef __linux__