xref: /aosp_15_r20/external/compiler-rt/lib/tsan/rtl/tsan_mman.cc (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //===-- tsan_mman.cc ------------------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot //                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of ThreadSanitizer (TSan), a race detector.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
13*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_allocator_interface.h"
14*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common.h"
15*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_placement_new.h"
16*7c3d14c8STreehugger Robot #include "tsan_mman.h"
17*7c3d14c8STreehugger Robot #include "tsan_rtl.h"
18*7c3d14c8STreehugger Robot #include "tsan_report.h"
19*7c3d14c8STreehugger Robot #include "tsan_flags.h"
20*7c3d14c8STreehugger Robot 
21*7c3d14c8STreehugger Robot // May be overriden by front-end.
22*7c3d14c8STreehugger Robot SANITIZER_WEAK_DEFAULT_IMPL
__sanitizer_malloc_hook(void * ptr,uptr size)23*7c3d14c8STreehugger Robot void __sanitizer_malloc_hook(void *ptr, uptr size) {
24*7c3d14c8STreehugger Robot   (void)ptr;
25*7c3d14c8STreehugger Robot   (void)size;
26*7c3d14c8STreehugger Robot }
27*7c3d14c8STreehugger Robot 
28*7c3d14c8STreehugger Robot SANITIZER_WEAK_DEFAULT_IMPL
__sanitizer_free_hook(void * ptr)29*7c3d14c8STreehugger Robot void __sanitizer_free_hook(void *ptr) {
30*7c3d14c8STreehugger Robot   (void)ptr;
31*7c3d14c8STreehugger Robot }
32*7c3d14c8STreehugger Robot 
33*7c3d14c8STreehugger Robot namespace __tsan {
34*7c3d14c8STreehugger Robot 
35*7c3d14c8STreehugger Robot struct MapUnmapCallback {
OnMap__tsan::MapUnmapCallback36*7c3d14c8STreehugger Robot   void OnMap(uptr p, uptr size) const { }
OnUnmap__tsan::MapUnmapCallback37*7c3d14c8STreehugger Robot   void OnUnmap(uptr p, uptr size) const {
38*7c3d14c8STreehugger Robot     // We are about to unmap a chunk of user memory.
39*7c3d14c8STreehugger Robot     // Mark the corresponding shadow memory as not needed.
40*7c3d14c8STreehugger Robot     DontNeedShadowFor(p, size);
41*7c3d14c8STreehugger Robot     // Mark the corresponding meta shadow memory as not needed.
42*7c3d14c8STreehugger Robot     // Note the block does not contain any meta info at this point
43*7c3d14c8STreehugger Robot     // (this happens after free).
44*7c3d14c8STreehugger Robot     const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize;
45*7c3d14c8STreehugger Robot     const uptr kPageSize = GetPageSizeCached() * kMetaRatio;
46*7c3d14c8STreehugger Robot     // Block came from LargeMmapAllocator, so must be large.
47*7c3d14c8STreehugger Robot     // We rely on this in the calculations below.
48*7c3d14c8STreehugger Robot     CHECK_GE(size, 2 * kPageSize);
49*7c3d14c8STreehugger Robot     uptr diff = RoundUp(p, kPageSize) - p;
50*7c3d14c8STreehugger Robot     if (diff != 0) {
51*7c3d14c8STreehugger Robot       p += diff;
52*7c3d14c8STreehugger Robot       size -= diff;
53*7c3d14c8STreehugger Robot     }
54*7c3d14c8STreehugger Robot     diff = p + size - RoundDown(p + size, kPageSize);
55*7c3d14c8STreehugger Robot     if (diff != 0)
56*7c3d14c8STreehugger Robot       size -= diff;
57*7c3d14c8STreehugger Robot     FlushUnneededShadowMemory((uptr)MemToMeta(p), size / kMetaRatio);
58*7c3d14c8STreehugger Robot   }
59*7c3d14c8STreehugger Robot };
60*7c3d14c8STreehugger Robot 
61*7c3d14c8STreehugger Robot static char allocator_placeholder[sizeof(Allocator)] ALIGNED(64);
allocator()62*7c3d14c8STreehugger Robot Allocator *allocator() {
63*7c3d14c8STreehugger Robot   return reinterpret_cast<Allocator*>(&allocator_placeholder);
64*7c3d14c8STreehugger Robot }
65*7c3d14c8STreehugger Robot 
66*7c3d14c8STreehugger Robot struct GlobalProc {
67*7c3d14c8STreehugger Robot   Mutex mtx;
68*7c3d14c8STreehugger Robot   Processor *proc;
69*7c3d14c8STreehugger Robot 
GlobalProc__tsan::GlobalProc70*7c3d14c8STreehugger Robot   GlobalProc()
71*7c3d14c8STreehugger Robot       : mtx(MutexTypeGlobalProc, StatMtxGlobalProc)
72*7c3d14c8STreehugger Robot       , proc(ProcCreate()) {
73*7c3d14c8STreehugger Robot   }
74*7c3d14c8STreehugger Robot };
75*7c3d14c8STreehugger Robot 
76*7c3d14c8STreehugger Robot static char global_proc_placeholder[sizeof(GlobalProc)] ALIGNED(64);
global_proc()77*7c3d14c8STreehugger Robot GlobalProc *global_proc() {
78*7c3d14c8STreehugger Robot   return reinterpret_cast<GlobalProc*>(&global_proc_placeholder);
79*7c3d14c8STreehugger Robot }
80*7c3d14c8STreehugger Robot 
ScopedGlobalProcessor()81*7c3d14c8STreehugger Robot ScopedGlobalProcessor::ScopedGlobalProcessor() {
82*7c3d14c8STreehugger Robot   GlobalProc *gp = global_proc();
83*7c3d14c8STreehugger Robot   ThreadState *thr = cur_thread();
84*7c3d14c8STreehugger Robot   if (thr->proc())
85*7c3d14c8STreehugger Robot     return;
86*7c3d14c8STreehugger Robot   // If we don't have a proc, use the global one.
87*7c3d14c8STreehugger Robot   // There are currently only two known case where this path is triggered:
88*7c3d14c8STreehugger Robot   //   __interceptor_free
89*7c3d14c8STreehugger Robot   //   __nptl_deallocate_tsd
90*7c3d14c8STreehugger Robot   //   start_thread
91*7c3d14c8STreehugger Robot   //   clone
92*7c3d14c8STreehugger Robot   // and:
93*7c3d14c8STreehugger Robot   //   ResetRange
94*7c3d14c8STreehugger Robot   //   __interceptor_munmap
95*7c3d14c8STreehugger Robot   //   __deallocate_stack
96*7c3d14c8STreehugger Robot   //   start_thread
97*7c3d14c8STreehugger Robot   //   clone
98*7c3d14c8STreehugger Robot   // Ideally, we destroy thread state (and unwire proc) when a thread actually
99*7c3d14c8STreehugger Robot   // exits (i.e. when we join/wait it). Then we would not need the global proc
100*7c3d14c8STreehugger Robot   gp->mtx.Lock();
101*7c3d14c8STreehugger Robot   ProcWire(gp->proc, thr);
102*7c3d14c8STreehugger Robot }
103*7c3d14c8STreehugger Robot 
~ScopedGlobalProcessor()104*7c3d14c8STreehugger Robot ScopedGlobalProcessor::~ScopedGlobalProcessor() {
105*7c3d14c8STreehugger Robot   GlobalProc *gp = global_proc();
106*7c3d14c8STreehugger Robot   ThreadState *thr = cur_thread();
107*7c3d14c8STreehugger Robot   if (thr->proc() != gp->proc)
108*7c3d14c8STreehugger Robot     return;
109*7c3d14c8STreehugger Robot   ProcUnwire(gp->proc, thr);
110*7c3d14c8STreehugger Robot   gp->mtx.Unlock();
111*7c3d14c8STreehugger Robot }
112*7c3d14c8STreehugger Robot 
InitializeAllocator()113*7c3d14c8STreehugger Robot void InitializeAllocator() {
114*7c3d14c8STreehugger Robot   allocator()->Init(common_flags()->allocator_may_return_null);
115*7c3d14c8STreehugger Robot }
116*7c3d14c8STreehugger Robot 
InitializeAllocatorLate()117*7c3d14c8STreehugger Robot void InitializeAllocatorLate() {
118*7c3d14c8STreehugger Robot   new(global_proc()) GlobalProc();
119*7c3d14c8STreehugger Robot }
120*7c3d14c8STreehugger Robot 
AllocatorProcStart(Processor * proc)121*7c3d14c8STreehugger Robot void AllocatorProcStart(Processor *proc) {
122*7c3d14c8STreehugger Robot   allocator()->InitCache(&proc->alloc_cache);
123*7c3d14c8STreehugger Robot   internal_allocator()->InitCache(&proc->internal_alloc_cache);
124*7c3d14c8STreehugger Robot }
125*7c3d14c8STreehugger Robot 
AllocatorProcFinish(Processor * proc)126*7c3d14c8STreehugger Robot void AllocatorProcFinish(Processor *proc) {
127*7c3d14c8STreehugger Robot   allocator()->DestroyCache(&proc->alloc_cache);
128*7c3d14c8STreehugger Robot   internal_allocator()->DestroyCache(&proc->internal_alloc_cache);
129*7c3d14c8STreehugger Robot }
130*7c3d14c8STreehugger Robot 
AllocatorPrintStats()131*7c3d14c8STreehugger Robot void AllocatorPrintStats() {
132*7c3d14c8STreehugger Robot   allocator()->PrintStats();
133*7c3d14c8STreehugger Robot }
134*7c3d14c8STreehugger Robot 
SignalUnsafeCall(ThreadState * thr,uptr pc)135*7c3d14c8STreehugger Robot static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
136*7c3d14c8STreehugger Robot   if (atomic_load_relaxed(&thr->in_signal_handler) == 0 ||
137*7c3d14c8STreehugger Robot       !flags()->report_signal_unsafe)
138*7c3d14c8STreehugger Robot     return;
139*7c3d14c8STreehugger Robot   VarSizeStackTrace stack;
140*7c3d14c8STreehugger Robot   ObtainCurrentStack(thr, pc, &stack);
141*7c3d14c8STreehugger Robot   if (IsFiredSuppression(ctx, ReportTypeSignalUnsafe, stack))
142*7c3d14c8STreehugger Robot     return;
143*7c3d14c8STreehugger Robot   ThreadRegistryLock l(ctx->thread_registry);
144*7c3d14c8STreehugger Robot   ScopedReport rep(ReportTypeSignalUnsafe);
145*7c3d14c8STreehugger Robot   rep.AddStack(stack, true);
146*7c3d14c8STreehugger Robot   OutputReport(thr, rep);
147*7c3d14c8STreehugger Robot }
148*7c3d14c8STreehugger Robot 
user_alloc(ThreadState * thr,uptr pc,uptr sz,uptr align,bool signal)149*7c3d14c8STreehugger Robot void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
150*7c3d14c8STreehugger Robot   if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
151*7c3d14c8STreehugger Robot     return allocator()->ReturnNullOrDie();
152*7c3d14c8STreehugger Robot   void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align);
153*7c3d14c8STreehugger Robot   if (p == 0)
154*7c3d14c8STreehugger Robot     return 0;
155*7c3d14c8STreehugger Robot   if (ctx && ctx->initialized)
156*7c3d14c8STreehugger Robot     OnUserAlloc(thr, pc, (uptr)p, sz, true);
157*7c3d14c8STreehugger Robot   if (signal)
158*7c3d14c8STreehugger Robot     SignalUnsafeCall(thr, pc);
159*7c3d14c8STreehugger Robot   return p;
160*7c3d14c8STreehugger Robot }
161*7c3d14c8STreehugger Robot 
user_calloc(ThreadState * thr,uptr pc,uptr size,uptr n)162*7c3d14c8STreehugger Robot void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) {
163*7c3d14c8STreehugger Robot   if (CallocShouldReturnNullDueToOverflow(size, n))
164*7c3d14c8STreehugger Robot     return allocator()->ReturnNullOrDie();
165*7c3d14c8STreehugger Robot   void *p = user_alloc(thr, pc, n * size);
166*7c3d14c8STreehugger Robot   if (p)
167*7c3d14c8STreehugger Robot     internal_memset(p, 0, n * size);
168*7c3d14c8STreehugger Robot   return p;
169*7c3d14c8STreehugger Robot }
170*7c3d14c8STreehugger Robot 
user_free(ThreadState * thr,uptr pc,void * p,bool signal)171*7c3d14c8STreehugger Robot void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
172*7c3d14c8STreehugger Robot   ScopedGlobalProcessor sgp;
173*7c3d14c8STreehugger Robot   if (ctx && ctx->initialized)
174*7c3d14c8STreehugger Robot     OnUserFree(thr, pc, (uptr)p, true);
175*7c3d14c8STreehugger Robot   allocator()->Deallocate(&thr->proc()->alloc_cache, p);
176*7c3d14c8STreehugger Robot   if (signal)
177*7c3d14c8STreehugger Robot     SignalUnsafeCall(thr, pc);
178*7c3d14c8STreehugger Robot }
179*7c3d14c8STreehugger Robot 
OnUserAlloc(ThreadState * thr,uptr pc,uptr p,uptr sz,bool write)180*7c3d14c8STreehugger Robot void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {
181*7c3d14c8STreehugger Robot   DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p);
182*7c3d14c8STreehugger Robot   ctx->metamap.AllocBlock(thr, pc, p, sz);
183*7c3d14c8STreehugger Robot   if (write && thr->ignore_reads_and_writes == 0)
184*7c3d14c8STreehugger Robot     MemoryRangeImitateWrite(thr, pc, (uptr)p, sz);
185*7c3d14c8STreehugger Robot   else
186*7c3d14c8STreehugger Robot     MemoryResetRange(thr, pc, (uptr)p, sz);
187*7c3d14c8STreehugger Robot }
188*7c3d14c8STreehugger Robot 
OnUserFree(ThreadState * thr,uptr pc,uptr p,bool write)189*7c3d14c8STreehugger Robot void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) {
190*7c3d14c8STreehugger Robot   CHECK_NE(p, (void*)0);
191*7c3d14c8STreehugger Robot   uptr sz = ctx->metamap.FreeBlock(thr->proc(), p);
192*7c3d14c8STreehugger Robot   DPrintf("#%d: free(%p, %zu)\n", thr->tid, p, sz);
193*7c3d14c8STreehugger Robot   if (write && thr->ignore_reads_and_writes == 0)
194*7c3d14c8STreehugger Robot     MemoryRangeFreed(thr, pc, (uptr)p, sz);
195*7c3d14c8STreehugger Robot }
196*7c3d14c8STreehugger Robot 
user_realloc(ThreadState * thr,uptr pc,void * p,uptr sz)197*7c3d14c8STreehugger Robot void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
198*7c3d14c8STreehugger Robot   void *p2 = 0;
199*7c3d14c8STreehugger Robot   // FIXME: Handle "shrinking" more efficiently,
200*7c3d14c8STreehugger Robot   // it seems that some software actually does this.
201*7c3d14c8STreehugger Robot   if (sz) {
202*7c3d14c8STreehugger Robot     p2 = user_alloc(thr, pc, sz);
203*7c3d14c8STreehugger Robot     if (p2 == 0)
204*7c3d14c8STreehugger Robot       return 0;
205*7c3d14c8STreehugger Robot     if (p) {
206*7c3d14c8STreehugger Robot       uptr oldsz = user_alloc_usable_size(p);
207*7c3d14c8STreehugger Robot       internal_memcpy(p2, p, min(oldsz, sz));
208*7c3d14c8STreehugger Robot     }
209*7c3d14c8STreehugger Robot   }
210*7c3d14c8STreehugger Robot   if (p)
211*7c3d14c8STreehugger Robot     user_free(thr, pc, p);
212*7c3d14c8STreehugger Robot   return p2;
213*7c3d14c8STreehugger Robot }
214*7c3d14c8STreehugger Robot 
user_alloc_usable_size(const void * p)215*7c3d14c8STreehugger Robot uptr user_alloc_usable_size(const void *p) {
216*7c3d14c8STreehugger Robot   if (p == 0)
217*7c3d14c8STreehugger Robot     return 0;
218*7c3d14c8STreehugger Robot   MBlock *b = ctx->metamap.GetBlock((uptr)p);
219*7c3d14c8STreehugger Robot   if (!b)
220*7c3d14c8STreehugger Robot     return 0;  // Not a valid pointer.
221*7c3d14c8STreehugger Robot   if (b->siz == 0)
222*7c3d14c8STreehugger Robot     return 1;  // Zero-sized allocations are actually 1 byte.
223*7c3d14c8STreehugger Robot   return b->siz;
224*7c3d14c8STreehugger Robot }
225*7c3d14c8STreehugger Robot 
invoke_malloc_hook(void * ptr,uptr size)226*7c3d14c8STreehugger Robot void invoke_malloc_hook(void *ptr, uptr size) {
227*7c3d14c8STreehugger Robot   ThreadState *thr = cur_thread();
228*7c3d14c8STreehugger Robot   if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
229*7c3d14c8STreehugger Robot     return;
230*7c3d14c8STreehugger Robot   __sanitizer_malloc_hook(ptr, size);
231*7c3d14c8STreehugger Robot   RunMallocHooks(ptr, size);
232*7c3d14c8STreehugger Robot }
233*7c3d14c8STreehugger Robot 
invoke_free_hook(void * ptr)234*7c3d14c8STreehugger Robot void invoke_free_hook(void *ptr) {
235*7c3d14c8STreehugger Robot   ThreadState *thr = cur_thread();
236*7c3d14c8STreehugger Robot   if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
237*7c3d14c8STreehugger Robot     return;
238*7c3d14c8STreehugger Robot   __sanitizer_free_hook(ptr);
239*7c3d14c8STreehugger Robot   RunFreeHooks(ptr);
240*7c3d14c8STreehugger Robot }
241*7c3d14c8STreehugger Robot 
internal_alloc(MBlockType typ,uptr sz)242*7c3d14c8STreehugger Robot void *internal_alloc(MBlockType typ, uptr sz) {
243*7c3d14c8STreehugger Robot   ThreadState *thr = cur_thread();
244*7c3d14c8STreehugger Robot   if (thr->nomalloc) {
245*7c3d14c8STreehugger Robot     thr->nomalloc = 0;  // CHECK calls internal_malloc().
246*7c3d14c8STreehugger Robot     CHECK(0);
247*7c3d14c8STreehugger Robot   }
248*7c3d14c8STreehugger Robot   return InternalAlloc(sz, &thr->proc()->internal_alloc_cache);
249*7c3d14c8STreehugger Robot }
250*7c3d14c8STreehugger Robot 
internal_free(void * p)251*7c3d14c8STreehugger Robot void internal_free(void *p) {
252*7c3d14c8STreehugger Robot   ThreadState *thr = cur_thread();
253*7c3d14c8STreehugger Robot   if (thr->nomalloc) {
254*7c3d14c8STreehugger Robot     thr->nomalloc = 0;  // CHECK calls internal_malloc().
255*7c3d14c8STreehugger Robot     CHECK(0);
256*7c3d14c8STreehugger Robot   }
257*7c3d14c8STreehugger Robot   InternalFree(p, &thr->proc()->internal_alloc_cache);
258*7c3d14c8STreehugger Robot }
259*7c3d14c8STreehugger Robot 
260*7c3d14c8STreehugger Robot }  // namespace __tsan
261*7c3d14c8STreehugger Robot 
262*7c3d14c8STreehugger Robot using namespace __tsan;
263*7c3d14c8STreehugger Robot 
264*7c3d14c8STreehugger Robot extern "C" {
__sanitizer_get_current_allocated_bytes()265*7c3d14c8STreehugger Robot uptr __sanitizer_get_current_allocated_bytes() {
266*7c3d14c8STreehugger Robot   uptr stats[AllocatorStatCount];
267*7c3d14c8STreehugger Robot   allocator()->GetStats(stats);
268*7c3d14c8STreehugger Robot   return stats[AllocatorStatAllocated];
269*7c3d14c8STreehugger Robot }
270*7c3d14c8STreehugger Robot 
__sanitizer_get_heap_size()271*7c3d14c8STreehugger Robot uptr __sanitizer_get_heap_size() {
272*7c3d14c8STreehugger Robot   uptr stats[AllocatorStatCount];
273*7c3d14c8STreehugger Robot   allocator()->GetStats(stats);
274*7c3d14c8STreehugger Robot   return stats[AllocatorStatMapped];
275*7c3d14c8STreehugger Robot }
276*7c3d14c8STreehugger Robot 
__sanitizer_get_free_bytes()277*7c3d14c8STreehugger Robot uptr __sanitizer_get_free_bytes() {
278*7c3d14c8STreehugger Robot   return 1;
279*7c3d14c8STreehugger Robot }
280*7c3d14c8STreehugger Robot 
__sanitizer_get_unmapped_bytes()281*7c3d14c8STreehugger Robot uptr __sanitizer_get_unmapped_bytes() {
282*7c3d14c8STreehugger Robot   return 1;
283*7c3d14c8STreehugger Robot }
284*7c3d14c8STreehugger Robot 
__sanitizer_get_estimated_allocated_size(uptr size)285*7c3d14c8STreehugger Robot uptr __sanitizer_get_estimated_allocated_size(uptr size) {
286*7c3d14c8STreehugger Robot   return size;
287*7c3d14c8STreehugger Robot }
288*7c3d14c8STreehugger Robot 
__sanitizer_get_ownership(const void * p)289*7c3d14c8STreehugger Robot int __sanitizer_get_ownership(const void *p) {
290*7c3d14c8STreehugger Robot   return allocator()->GetBlockBegin(p) != 0;
291*7c3d14c8STreehugger Robot }
292*7c3d14c8STreehugger Robot 
__sanitizer_get_allocated_size(const void * p)293*7c3d14c8STreehugger Robot uptr __sanitizer_get_allocated_size(const void *p) {
294*7c3d14c8STreehugger Robot   return user_alloc_usable_size(p);
295*7c3d14c8STreehugger Robot }
296*7c3d14c8STreehugger Robot 
__tsan_on_thread_idle()297*7c3d14c8STreehugger Robot void __tsan_on_thread_idle() {
298*7c3d14c8STreehugger Robot   ThreadState *thr = cur_thread();
299*7c3d14c8STreehugger Robot   allocator()->SwallowCache(&thr->proc()->alloc_cache);
300*7c3d14c8STreehugger Robot   internal_allocator()->SwallowCache(&thr->proc()->internal_alloc_cache);
301*7c3d14c8STreehugger Robot   ctx->metamap.OnProcIdle(thr->proc());
302*7c3d14c8STreehugger Robot }
303*7c3d14c8STreehugger Robot }  // extern "C"
304