Home | History | Annotate | Download | only in rtl
      1 //===-- tsan_interface_java.cc --------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is a part of ThreadSanitizer (TSan), a race detector.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "tsan_interface_java.h"
     15 #include "tsan_rtl.h"
     16 #include "tsan_mutex.h"
     17 #include "sanitizer_common/sanitizer_internal_defs.h"
     18 #include "sanitizer_common/sanitizer_common.h"
     19 #include "sanitizer_common/sanitizer_placement_new.h"
     20 #include "sanitizer_common/sanitizer_stacktrace.h"
     21 
     22 using namespace __tsan;  // NOLINT
     23 
     24 namespace __tsan {
     25 
     26 const uptr kHeapShadow = 0x300000000000ull;
     27 const uptr kHeapAlignment = 8;
     28 
     29 struct BlockDesc {
     30   bool begin;
     31   Mutex mtx;
     32   SyncVar *head;
     33 
     34   BlockDesc()
     35       : mtx(MutexTypeJavaMBlock, StatMtxJavaMBlock)
     36       , head() {
     37     CHECK_EQ(begin, false);
     38     begin = true;
     39   }
     40 
     41   ~BlockDesc() {
     42     CHECK_EQ(begin, true);
     43     begin = false;
     44     ThreadState *thr = cur_thread();
     45     SyncVar *s = head;
     46     while (s) {
     47       SyncVar *s1 = s->next;
     48       StatInc(thr, StatSyncDestroyed);
     49       s->mtx.Lock();
     50       s->mtx.Unlock();
     51       thr->mset.Remove(s->GetId());
     52       DestroyAndFree(s);
     53       s = s1;
     54     }
     55   }
     56 };
     57 
     58 struct JavaContext {
     59   const uptr heap_begin;
     60   const uptr heap_size;
     61   BlockDesc *heap_shadow;
     62 
     63   JavaContext(jptr heap_begin, jptr heap_size)
     64       : heap_begin(heap_begin)
     65       , heap_size(heap_size) {
     66     uptr size = heap_size / kHeapAlignment * sizeof(BlockDesc);
     67     heap_shadow = (BlockDesc*)MmapFixedNoReserve(kHeapShadow, size);
     68     if ((uptr)heap_shadow != kHeapShadow) {
     69       Printf("ThreadSanitizer: failed to mmap Java heap shadow\n");
     70       Die();
     71     }
     72   }
     73 };
     74 
     75 class ScopedJavaFunc {
     76  public:
     77   ScopedJavaFunc(ThreadState *thr, uptr pc)
     78       : thr_(thr) {
     79     Initialize(thr_);
     80     FuncEntry(thr, pc);
     81     CHECK_EQ(thr_->in_rtl, 0);
     82     thr_->in_rtl++;
     83   }
     84 
     85   ~ScopedJavaFunc() {
     86     thr_->in_rtl--;
     87     CHECK_EQ(thr_->in_rtl, 0);
     88     FuncExit(thr_);
     89     // FIXME(dvyukov): process pending signals.
     90   }
     91 
     92  private:
     93   ThreadState *thr_;
     94 };
     95 
     96 static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
     97 static JavaContext *jctx;
     98 
     99 static BlockDesc *getblock(uptr addr) {
    100   uptr i = (addr - jctx->heap_begin) / kHeapAlignment;
    101   return &jctx->heap_shadow[i];
    102 }
    103 
    104 static uptr USED getmem(BlockDesc *b) {
    105   uptr i = b - jctx->heap_shadow;
    106   uptr p = jctx->heap_begin + i * kHeapAlignment;
    107   CHECK_GE(p, jctx->heap_begin);
    108   CHECK_LT(p, jctx->heap_begin + jctx->heap_size);
    109   return p;
    110 }
    111 
    112 static BlockDesc *getblockbegin(uptr addr) {
    113   for (BlockDesc *b = getblock(addr);; b--) {
    114     CHECK_GE(b, jctx->heap_shadow);
    115     if (b->begin)
    116       return b;
    117   }
    118   return 0;
    119 }
    120 
    121 SyncVar* GetJavaSync(ThreadState *thr, uptr pc, uptr addr,
    122                      bool write_lock, bool create) {
    123   if (jctx == 0 || addr < jctx->heap_begin
    124       || addr >= jctx->heap_begin + jctx->heap_size)
    125     return 0;
    126   BlockDesc *b = getblockbegin(addr);
    127   DPrintf("#%d: GetJavaSync %p->%p\n", thr->tid, addr, b);
    128   Lock l(&b->mtx);
    129   SyncVar *s = b->head;
    130   for (; s; s = s->next) {
    131     if (s->addr == addr) {
    132       DPrintf("#%d: found existing sync for %p\n", thr->tid, addr);
    133       break;
    134     }
    135   }
    136   if (s == 0 && create) {
    137     DPrintf("#%d: creating new sync for %p\n", thr->tid, addr);
    138     s = CTX()->synctab.Create(thr, pc, addr);
    139     s->next = b->head;
    140     b->head = s;
    141   }
    142   if (s) {
    143     if (write_lock)
    144       s->mtx.Lock();
    145     else
    146       s->mtx.ReadLock();
    147   }
    148   return s;
    149 }
    150 
    151 SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr) {
    152   // We do not destroy Java mutexes other than in __tsan_java_free().
    153   return 0;
    154 }
    155 
    156 }  // namespace __tsan
    157 
    158 #define SCOPED_JAVA_FUNC(func) \
    159   ThreadState *thr = cur_thread(); \
    160   const uptr caller_pc = GET_CALLER_PC(); \
    161   const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
    162   (void)pc; \
    163   ScopedJavaFunc scoped(thr, caller_pc); \
    164 /**/
    165 
    166 void __tsan_java_init(jptr heap_begin, jptr heap_size) {
    167   SCOPED_JAVA_FUNC(__tsan_java_init);
    168   DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);
    169   CHECK_EQ(jctx, 0);
    170   CHECK_GT(heap_begin, 0);
    171   CHECK_GT(heap_size, 0);
    172   CHECK_EQ(heap_begin % kHeapAlignment, 0);
    173   CHECK_EQ(heap_size % kHeapAlignment, 0);
    174   CHECK_LT(heap_begin, heap_begin + heap_size);
    175   jctx = new(jctx_buf) JavaContext(heap_begin, heap_size);
    176 }
    177 
    178 int  __tsan_java_fini() {
    179   SCOPED_JAVA_FUNC(__tsan_java_fini);
    180   DPrintf("#%d: java_fini()\n", thr->tid);
    181   CHECK_NE(jctx, 0);
    182   // FIXME(dvyukov): this does not call atexit() callbacks.
    183   int status = Finalize(thr);
    184   DPrintf("#%d: java_fini() = %d\n", thr->tid, status);
    185   return status;
    186 }
    187 
    188 void __tsan_java_alloc(jptr ptr, jptr size) {
    189   SCOPED_JAVA_FUNC(__tsan_java_alloc);
    190   DPrintf("#%d: java_alloc(%p, %p)\n", thr->tid, ptr, size);
    191   CHECK_NE(jctx, 0);
    192   CHECK_NE(size, 0);
    193   CHECK_EQ(ptr % kHeapAlignment, 0);
    194   CHECK_EQ(size % kHeapAlignment, 0);
    195   CHECK_GE(ptr, jctx->heap_begin);
    196   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
    197 
    198   BlockDesc *b = getblock(ptr);
    199   new(b) BlockDesc();
    200 }
    201 
    202 void __tsan_java_free(jptr ptr, jptr size) {
    203   SCOPED_JAVA_FUNC(__tsan_java_free);
    204   DPrintf("#%d: java_free(%p, %p)\n", thr->tid, ptr, size);
    205   CHECK_NE(jctx, 0);
    206   CHECK_NE(size, 0);
    207   CHECK_EQ(ptr % kHeapAlignment, 0);
    208   CHECK_EQ(size % kHeapAlignment, 0);
    209   CHECK_GE(ptr, jctx->heap_begin);
    210   CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
    211 
    212   BlockDesc *beg = getblock(ptr);
    213   BlockDesc *end = getblock(ptr + size);
    214   for (BlockDesc *b = beg; b != end; b++) {
    215     if (b->begin)
    216       b->~BlockDesc();
    217   }
    218 }
    219 
    220 void __tsan_java_move(jptr src, jptr dst, jptr size) {
    221   SCOPED_JAVA_FUNC(__tsan_java_move);
    222   DPrintf("#%d: java_move(%p, %p, %p)\n", thr->tid, src, dst, size);
    223   CHECK_NE(jctx, 0);
    224   CHECK_NE(size, 0);
    225   CHECK_EQ(src % kHeapAlignment, 0);
    226   CHECK_EQ(dst % kHeapAlignment, 0);
    227   CHECK_EQ(size % kHeapAlignment, 0);
    228   CHECK_GE(src, jctx->heap_begin);
    229   CHECK_LE(src + size, jctx->heap_begin + jctx->heap_size);
    230   CHECK_GE(dst, jctx->heap_begin);
    231   CHECK_LE(dst + size, jctx->heap_begin + jctx->heap_size);
    232   CHECK(dst >= src + size || src >= dst + size);
    233 
    234   // Assuming it's not running concurrently with threads that do
    235   // memory accesses and mutex operations (stop-the-world phase).
    236   {  // NOLINT
    237     BlockDesc *s = getblock(src);
    238     BlockDesc *d = getblock(dst);
    239     BlockDesc *send = getblock(src + size);
    240     for (; s != send; s++, d++) {
    241       CHECK_EQ(d->begin, false);
    242       if (s->begin) {
    243         DPrintf("#%d: moving block %p->%p\n", thr->tid, getmem(s), getmem(d));
    244         new(d) BlockDesc;
    245         d->head = s->head;
    246         for (SyncVar *sync = d->head; sync; sync = sync->next) {
    247           uptr newaddr = sync->addr - src + dst;
    248           DPrintf("#%d: moving sync %p->%p\n", thr->tid, sync->addr, newaddr);
    249           sync->addr = newaddr;
    250         }
    251         s->head = 0;
    252         s->~BlockDesc();
    253       }
    254     }
    255   }
    256 
    257   {  // NOLINT
    258     u64 *s = (u64*)MemToShadow(src);
    259     u64 *d = (u64*)MemToShadow(dst);
    260     u64 *send = (u64*)MemToShadow(src + size);
    261     for (; s != send; s++, d++) {
    262       *d = *s;
    263       *s = 0;
    264     }
    265   }
    266 }
    267 
    268 void __tsan_java_mutex_lock(jptr addr) {
    269   SCOPED_JAVA_FUNC(__tsan_java_mutex_lock);
    270   DPrintf("#%d: java_mutex_lock(%p)\n", thr->tid, addr);
    271   CHECK_NE(jctx, 0);
    272   CHECK_GE(addr, jctx->heap_begin);
    273   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
    274 
    275   MutexCreate(thr, pc, addr, true, true, true);
    276   MutexLock(thr, pc, addr);
    277 }
    278 
    279 void __tsan_java_mutex_unlock(jptr addr) {
    280   SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock);
    281   DPrintf("#%d: java_mutex_unlock(%p)\n", thr->tid, addr);
    282   CHECK_NE(jctx, 0);
    283   CHECK_GE(addr, jctx->heap_begin);
    284   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
    285 
    286   MutexUnlock(thr, pc, addr);
    287 }
    288 
    289 void __tsan_java_mutex_read_lock(jptr addr) {
    290   SCOPED_JAVA_FUNC(__tsan_java_mutex_read_lock);
    291   DPrintf("#%d: java_mutex_read_lock(%p)\n", thr->tid, addr);
    292   CHECK_NE(jctx, 0);
    293   CHECK_GE(addr, jctx->heap_begin);
    294   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
    295 
    296   MutexCreate(thr, pc, addr, true, true, true);
    297   MutexReadLock(thr, pc, addr);
    298 }
    299 
    300 void __tsan_java_mutex_read_unlock(jptr addr) {
    301   SCOPED_JAVA_FUNC(__tsan_java_mutex_read_unlock);
    302   DPrintf("#%d: java_mutex_read_unlock(%p)\n", thr->tid, addr);
    303   CHECK_NE(jctx, 0);
    304   CHECK_GE(addr, jctx->heap_begin);
    305   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
    306 
    307   MutexReadUnlock(thr, pc, addr);
    308 }
    309 
    310 void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
    311   SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec);
    312   DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec);
    313   CHECK_NE(jctx, 0);
    314   CHECK_GE(addr, jctx->heap_begin);
    315   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
    316   CHECK_GT(rec, 0);
    317 
    318   MutexCreate(thr, pc, addr, true, true, true);
    319   MutexLock(thr, pc, addr, rec);
    320 }
    321 
    322 int __tsan_java_mutex_unlock_rec(jptr addr) {
    323   SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec);
    324   DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr);
    325   CHECK_NE(jctx, 0);
    326   CHECK_GE(addr, jctx->heap_begin);
    327   CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
    328 
    329   return MutexUnlock(thr, pc, addr, true);
    330 }
    331