1603c4be006d8c53905d736bf1f19a49f5ce98276Alexey Samsonov//===-- tsan_mman.cc ------------------------------------------------------===// 27ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 37ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// The LLVM Compiler Infrastructure 47ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 57ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is distributed under the University of Illinois Open Source 67ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// License. See LICENSE.TXT for details. 77ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 87ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===// 97ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is a part of ThreadSanitizer (TSan), a race detector. 117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// 127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===// 13f7667cc84cdd8923c0b6c7cfc92b7bd5692ce18cAlexey Samsonov#include "sanitizer_common/sanitizer_common.h" 142e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov#include "sanitizer_common/sanitizer_placement_new.h" 157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_mman.h" 167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h" 177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_report.h" 187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_flags.h" 197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan { 217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 22ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukovstatic char allocator_placeholder[sizeof(Allocator)] ALIGNED(64); 23ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry VyukovAllocator *allocator() { 242e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov return reinterpret_cast<Allocator*>(&allocator_placeholder); 252e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov} 262e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov 272e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukovvoid InitializeAllocator() { 282e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov allocator()->Init(); 292e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov} 302e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov 312e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukovvoid AlloctorThreadFinish(ThreadState *thr) { 322e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov allocator()->SwallowCache(&thr->alloc_cache); 332e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov} 342e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov 357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void SignalUnsafeCall(ThreadState *thr, uptr pc) { 367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (!thr->in_signal_handler || !flags()->report_signal_unsafe) 377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return; 387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany StackTrace stack; 397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany stack.ObtainCurrent(thr, pc); 407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ScopedReport rep(ReportTypeSignalUnsafe); 417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany rep.AddStack(&stack); 42f5820e74ad31eb8352049c880f8d58e286a9b713Dmitry Vyukov OutputReport(rep, rep.GetReport()->stacks[0]); 437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 452e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukovvoid *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) { 467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_GT(thr->in_rtl, 0); 472e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov void *p = allocator()->Allocate(&thr->alloc_cache, sz, align); 482e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov if (p == 0) 49efd958213d70188ae6f79afd79fe2c84956d24ffDmitry Vyukov return 0; 502e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov MBlock *b = (MBlock*)allocator()->GetMetaData(p); 517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany b->size = sz; 52ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov b->alloc_tid = thr->unique_id; 53848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov b->alloc_stack_id = CurrentStackId(thr, pc); 547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (CTX() && CTX()->initialized) { 559bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov MemoryRangeImitateWrite(thr, pc, (uptr)p, sz); 567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 57e954101f6602ac181a2c3accfbbad0ae51b0bf7cAlexey Samsonov DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p); 587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany SignalUnsafeCall(thr, pc); 597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return p; 607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid user_free(ThreadState *thr, uptr pc, void *p) { 637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_GT(thr->in_rtl, 0); 647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_NE(p, (void*)0); 657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany DPrintf("#%d: free(%p)\n", thr->tid, p); 662e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov MBlock *b = (MBlock*)allocator()->GetMetaData(p); 679bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov if (b->head) { 689bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov Lock l(&b->mtx); 699bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov for (SyncVar *s = b->head; s;) { 709bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov SyncVar *res = s; 719bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov s = s->next; 729bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov StatInc(thr, StatSyncDestroyed); 739bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov res->mtx.Lock(); 749bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov res->mtx.Unlock(); 759bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov DestroyAndFree(res); 769bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov } 779bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov b->head = 0; 789bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov } 797ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (CTX() && CTX()->initialized && thr->in_rtl == 1) { 807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany MemoryRangeFreed(thr, pc, (uptr)p, b->size); 817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 822e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov allocator()->Deallocate(&thr->alloc_cache, p); 837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany SignalUnsafeCall(thr, pc); 847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) { 877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_GT(thr->in_rtl, 0); 887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany void *p2 = 0; 897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // FIXME: Handle "shrinking" more efficiently, 907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany // it seems that some software actually does this. 917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (sz) { 927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany p2 = user_alloc(thr, pc, sz); 93efd958213d70188ae6f79afd79fe2c84956d24ffDmitry Vyukov if (p2 == 0) 94efd958213d70188ae6f79afd79fe2c84956d24ffDmitry Vyukov return 0; 957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (p) { 967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany MBlock *b = user_mblock(thr, p); 977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany internal_memcpy(p2, p, min(b->size, sz)); 987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 1007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany if (p) { 1017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany user_free(thr, pc, p); 1027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany } 1037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany return p2; 1047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1067ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyMBlock *user_mblock(ThreadState *thr, void *p) { 107ff35f1d82b4f145b3477ef27a7a2e7b63c486988Dmitry Vyukov // CHECK_GT(thr->in_rtl, 0); 1087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_NE(p, (void*)0); 1092e87051d136db3150a3ca322d8862f92b0a684bbDmitry Vyukov return (MBlock*)allocator()->GetMetaData(p); 1107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid *internal_alloc(MBlockType typ, uptr sz) { 1137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ThreadState *thr = cur_thread(); 1147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_GT(thr->in_rtl, 0); 1159ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov if (thr->nomalloc) { 1169ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov thr->nomalloc = 0; // CHECK calls internal_malloc(). 1179ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov CHECK(0); 1189ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov } 119f7667cc84cdd8923c0b6c7cfc92b7bd5692ce18cAlexey Samsonov return InternalAlloc(sz); 1207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid internal_free(void *p) { 1237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany ThreadState *thr = cur_thread(); 1247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany CHECK_GT(thr->in_rtl, 0); 1259ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov if (thr->nomalloc) { 1269ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov thr->nomalloc = 0; // CHECK calls internal_malloc(). 1279ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov CHECK(0); 1289ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov } 129f7667cc84cdd8923c0b6c7cfc92b7bd5692ce18cAlexey Samsonov InternalFree(p); 1307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} 1317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany 1327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany} // namespace __tsan 133