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>
41 #define __need_res_state
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 FlushUnneededShadowMemory(kLinuxShadowBeg
, 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 static uptr g_data_start
;
122 static uptr g_data_end
;
125 static void CheckPIE() {
126 // Ensure that the binary is indeed compiled with -pie.
127 MemoryMappingLayout proc_maps
;
129 if (proc_maps
.Next(&start
, &end
,
130 /*offset*/0, /*filename*/0, /*filename_size*/0)) {
131 if ((u64
)start
< kLinuxAppMemBeg
) {
132 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
133 "something is mapped at 0x%zx < 0x%zx)\n",
134 start
, kLinuxAppMemBeg
);
135 Printf("FATAL: Make sure to compile with -fPIE"
136 " and to link with -pie.\n");
142 static void InitDataSeg() {
143 MemoryMappingLayout proc_maps
;
144 uptr start
, end
, offset
;
146 bool prev_is_data
= false;
147 while (proc_maps
.Next(&start
, &end
, &offset
, name
, ARRAY_SIZE(name
))) {
148 DPrintf("%p-%p %p %s\n", start
, end
, offset
, name
);
149 bool is_data
= offset
!= 0 && name
[0] != 0;
150 // BSS may get merged with [heap] in /proc/self/maps. This is not very
152 bool is_bss
= offset
== 0 &&
153 (name
[0] == 0 || internal_strcmp(name
, "[heap]") == 0) && prev_is_data
;
154 if (g_data_start
== 0 && is_data
)
155 g_data_start
= start
;
158 prev_is_data
= is_data
;
160 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start
, g_data_end
);
161 CHECK_LT(g_data_start
, g_data_end
);
162 CHECK_GE((uptr
)&g_data_start
, g_data_start
);
163 CHECK_LT((uptr
)&g_data_start
, g_data_end
);
166 static uptr g_tls_size
;
169 # define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
171 # define INTERNAL_FUNCTION
174 static int InitTlsSize() {
175 typedef void (*get_tls_func
)(size_t*, size_t*) INTERNAL_FUNCTION
;
176 get_tls_func get_tls
;
177 void *get_tls_static_info_ptr
= dlsym(RTLD_NEXT
, "_dl_get_tls_static_info");
178 CHECK_EQ(sizeof(get_tls
), sizeof(get_tls_static_info_ptr
));
179 internal_memcpy(&get_tls
, &get_tls_static_info_ptr
,
180 sizeof(get_tls_static_info_ptr
));
181 CHECK_NE(get_tls
, 0);
183 size_t tls_align
= 0;
184 get_tls(&tls_size
, &tls_align
);
187 #endif // #ifndef TSAN_GO
189 static rlim_t
getlim(int res
) {
191 CHECK_EQ(0, getrlimit(res
, &rlim
));
192 return rlim
.rlim_cur
;
195 static void setlim(int res
, rlim_t lim
) {
196 // The following magic is to prevent clang from replacing it with memset.
197 volatile rlimit rlim
;
200 setrlimit(res
, (rlimit
*)&rlim
);
203 const char *InitializePlatform() {
205 if (sizeof(p
) == 8) {
206 // Disable core dumps, dumping of 16TB usually takes a bit long.
207 setlim(RLIMIT_CORE
, 0);
210 // Go maps shadow memory lazily and works fine with limited address space.
211 // Unlimited stack is not a problem as well, because the executable
212 // is not compiled with -pie.
215 // TSan doesn't play well with unlimited stack size (as stack
216 // overlaps with shadow memory). If we detect unlimited stack size,
217 // we re-exec the program with limited stack size as a best effort.
218 if (getlim(RLIMIT_STACK
) == (rlim_t
)-1) {
219 const uptr kMaxStackSize
= 32 * 1024 * 1024;
220 Report("WARNING: Program is run with unlimited stack size, which "
221 "wouldn't work with ThreadSanitizer.\n");
222 Report("Re-execing with stack size limited to %zd bytes.\n",
224 SetStackSizeLimitInBytes(kMaxStackSize
);
228 if (getlim(RLIMIT_AS
) != (rlim_t
)-1) {
229 Report("WARNING: Program is run with limited virtual address space,"
230 " which 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
;
293 int ExtractResolvFDs(void *state
, int *fds
, int nfd
) {
295 __res_state
*statp
= (__res_state
*)state
;
296 for (int i
= 0; i
< MAXNS
&& cnt
< nfd
; i
++) {
297 if (statp
->_u
._ext
.nsaddrs
[i
] && statp
->_u
._ext
.nssocks
[i
] != -1)
298 fds
[cnt
++] = statp
->_u
._ext
.nssocks
[i
];
305 } // namespace __tsan
307 #endif // #ifdef __linux__