1 //===-- tsan_rtl_thread.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 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common/sanitizer_placement_new.h"
14 #include "tsan_mman.h"
15 #include "tsan_platform.h"
16 #include "tsan_report.h"
17 #include "tsan_sync.h"
22 const int kThreadQuarantineSize
= 16;
24 const int kThreadQuarantineSize
= 64;
27 static void MaybeReportThreadLeak(ThreadContext
*tctx
) {
30 if (tctx
->status
!= ThreadStatusCreated
31 && tctx
->status
!= ThreadStatusRunning
32 && tctx
->status
!= ThreadStatusFinished
)
34 ScopedReport
rep(ReportTypeThreadLeak
);
36 OutputReport(CTX(), rep
);
39 void ThreadFinalize(ThreadState
*thr
) {
40 CHECK_GT(thr
->in_rtl
, 0);
41 if (!flags()->report_thread_leaks
)
44 Lock
l(&ctx
->thread_mtx
);
45 for (unsigned i
= 0; i
< kMaxTid
; i
++) {
46 ThreadContext
*tctx
= ctx
->threads
[i
];
49 MaybeReportThreadLeak(tctx
);
53 int ThreadCount(ThreadState
*thr
) {
54 CHECK_GT(thr
->in_rtl
, 0);
56 Lock
l(&ctx
->thread_mtx
);
58 for (unsigned i
= 0; i
< kMaxTid
; i
++) {
59 ThreadContext
*tctx
= ctx
->threads
[i
];
62 if (tctx
->status
!= ThreadStatusCreated
63 && tctx
->status
!= ThreadStatusRunning
)
70 static void ThreadDead(ThreadState
*thr
, ThreadContext
*tctx
) {
72 CHECK_GT(thr
->in_rtl
, 0);
73 CHECK(tctx
->status
== ThreadStatusRunning
74 || tctx
->status
== ThreadStatusFinished
);
75 DPrintf("#%d: ThreadDead uid=%zu\n", thr
->tid
, tctx
->user_id
);
76 tctx
->status
= ThreadStatusDead
;
82 if (ctx
->dead_list_size
== 0)
83 ctx
->dead_list_head
= tctx
;
85 ctx
->dead_list_tail
->dead_next
= tctx
;
86 ctx
->dead_list_tail
= tctx
;
87 ctx
->dead_list_size
++;
90 int ThreadCreate(ThreadState
*thr
, uptr pc
, uptr uid
, bool detached
) {
91 CHECK_GT(thr
->in_rtl
, 0);
93 Lock
l(&ctx
->thread_mtx
);
94 StatInc(thr
, StatThreadCreate
);
96 ThreadContext
*tctx
= 0;
97 if (ctx
->dead_list_size
> kThreadQuarantineSize
98 || ctx
->thread_seq
>= kMaxTid
) {
99 // Reusing old thread descriptor and tid.
100 if (ctx
->dead_list_size
== 0) {
101 Printf("ThreadSanitizer: %d thread limit exceeded. Dying.\n",
105 StatInc(thr
, StatThreadReuse
);
106 tctx
= ctx
->dead_list_head
;
107 ctx
->dead_list_head
= tctx
->dead_next
;
108 ctx
->dead_list_size
--;
109 if (ctx
->dead_list_size
== 0) {
110 CHECK_EQ(tctx
->dead_next
, 0);
111 ctx
->dead_list_head
= 0;
113 CHECK_EQ(tctx
->status
, ThreadStatusDead
);
114 tctx
->status
= ThreadStatusInvalid
;
118 DestroyAndFree(tctx
->dead_info
);
120 internal_free(tctx
->name
);
124 // Allocating new thread descriptor and tid.
125 StatInc(thr
, StatThreadMaxTid
);
126 tid
= ctx
->thread_seq
++;
127 void *mem
= internal_alloc(MBlockThreadContex
, sizeof(ThreadContext
));
128 tctx
= new(mem
) ThreadContext(tid
);
129 ctx
->threads
[tid
] = tctx
;
130 MapThreadTrace(GetThreadTrace(tid
), TraceSize() * sizeof(Event
));
134 CHECK_LT(tid
, kMaxTid
);
135 DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr
->tid
, tid
, uid
);
136 CHECK_EQ(tctx
->status
, ThreadStatusInvalid
);
137 ctx
->alive_threads
++;
138 if (ctx
->max_alive_threads
< ctx
->alive_threads
) {
139 ctx
->max_alive_threads
++;
140 CHECK_EQ(ctx
->max_alive_threads
, ctx
->alive_threads
);
141 StatInc(thr
, StatThreadMaxAlive
);
143 tctx
->status
= ThreadStatusCreated
;
146 tctx
->unique_id
= ctx
->unique_thread_seq
++;
147 tctx
->detached
= detached
;
149 thr
->fast_state
.IncrementEpoch();
150 // Can't increment epoch w/o writing to the trace as well.
151 TraceAddEvent(thr
, thr
->fast_state
, EventTypeMop
, 0);
152 thr
->clock
.set(thr
->tid
, thr
->fast_state
.epoch());
153 thr
->fast_synch_epoch
= thr
->fast_state
.epoch();
154 thr
->clock
.release(&tctx
->sync
);
155 StatInc(thr
, StatSyncRelease
);
156 tctx
->creation_stack
.ObtainCurrent(thr
, pc
);
157 tctx
->creation_tid
= thr
->tid
;
162 void ThreadStart(ThreadState
*thr
, int tid
, uptr os_id
) {
163 CHECK_GT(thr
->in_rtl
, 0);
168 GetThreadStackAndTls(tid
== 0, &stk_addr
, &stk_size
, &tls_addr
, &tls_size
);
171 if (stk_addr
&& stk_size
) {
172 MemoryResetRange(thr
, /*pc=*/ 1, stk_addr
, stk_size
);
175 if (tls_addr
&& tls_size
) {
176 // Check that the thr object is in tls;
177 const uptr thr_beg
= (uptr
)thr
;
178 const uptr thr_end
= (uptr
)thr
+ sizeof(*thr
);
179 CHECK_GE(thr_beg
, tls_addr
);
180 CHECK_LE(thr_beg
, tls_addr
+ tls_size
);
181 CHECK_GE(thr_end
, tls_addr
);
182 CHECK_LE(thr_end
, tls_addr
+ tls_size
);
183 // Since the thr object is huge, skip it.
184 MemoryResetRange(thr
, /*pc=*/ 2, tls_addr
, thr_beg
- tls_addr
);
185 MemoryResetRange(thr
, /*pc=*/ 2, thr_end
, tls_addr
+ tls_size
- thr_end
);
189 Lock
l(&CTX()->thread_mtx
);
190 ThreadContext
*tctx
= CTX()->threads
[tid
];
192 CHECK_EQ(tctx
->status
, ThreadStatusCreated
);
193 tctx
->status
= ThreadStatusRunning
;
195 // RoundUp so that one trace part does not contain events
196 // from different threads.
197 tctx
->epoch0
= RoundUp(tctx
->epoch1
+ 1, kTracePartSize
);
198 tctx
->epoch1
= (u64
)-1;
199 new(thr
) ThreadState(CTX(), tid
, tctx
->unique_id
,
200 tctx
->epoch0
, stk_addr
, stk_size
,
203 // Setup dynamic shadow stack.
204 const int kInitStackSize
= 8;
205 thr
->shadow_stack
= (uptr
*)internal_alloc(MBlockShadowStack
,
206 kInitStackSize
* sizeof(uptr
));
207 thr
->shadow_stack_pos
= thr
->shadow_stack
;
208 thr
->shadow_stack_end
= thr
->shadow_stack
+ kInitStackSize
;
211 AllocatorThreadStart(thr
);
214 thr
->fast_synch_epoch
= tctx
->epoch0
;
215 thr
->clock
.set(tid
, tctx
->epoch0
);
216 thr
->clock
.acquire(&tctx
->sync
);
217 thr
->fast_state
.SetHistorySize(flags()->history_size
);
218 const uptr trace
= (tctx
->epoch0
/ kTracePartSize
) % TraceParts();
219 thr
->trace
.headers
[trace
].epoch0
= tctx
->epoch0
;
220 StatInc(thr
, StatSyncAcquire
);
221 DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
222 "tls_addr=%zx tls_size=%zx\n",
223 tid
, (uptr
)tctx
->epoch0
, stk_addr
, stk_size
, tls_addr
, tls_size
);
224 thr
->is_alive
= true;
227 void ThreadFinish(ThreadState
*thr
) {
228 CHECK_GT(thr
->in_rtl
, 0);
229 StatInc(thr
, StatThreadFinish
);
230 // FIXME: Treat it as write.
231 if (thr
->stk_addr
&& thr
->stk_size
)
232 MemoryResetRange(thr
, /*pc=*/ 3, thr
->stk_addr
, thr
->stk_size
);
233 if (thr
->tls_addr
&& thr
->tls_size
) {
234 const uptr thr_beg
= (uptr
)thr
;
235 const uptr thr_end
= (uptr
)thr
+ sizeof(*thr
);
236 // Since the thr object is huge, skip it.
237 MemoryResetRange(thr
, /*pc=*/ 4, thr
->tls_addr
, thr_beg
- thr
->tls_addr
);
238 MemoryResetRange(thr
, /*pc=*/ 5,
239 thr_end
, thr
->tls_addr
+ thr
->tls_size
- thr_end
);
241 thr
->is_alive
= false;
242 Context
*ctx
= CTX();
243 Lock
l(&ctx
->thread_mtx
);
244 ThreadContext
*tctx
= ctx
->threads
[thr
->tid
];
246 CHECK_EQ(tctx
->status
, ThreadStatusRunning
);
247 CHECK_GT(ctx
->alive_threads
, 0);
248 ctx
->alive_threads
--;
249 if (tctx
->detached
) {
250 ThreadDead(thr
, tctx
);
252 thr
->fast_state
.IncrementEpoch();
253 // Can't increment epoch w/o writing to the trace as well.
254 TraceAddEvent(thr
, thr
->fast_state
, EventTypeMop
, 0);
255 thr
->clock
.set(thr
->tid
, thr
->fast_state
.epoch());
256 thr
->fast_synch_epoch
= thr
->fast_state
.epoch();
257 thr
->clock
.release(&tctx
->sync
);
258 StatInc(thr
, StatSyncRelease
);
259 tctx
->status
= ThreadStatusFinished
;
262 // Save from info about the thread.
263 tctx
->dead_info
= new(internal_alloc(MBlockDeadInfo
, sizeof(ThreadDeadInfo
)))
265 for (uptr i
= 0; i
< TraceParts(); i
++) {
266 tctx
->dead_info
->trace
.headers
[i
].epoch0
= thr
->trace
.headers
[i
].epoch0
;
267 tctx
->dead_info
->trace
.headers
[i
].stack0
.CopyFrom(
268 thr
->trace
.headers
[i
].stack0
);
270 tctx
->epoch1
= thr
->fast_state
.epoch();
273 AllocatorThreadFinish(thr
);
276 StatAggregate(ctx
->stat
, thr
->stat
);
280 int ThreadTid(ThreadState
*thr
, uptr pc
, uptr uid
) {
281 CHECK_GT(thr
->in_rtl
, 0);
282 Context
*ctx
= CTX();
283 Lock
l(&ctx
->thread_mtx
);
285 for (unsigned tid
= 0; tid
< kMaxTid
; tid
++) {
286 ThreadContext
*tctx
= ctx
->threads
[tid
];
287 if (tctx
!= 0 && tctx
->user_id
== uid
288 && tctx
->status
!= ThreadStatusInvalid
) {
294 DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr
->tid
, uid
, res
);
298 void ThreadJoin(ThreadState
*thr
, uptr pc
, int tid
) {
299 CHECK_GT(thr
->in_rtl
, 0);
301 CHECK_LT(tid
, kMaxTid
);
302 DPrintf("#%d: ThreadJoin tid=%d\n", thr
->tid
, tid
);
303 Context
*ctx
= CTX();
304 Lock
l(&ctx
->thread_mtx
);
305 ThreadContext
*tctx
= ctx
->threads
[tid
];
306 if (tctx
->status
== ThreadStatusInvalid
) {
307 Printf("ThreadSanitizer: join of non-existent thread\n");
310 // FIXME(dvyukov): print message and continue (it's user error).
311 CHECK_EQ(tctx
->detached
, false);
312 CHECK_EQ(tctx
->status
, ThreadStatusFinished
);
313 thr
->clock
.acquire(&tctx
->sync
);
314 StatInc(thr
, StatSyncAcquire
);
315 ThreadDead(thr
, tctx
);
318 void ThreadDetach(ThreadState
*thr
, uptr pc
, int tid
) {
319 CHECK_GT(thr
->in_rtl
, 0);
321 CHECK_LT(tid
, kMaxTid
);
322 Context
*ctx
= CTX();
323 Lock
l(&ctx
->thread_mtx
);
324 ThreadContext
*tctx
= ctx
->threads
[tid
];
325 if (tctx
->status
== ThreadStatusInvalid
) {
326 Printf("ThreadSanitizer: detach of non-existent thread\n");
329 if (tctx
->status
== ThreadStatusFinished
) {
330 ThreadDead(thr
, tctx
);
332 tctx
->detached
= true;
336 void ThreadSetName(ThreadState
*thr
, const char *name
) {
337 Context
*ctx
= CTX();
338 Lock
l(&ctx
->thread_mtx
);
339 ThreadContext
*tctx
= ctx
->threads
[thr
->tid
];
341 CHECK_EQ(tctx
->status
, ThreadStatusRunning
);
343 internal_free(tctx
->name
);
347 tctx
->name
= internal_strdup(name
);
350 void MemoryAccessRange(ThreadState
*thr
, uptr pc
, uptr addr
,
351 uptr size
, bool is_write
) {
355 u64
*shadow_mem
= (u64
*)MemToShadow(addr
);
356 DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n",
357 thr
->tid
, (void*)pc
, (void*)addr
,
358 (int)size
, is_write
);
361 if (!IsAppMem(addr
)) {
362 Printf("Access to non app mem %zx\n", addr
);
363 DCHECK(IsAppMem(addr
));
365 if (!IsAppMem(addr
+ size
- 1)) {
366 Printf("Access to non app mem %zx\n", addr
+ size
- 1);
367 DCHECK(IsAppMem(addr
+ size
- 1));
369 if (!IsShadowMem((uptr
)shadow_mem
)) {
370 Printf("Bad shadow addr %p (%zx)\n", shadow_mem
, addr
);
371 DCHECK(IsShadowMem((uptr
)shadow_mem
));
373 if (!IsShadowMem((uptr
)(shadow_mem
+ size
* kShadowCnt
/ 8 - 1))) {
374 Printf("Bad shadow addr %p (%zx)\n",
375 shadow_mem
+ size
* kShadowCnt
/ 8 - 1, addr
+ size
- 1);
376 DCHECK(IsShadowMem((uptr
)(shadow_mem
+ size
* kShadowCnt
/ 8 - 1)));
380 StatInc(thr
, StatMopRange
);
382 FastState fast_state
= thr
->fast_state
;
383 if (fast_state
.GetIgnoreBit())
386 fast_state
.IncrementEpoch();
387 thr
->fast_state
= fast_state
;
388 TraceAddEvent(thr
, fast_state
, EventTypeMop
, pc
);
390 bool unaligned
= (addr
% kShadowCell
) != 0;
392 // Handle unaligned beginning, if any.
393 for (; addr
% kShadowCell
&& size
; addr
++, size
--) {
394 int const kAccessSizeLog
= 0;
395 Shadow
cur(fast_state
);
396 cur
.SetWrite(is_write
);
397 cur
.SetAddr0AndSizeLog(addr
& (kShadowCell
- 1), kAccessSizeLog
);
398 MemoryAccessImpl(thr
, addr
, kAccessSizeLog
, is_write
, false,
402 shadow_mem
+= kShadowCnt
;
403 // Handle middle part, if any.
404 for (; size
>= kShadowCell
; addr
+= kShadowCell
, size
-= kShadowCell
) {
405 int const kAccessSizeLog
= 3;
406 Shadow
cur(fast_state
);
407 cur
.SetWrite(is_write
);
408 cur
.SetAddr0AndSizeLog(0, kAccessSizeLog
);
409 MemoryAccessImpl(thr
, addr
, kAccessSizeLog
, is_write
, false,
411 shadow_mem
+= kShadowCnt
;
413 // Handle ending, if any.
414 for (; size
; addr
++, size
--) {
415 int const kAccessSizeLog
= 0;
416 Shadow
cur(fast_state
);
417 cur
.SetWrite(is_write
);
418 cur
.SetAddr0AndSizeLog(addr
& (kShadowCell
- 1), kAccessSizeLog
);
419 MemoryAccessImpl(thr
, addr
, kAccessSizeLog
, is_write
, false,
424 void MemoryAccessRangeStep(ThreadState
*thr
, uptr pc
, uptr addr
,
425 uptr size
, uptr step
, bool is_write
) {
428 FastState fast_state
= thr
->fast_state
;
429 if (fast_state
.GetIgnoreBit())
431 StatInc(thr
, StatMopRange
);
432 fast_state
.IncrementEpoch();
433 thr
->fast_state
= fast_state
;
434 TraceAddEvent(thr
, fast_state
, EventTypeMop
, pc
);
436 for (uptr addr_end
= addr
+ size
; addr
< addr_end
; addr
+= step
) {
437 u64
*shadow_mem
= (u64
*)MemToShadow(addr
);
438 Shadow
cur(fast_state
);
439 cur
.SetWrite(is_write
);
440 cur
.SetAddr0AndSizeLog(addr
& (kShadowCell
- 1), kSizeLog1
);
441 MemoryAccessImpl(thr
, addr
, kSizeLog1
, is_write
, false,
445 } // namespace __tsan