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