1 //===-- tsan_mman.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 //===----------------------------------------------------------------------===//
11 #include "sanitizer_common/sanitizer_common.h"
12 #include "sanitizer_common/sanitizer_placement_new.h"
13 #include "tsan_mman.h"
15 #include "tsan_report.h"
16 #include "tsan_flags.h"
18 // May be overriden by front-end.
19 extern "C" void WEAK
__tsan_malloc_hook(void *ptr
, uptr size
) {
24 extern "C" void WEAK
__tsan_free_hook(void *ptr
) {
30 static char allocator_placeholder
[sizeof(Allocator
)] ALIGNED(64);
31 Allocator
*allocator() {
32 return reinterpret_cast<Allocator
*>(&allocator_placeholder
);
35 void InitializeAllocator() {
39 void AlloctorThreadFinish(ThreadState
*thr
) {
40 allocator()->SwallowCache(&thr
->alloc_cache
);
43 static void SignalUnsafeCall(ThreadState
*thr
, uptr pc
) {
44 if (!thr
->in_signal_handler
|| !flags()->report_signal_unsafe
)
48 stack
.ObtainCurrent(thr
, pc
);
49 Lock
l(&ctx
->thread_mtx
);
50 ScopedReport
rep(ReportTypeSignalUnsafe
);
51 if (!IsFiredSuppression(ctx
, rep
, stack
)) {
53 OutputReport(ctx
, rep
, rep
.GetReport()->stacks
[0]);
57 void *user_alloc(ThreadState
*thr
, uptr pc
, uptr sz
, uptr align
) {
58 CHECK_GT(thr
->in_rtl
, 0);
59 void *p
= allocator()->Allocate(&thr
->alloc_cache
, sz
, align
);
62 MBlock
*b
= new(allocator()->GetMetaData(p
)) MBlock
;
65 b
->alloc_tid
= thr
->unique_id
;
66 b
->alloc_stack_id
= CurrentStackId(thr
, pc
);
67 if (CTX() && CTX()->initialized
) {
68 MemoryRangeImitateWrite(thr
, pc
, (uptr
)p
, sz
);
70 DPrintf("#%d: alloc(%zu) = %p\n", thr
->tid
, sz
, p
);
71 SignalUnsafeCall(thr
, pc
);
75 void user_free(ThreadState
*thr
, uptr pc
, void *p
) {
76 CHECK_GT(thr
->in_rtl
, 0);
77 CHECK_NE(p
, (void*)0);
78 DPrintf("#%d: free(%p)\n", thr
->tid
, p
);
79 MBlock
*b
= (MBlock
*)allocator()->GetMetaData(p
);
82 for (SyncVar
*s
= b
->head
; s
;) {
85 StatInc(thr
, StatSyncDestroyed
);
92 if (CTX() && CTX()->initialized
&& thr
->in_rtl
== 1) {
93 MemoryRangeFreed(thr
, pc
, (uptr
)p
, b
->size
);
96 allocator()->Deallocate(&thr
->alloc_cache
, p
);
97 SignalUnsafeCall(thr
, pc
);
100 void *user_realloc(ThreadState
*thr
, uptr pc
, void *p
, uptr sz
) {
101 CHECK_GT(thr
->in_rtl
, 0);
103 // FIXME: Handle "shrinking" more efficiently,
104 // it seems that some software actually does this.
106 p2
= user_alloc(thr
, pc
, sz
);
110 MBlock
*b
= user_mblock(thr
, p
);
111 internal_memcpy(p2
, p
, min(b
->size
, sz
));
115 user_free(thr
, pc
, p
);
120 MBlock
*user_mblock(ThreadState
*thr
, void *p
) {
121 CHECK_NE(p
, (void*)0);
122 Allocator
*a
= allocator();
123 void *b
= a
->GetBlockBegin(p
);
125 return (MBlock
*)a
->GetMetaData(b
);
128 void invoke_malloc_hook(void *ptr
, uptr size
) {
129 Context
*ctx
= CTX();
130 ThreadState
*thr
= cur_thread();
131 if (ctx
== 0 || !ctx
->initialized
|| thr
->in_rtl
)
133 __tsan_malloc_hook(ptr
, size
);
136 void invoke_free_hook(void *ptr
) {
137 Context
*ctx
= CTX();
138 ThreadState
*thr
= cur_thread();
139 if (ctx
== 0 || !ctx
->initialized
|| thr
->in_rtl
)
141 __tsan_free_hook(ptr
);
144 void *internal_alloc(MBlockType typ
, uptr sz
) {
145 ThreadState
*thr
= cur_thread();
146 CHECK_GT(thr
->in_rtl
, 0);
148 thr
->nomalloc
= 0; // CHECK calls internal_malloc().
151 return InternalAlloc(sz
);
154 void internal_free(void *p
) {
155 ThreadState
*thr
= cur_thread();
156 CHECK_GT(thr
->in_rtl
, 0);
158 thr
->nomalloc
= 0; // CHECK calls internal_malloc().
164 } // namespace __tsan