diff options
author | Ed Schouten <ed@FreeBSD.org> | 2013-05-27 18:27:12 +0000 |
---|---|---|
committer | Ed Schouten <ed@FreeBSD.org> | 2013-05-27 18:27:12 +0000 |
commit | 11023dc647fd8f41418da90d59db138400d0f334 (patch) | |
tree | 50f0ab80515576749ef638dd0766b70a65904bfa /lib/tsan/rtl/tsan_rtl_thread.cc | |
parent | 58aabf08b77d221489f10e274812ec60917c21a8 (diff) | |
download | src-11023dc647fd8f41418da90d59db138400d0f334.tar.gz src-11023dc647fd8f41418da90d59db138400d0f334.zip |
Import compiler-rt r182741.vendor/compiler-rt/compiler-rt-r182741
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=251034
svn path=/vendor/compiler-rt/compiler-rt-r182741/; revision=251036; tag=vendor/compiler-rt/compiler-rt-r182741
Diffstat (limited to 'lib/tsan/rtl/tsan_rtl_thread.cc')
-rw-r--r-- | lib/tsan/rtl/tsan_rtl_thread.cc | 474 |
1 files changed, 217 insertions, 257 deletions
diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc index 359775927834..ee13fa18db3f 100644 --- a/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/lib/tsan/rtl/tsan_rtl_thread.cc @@ -20,144 +20,193 @@ namespace __tsan { +// ThreadContext implementation. + +ThreadContext::ThreadContext(int tid) + : ThreadContextBase(tid) + , thr() + , sync() + , epoch0() + , epoch1() { +} + #ifndef TSAN_GO -const int kThreadQuarantineSize = 16; -#else -const int kThreadQuarantineSize = 64; +ThreadContext::~ThreadContext() { +} #endif -static void MaybeReportThreadLeak(ThreadContext *tctx) { - if (tctx->detached) +void ThreadContext::OnDead() { + sync.Reset(); +} + +void ThreadContext::OnJoined(void *arg) { + ThreadState *caller_thr = static_cast<ThreadState *>(arg); + caller_thr->clock.acquire(&sync); + StatInc(caller_thr, StatSyncAcquire); + sync.Reset(); +} + +struct OnCreatedArgs { + ThreadState *thr; + uptr pc; +}; + +void ThreadContext::OnCreated(void *arg) { + thr = 0; + if (tid == 0) return; - if (tctx->status != ThreadStatusCreated - && tctx->status != ThreadStatusRunning - && tctx->status != ThreadStatusFinished) + OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg); + args->thr->fast_state.IncrementEpoch(); + // Can't increment epoch w/o writing to the trace as well. + TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0); + args->thr->clock.set(args->thr->tid, args->thr->fast_state.epoch()); + args->thr->fast_synch_epoch = args->thr->fast_state.epoch(); + args->thr->clock.release(&sync); + StatInc(args->thr, StatSyncRelease); +#ifdef TSAN_GO + creation_stack.ObtainCurrent(args->thr, args->pc); +#else + creation_stack_id = CurrentStackId(args->thr, args->pc); +#endif + if (reuse_count == 0) + StatInc(args->thr, StatThreadMaxTid); +} + +void ThreadContext::OnReset() { + sync.Reset(); + FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event)); + //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace)); +} + +struct OnStartedArgs { + ThreadState *thr; + uptr stk_addr; + uptr stk_size; + uptr tls_addr; + uptr tls_size; +}; + +void ThreadContext::OnStarted(void *arg) { + OnStartedArgs *args = static_cast<OnStartedArgs*>(arg); + thr = args->thr; + // RoundUp so that one trace part does not contain events + // from different threads. + epoch0 = RoundUp(epoch1 + 1, kTracePartSize); + epoch1 = (u64)-1; + new(thr) ThreadState(CTX(), tid, unique_id, + epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size); +#ifdef TSAN_GO + // Setup dynamic shadow stack. + const int kInitStackSize = 8; + args->thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack, + kInitStackSize * sizeof(uptr)); + args->thr->shadow_stack_pos = thr->shadow_stack; + args->thr->shadow_stack_end = thr->shadow_stack + kInitStackSize; +#endif +#ifndef TSAN_GO + AllocatorThreadStart(args->thr); +#endif + thr = args->thr; + thr->fast_synch_epoch = epoch0; + thr->clock.set(tid, epoch0); + thr->clock.acquire(&sync); + thr->fast_state.SetHistorySize(flags()->history_size); + const uptr trace = (epoch0 / kTracePartSize) % TraceParts(); + Trace *thr_trace = ThreadTrace(thr->tid); + thr_trace->headers[trace].epoch0 = epoch0; + StatInc(thr, StatSyncAcquire); + sync.Reset(); + DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx " + "tls_addr=%zx tls_size=%zx\n", + tid, (uptr)epoch0, args->stk_addr, args->stk_size, + args->tls_addr, args->tls_size); + thr->is_alive = true; +} + +void ThreadContext::OnFinished() { + if (!detached) { + thr->fast_state.IncrementEpoch(); + // Can't increment epoch w/o writing to the trace as well. + TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); + thr->clock.set(thr->tid, thr->fast_state.epoch()); + thr->fast_synch_epoch = thr->fast_state.epoch(); + thr->clock.release(&sync); + StatInc(thr, StatSyncRelease); + } + epoch1 = thr->fast_state.epoch(); + +#ifndef TSAN_GO + AllocatorThreadFinish(thr); +#endif + thr->~ThreadState(); + StatAggregate(CTX()->stat, thr->stat); + thr = 0; +} + +#ifndef TSAN_GO +struct ThreadLeak { + ThreadContext *tctx; + int count; +}; + +static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) { + Vector<ThreadLeak> &leaks = *(Vector<ThreadLeak>*)arg; + ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); + if (tctx->detached || tctx->status != ThreadStatusFinished) return; - ScopedReport rep(ReportTypeThreadLeak); - rep.AddThread(tctx); - OutputReport(CTX(), rep); + for (uptr i = 0; i < leaks.Size(); i++) { + if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) { + leaks[i].count++; + return; + } + } + ThreadLeak leak = {tctx, 1}; + leaks.PushBack(leak); +} +#endif + +static void ThreadCheckIgnore(ThreadState *thr) { + if (thr->ignore_reads_and_writes) { + Printf("ThreadSanitizer: thread T%d finished with ignores enabled.\n", + thr->tid); + } } void ThreadFinalize(ThreadState *thr) { CHECK_GT(thr->in_rtl, 0); + ThreadCheckIgnore(thr); +#ifndef TSAN_GO if (!flags()->report_thread_leaks) return; - Context *ctx = CTX(); - Lock l(&ctx->thread_mtx); - for (unsigned i = 0; i < kMaxTid; i++) { - ThreadContext *tctx = ctx->threads[i]; - if (tctx == 0) - continue; - MaybeReportThreadLeak(tctx); + ThreadRegistryLock l(CTX()->thread_registry); + Vector<ThreadLeak> leaks(MBlockScopedBuf); + CTX()->thread_registry->RunCallbackForEachThreadLocked( + MaybeReportThreadLeak, &leaks); + for (uptr i = 0; i < leaks.Size(); i++) { + ScopedReport rep(ReportTypeThreadLeak); + rep.AddThread(leaks[i].tctx); + rep.SetCount(leaks[i].count); + OutputReport(CTX(), rep); } +#endif } int ThreadCount(ThreadState *thr) { CHECK_GT(thr->in_rtl, 0); Context *ctx = CTX(); - Lock l(&ctx->thread_mtx); - int cnt = 0; - for (unsigned i = 0; i < kMaxTid; i++) { - ThreadContext *tctx = ctx->threads[i]; - if (tctx == 0) - continue; - if (tctx->status != ThreadStatusCreated - && tctx->status != ThreadStatusRunning) - continue; - cnt++; - } - return cnt; -} - -static void ThreadDead(ThreadState *thr, ThreadContext *tctx) { - Context *ctx = CTX(); - CHECK_GT(thr->in_rtl, 0); - CHECK(tctx->status == ThreadStatusRunning - || tctx->status == ThreadStatusFinished); - DPrintf("#%d: ThreadDead uid=%zu\n", thr->tid, tctx->user_id); - tctx->status = ThreadStatusDead; - tctx->user_id = 0; - tctx->sync.Reset(); - - // Put to dead list. - tctx->dead_next = 0; - if (ctx->dead_list_size == 0) - ctx->dead_list_head = tctx; - else - ctx->dead_list_tail->dead_next = tctx; - ctx->dead_list_tail = tctx; - ctx->dead_list_size++; + uptr result; + ctx->thread_registry->GetNumberOfThreads(0, 0, &result); + return (int)result; } int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) { CHECK_GT(thr->in_rtl, 0); - Context *ctx = CTX(); - Lock l(&ctx->thread_mtx); StatInc(thr, StatThreadCreate); - int tid = -1; - ThreadContext *tctx = 0; - if (ctx->dead_list_size > kThreadQuarantineSize - || ctx->thread_seq >= kMaxTid) { - // Reusing old thread descriptor and tid. - if (ctx->dead_list_size == 0) { - Printf("ThreadSanitizer: %d thread limit exceeded. Dying.\n", - kMaxTid); - Die(); - } - StatInc(thr, StatThreadReuse); - tctx = ctx->dead_list_head; - ctx->dead_list_head = tctx->dead_next; - ctx->dead_list_size--; - if (ctx->dead_list_size == 0) { - CHECK_EQ(tctx->dead_next, 0); - ctx->dead_list_head = 0; - } - CHECK_EQ(tctx->status, ThreadStatusDead); - tctx->status = ThreadStatusInvalid; - tctx->reuse_count++; - tctx->sync.Reset(); - tid = tctx->tid; - DestroyAndFree(tctx->dead_info); - if (tctx->name) { - internal_free(tctx->name); - tctx->name = 0; - } - } else { - // Allocating new thread descriptor and tid. - StatInc(thr, StatThreadMaxTid); - tid = ctx->thread_seq++; - void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext)); - tctx = new(mem) ThreadContext(tid); - ctx->threads[tid] = tctx; - MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event)); - } - CHECK_NE(tctx, 0); - CHECK_GE(tid, 0); - CHECK_LT(tid, kMaxTid); + Context *ctx = CTX(); + OnCreatedArgs args = { thr, pc }; + int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args); DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid); - CHECK_EQ(tctx->status, ThreadStatusInvalid); - ctx->alive_threads++; - if (ctx->max_alive_threads < ctx->alive_threads) { - ctx->max_alive_threads++; - CHECK_EQ(ctx->max_alive_threads, ctx->alive_threads); - StatInc(thr, StatThreadMaxAlive); - } - tctx->status = ThreadStatusCreated; - tctx->thr = 0; - tctx->user_id = uid; - tctx->unique_id = ctx->unique_thread_seq++; - tctx->detached = detached; - if (tid) { - thr->fast_state.IncrementEpoch(); - // Can't increment epoch w/o writing to the trace as well. - TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); - thr->clock.set(thr->tid, thr->fast_state.epoch()); - thr->fast_synch_epoch = thr->fast_state.epoch(); - thr->clock.release(&tctx->sync); - StatInc(thr, StatSyncRelease); - tctx->creation_stack.ObtainCurrent(thr, pc); - tctx->creation_tid = thr->tid; - } + StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads()); return tid; } @@ -170,9 +219,8 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) { GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size); if (tid) { - if (stk_addr && stk_size) { - MemoryResetRange(thr, /*pc=*/ 1, stk_addr, stk_size); - } + if (stk_addr && stk_size) + MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size); if (tls_addr && tls_size) { // Check that the thr object is in tls; @@ -183,113 +231,42 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) { CHECK_GE(thr_end, tls_addr); CHECK_LE(thr_end, tls_addr + tls_size); // Since the thr object is huge, skip it. - MemoryResetRange(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr); - MemoryResetRange(thr, /*pc=*/ 2, thr_end, tls_addr + tls_size - thr_end); + MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr); + MemoryRangeImitateWrite(thr, /*pc=*/ 2, + thr_end, tls_addr + tls_size - thr_end); } } - Lock l(&CTX()->thread_mtx); - ThreadContext *tctx = CTX()->threads[tid]; - CHECK_NE(tctx, 0); - CHECK_EQ(tctx->status, ThreadStatusCreated); - tctx->status = ThreadStatusRunning; - tctx->os_id = os_id; - // RoundUp so that one trace part does not contain events - // from different threads. - tctx->epoch0 = RoundUp(tctx->epoch1 + 1, kTracePartSize); - tctx->epoch1 = (u64)-1; - new(thr) ThreadState(CTX(), tid, tctx->unique_id, - tctx->epoch0, stk_addr, stk_size, - tls_addr, tls_size); -#ifdef TSAN_GO - // Setup dynamic shadow stack. - const int kInitStackSize = 8; - thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack, - kInitStackSize * sizeof(uptr)); - thr->shadow_stack_pos = thr->shadow_stack; - thr->shadow_stack_end = thr->shadow_stack + kInitStackSize; -#endif - tctx->thr = thr; - thr->fast_synch_epoch = tctx->epoch0; - thr->clock.set(tid, tctx->epoch0); - thr->clock.acquire(&tctx->sync); - thr->fast_state.SetHistorySize(flags()->history_size); - const uptr trace = (tctx->epoch0 / kTracePartSize) % TraceParts(); - thr->trace.headers[trace].epoch0 = tctx->epoch0; - StatInc(thr, StatSyncAcquire); - DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx " - "tls_addr=%zx tls_size=%zx\n", - tid, (uptr)tctx->epoch0, stk_addr, stk_size, tls_addr, tls_size); - thr->is_alive = true; + OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size }; + CTX()->thread_registry->StartThread(tid, os_id, &args); } void ThreadFinish(ThreadState *thr) { CHECK_GT(thr->in_rtl, 0); + ThreadCheckIgnore(thr); StatInc(thr, StatThreadFinish); - // FIXME: Treat it as write. if (thr->stk_addr && thr->stk_size) - MemoryResetRange(thr, /*pc=*/ 3, thr->stk_addr, thr->stk_size); - if (thr->tls_addr && thr->tls_size) { - const uptr thr_beg = (uptr)thr; - const uptr thr_end = (uptr)thr + sizeof(*thr); - // Since the thr object is huge, skip it. - MemoryResetRange(thr, /*pc=*/ 4, thr->tls_addr, thr_beg - thr->tls_addr); - MemoryResetRange(thr, /*pc=*/ 5, - thr_end, thr->tls_addr + thr->tls_size - thr_end); - } + DontNeedShadowFor(thr->stk_addr, thr->stk_size); + if (thr->tls_addr && thr->tls_size) + DontNeedShadowFor(thr->tls_addr, thr->tls_size); thr->is_alive = false; Context *ctx = CTX(); - Lock l(&ctx->thread_mtx); - ThreadContext *tctx = ctx->threads[thr->tid]; - CHECK_NE(tctx, 0); - CHECK_EQ(tctx->status, ThreadStatusRunning); - CHECK_GT(ctx->alive_threads, 0); - ctx->alive_threads--; - if (tctx->detached) { - ThreadDead(thr, tctx); - } else { - thr->fast_state.IncrementEpoch(); - // Can't increment epoch w/o writing to the trace as well. - TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); - thr->clock.set(thr->tid, thr->fast_state.epoch()); - thr->fast_synch_epoch = thr->fast_state.epoch(); - thr->clock.release(&tctx->sync); - StatInc(thr, StatSyncRelease); - tctx->status = ThreadStatusFinished; - } + ctx->thread_registry->FinishThread(thr->tid); +} - // Save from info about the thread. - tctx->dead_info = new(internal_alloc(MBlockDeadInfo, sizeof(ThreadDeadInfo))) - ThreadDeadInfo(); - for (uptr i = 0; i < TraceParts(); i++) { - tctx->dead_info->trace.headers[i].epoch0 = thr->trace.headers[i].epoch0; - tctx->dead_info->trace.headers[i].stack0.CopyFrom( - thr->trace.headers[i].stack0); +static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { + uptr uid = (uptr)arg; + if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { + tctx->user_id = 0; + return true; } - tctx->epoch1 = thr->fast_state.epoch(); - -#ifndef TSAN_GO - AlloctorThreadFinish(thr); -#endif - thr->~ThreadState(); - StatAggregate(ctx->stat, thr->stat); - tctx->thr = 0; + return false; } int ThreadTid(ThreadState *thr, uptr pc, uptr uid) { CHECK_GT(thr->in_rtl, 0); Context *ctx = CTX(); - Lock l(&ctx->thread_mtx); - int res = -1; - for (unsigned tid = 0; tid < kMaxTid; tid++) { - ThreadContext *tctx = ctx->threads[tid]; - if (tctx != 0 && tctx->user_id == uid - && tctx->status != ThreadStatusInvalid) { - tctx->user_id = 0; - res = tid; - break; - } - } + int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid); DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res); return res; } @@ -300,18 +277,7 @@ void ThreadJoin(ThreadState *thr, uptr pc, int tid) { CHECK_LT(tid, kMaxTid); DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid); Context *ctx = CTX(); - Lock l(&ctx->thread_mtx); - ThreadContext *tctx = ctx->threads[tid]; - if (tctx->status == ThreadStatusInvalid) { - Printf("ThreadSanitizer: join of non-existent thread\n"); - return; - } - // FIXME(dvyukov): print message and continue (it's user error). - CHECK_EQ(tctx->detached, false); - CHECK_EQ(tctx->status, ThreadStatusFinished); - thr->clock.acquire(&tctx->sync); - StatInc(thr, StatSyncAcquire); - ThreadDead(thr, tctx); + ctx->thread_registry->JoinThread(tid, thr); } void ThreadDetach(ThreadState *thr, uptr pc, int tid) { @@ -319,31 +285,12 @@ void ThreadDetach(ThreadState *thr, uptr pc, int tid) { CHECK_GT(tid, 0); CHECK_LT(tid, kMaxTid); Context *ctx = CTX(); - Lock l(&ctx->thread_mtx); - ThreadContext *tctx = ctx->threads[tid]; - if (tctx->status == ThreadStatusInvalid) { - Printf("ThreadSanitizer: detach of non-existent thread\n"); - return; - } - if (tctx->status == ThreadStatusFinished) { - ThreadDead(thr, tctx); - } else { - tctx->detached = true; - } + ctx->thread_registry->DetachThread(tid); } void ThreadSetName(ThreadState *thr, const char *name) { - Context *ctx = CTX(); - Lock l(&ctx->thread_mtx); - ThreadContext *tctx = ctx->threads[thr->tid]; - CHECK_NE(tctx, 0); - CHECK_EQ(tctx->status, ThreadStatusRunning); - if (tctx->name) { - internal_free(tctx->name); - tctx->name = 0; - } - if (name) - tctx->name = internal_strdup(name); + CHECK_GT(thr->in_rtl, 0); + CTX()->thread_registry->SetThreadName(thr->tid, name); } void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, @@ -378,6 +325,13 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, StatInc(thr, StatMopRange); + if (*shadow_mem == kShadowRodata) { + // Access to .rodata section, no races here. + // Measurements show that it can be 10-20% of all memory accesses. + StatInc(thr, StatMopRangeRodata); + return; + } + FastState fast_state = thr->fast_state; if (fast_state.GetIgnoreBit()) return; @@ -394,7 +348,7 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, Shadow cur(fast_state); cur.SetWrite(is_write); cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog); - MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, + MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, shadow_mem, cur); } if (unaligned) @@ -405,7 +359,7 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, Shadow cur(fast_state); cur.SetWrite(is_write); cur.SetAddr0AndSizeLog(0, kAccessSizeLog); - MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, + MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, shadow_mem, cur); shadow_mem += kShadowCnt; } @@ -415,24 +369,30 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, Shadow cur(fast_state); cur.SetWrite(is_write); cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog); - MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, + MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, shadow_mem, cur); } } -void MemoryRead1Byte(ThreadState *thr, uptr pc, uptr addr) { - MemoryAccess(thr, pc, addr, 0, 0); -} - -void MemoryWrite1Byte(ThreadState *thr, uptr pc, uptr addr) { - MemoryAccess(thr, pc, addr, 0, 1); -} - -void MemoryRead8Byte(ThreadState *thr, uptr pc, uptr addr) { - MemoryAccess(thr, pc, addr, 3, 0); -} +void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr, + uptr size, uptr step, bool is_write) { + if (size == 0) + return; + FastState fast_state = thr->fast_state; + if (fast_state.GetIgnoreBit()) + return; + StatInc(thr, StatMopRange); + fast_state.IncrementEpoch(); + thr->fast_state = fast_state; + TraceAddEvent(thr, fast_state, EventTypeMop, pc); -void MemoryWrite8Byte(ThreadState *thr, uptr pc, uptr addr) { - MemoryAccess(thr, pc, addr, 3, 1); + for (uptr addr_end = addr + size; addr < addr_end; addr += step) { + u64 *shadow_mem = (u64*)MemToShadow(addr); + Shadow cur(fast_state); + cur.SetWrite(is_write); + cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kSizeLog1); + MemoryAccessImpl(thr, addr, kSizeLog1, is_write, false, + shadow_mem, cur); + } } } // namespace __tsan |