1e5f5895bda30f374b0b51412fd4d837fa59aed66Alexey Samsonov//===-- asan_thread.cc ----------------------------------------------------===//
21e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
31e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//                     The LLVM Compiler Infrastructure
41e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
51e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// This file is distributed under the University of Illinois Open Source
61e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// License. See LICENSE.TXT for details.
71e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
81e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//===----------------------------------------------------------------------===//
91e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
101e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// This file is a part of AddressSanitizer, an address sanity checker.
111e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//
121e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany// Thread-related code.
131e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany//===----------------------------------------------------------------------===//
141e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_allocator.h"
151e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_interceptors.h"
1655cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov#include "asan_stack.h"
171e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_thread.h"
18af3441580555ceed092170232cd5f2cc180f19f4Kostya Serebryany#include "asan_thread_registry.h"
191e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany#include "asan_mapping.h"
20e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov#include "sanitizer_common/sanitizer_common.h"
211e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
221e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryanynamespace __asan {
231e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
241e172b4bdec57329bf904f063a29f99cddf2d85fKostya SerebryanyAsanThread::AsanThread(LinkerInitialized x)
251e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    : fake_stack_(x),
261e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany      malloc_storage_(x),
271e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany      stats_(x) { }
281e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
29e0cff0bc20ae51790c8edfbceb817e18ebf5355eKostya SerebryanyAsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine,
30c3390df6670cb166119b961eb27a033fb9073496Kostya Serebryany                               void *arg, StackTrace *stack) {
313f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany  uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
32a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonov  AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
3355cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  thread->start_routine_ = start_routine;
3455cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  thread->arg_ = arg;
3555cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov
366d924facc5c979a0d25f484cffcdb51c766ed551Kostya Serebryany  const uptr kSummaryAllocSize = kPageSize;
37b134ffa00ce2a4cbf7f48ac029e31c3e6e23ff6bKostya Serebryany  CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize);
386d924facc5c979a0d25f484cffcdb51c766ed551Kostya Serebryany  AsanThreadSummary *summary =
396d924facc5c979a0d25f484cffcdb51c766ed551Kostya Serebryany      (AsanThreadSummary*)MmapOrDie(kPageSize, "AsanThreadSummary");
40b134ffa00ce2a4cbf7f48ac029e31c3e6e23ff6bKostya Serebryany  summary->Init(parent_tid, stack);
4155cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  summary->set_thread(thread);
4255cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  thread->set_summary(summary);
4355cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov
4455cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  return thread;
451e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
461e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
47f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryanyvoid AsanThreadSummary::TSDDtor(void *tsd) {
48f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany  AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
49cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  if (flags()->verbosity >= 1) {
50f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany    Report("T%d TSDDtor\n", summary->tid());
51f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany  }
52f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany  if (summary->thread()) {
53f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany    summary->thread()->Destroy();
54f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany  }
55f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany}
56f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany
57a6b52264e1231bfc4ee9a2d9a4f32678c97295f0Kostya Serebryanyvoid AsanThread::Destroy() {
58cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  if (flags()->verbosity >= 1) {
59f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany    Report("T%d exited\n", tid());
60f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany  }
61f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany
62f58f998066db0231e521169d2f50af439ceecb49Kostya Serebryany  asanThreadRegistry().UnregisterThread(this);
633f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany  CHECK(summary()->thread() == 0);
641e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  // We also clear the shadow on thread destruction because
651e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  // some code may still be executing in later TSD destructors
661e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  // and we don't want it to have any poisoned stack.
671e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  ClearShadowForThreadStack();
6855cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  fake_stack().Cleanup();
693f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany  uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
70a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonov  UnmapOrDie(this, size);
711e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
721e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
7369eca73ac96688c8bfe1f23ee006af29c7858c40Kostya Serebryanyvoid AsanThread::Init() {
741e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  SetThreadStackTopAndBottom();
7555cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  CHECK(AddrIsInMem(stack_bottom_));
7655cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  CHECK(AddrIsInMem(stack_top_));
7755cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  ClearShadowForThreadStack();
78cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  if (flags()->verbosity >= 1) {
791e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    int local = 0;
80739eb7984139d457216623347ae3b7a706c0aadfEvgeniy Stepanov    Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
815bcca4e33ececdddd8e9e07619c129e870492251Alexey Samsonov           tid(), (void*)stack_bottom_, (void*)stack_top_,
82a7e760a53bc43b8e09bfdf5cd6f215267ba99729Kostya Serebryany           stack_top_ - stack_bottom_, &local);
831e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  }
8455cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  fake_stack_.Init(stack_size());
8575b19ebf25af204cf209d108997272822241d6daAlexander Potapenko  AsanPlatformThreadInit();
8669eca73ac96688c8bfe1f23ee006af29c7858c40Kostya Serebryany}
8769eca73ac96688c8bfe1f23ee006af29c7858c40Kostya Serebryany
88600972e3427173cc8904d741decd1af0ed5de9fdTimur Iskhodzhanovthread_return_t AsanThread::ThreadStart() {
8969eca73ac96688c8bfe1f23ee006af29c7858c40Kostya Serebryany  Init();
90cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  if (flags()->use_sigaltstack) SetAlternateSignalStack();
911e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
921e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  if (!start_routine_) {
933f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany    // start_routine_ == 0 if we're on the main thread or on one of the
941e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    // OS X libdispatch worker threads. But nobody is supposed to call
951e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    // ThreadStart() for the worker threads.
961e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    CHECK(tid() == 0);
971e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    return 0;
981e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  }
991e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
100600972e3427173cc8904d741decd1af0ed5de9fdTimur Iskhodzhanov  thread_return_t res = start_routine_(arg_);
1011e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  malloc_storage().CommitBack();
102cb8c4dce691097718d5af41b36899b72ef4b1d84Alexey Samsonov  if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
1031e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
104af3441580555ceed092170232cd5f2cc180f19f4Kostya Serebryany  this->Destroy();
105af3441580555ceed092170232cd5f2cc180f19f4Kostya Serebryany
1061e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  return res;
1071e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
1081e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
109e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonovvoid AsanThread::SetThreadStackTopAndBottom() {
110e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov  GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
111e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov  int local;
112e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov  CHECK(AddrIsInStack((uptr)&local));
113e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov}
114e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov
11555cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonovvoid AsanThread::ClearShadowForThreadStack() {
11655cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov  PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
11755cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov}
11855cdfc6c5af92560bc0623b5a0d70af71511c3c8Alexey Samsonov
1193f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryanyconst char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
1203f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany  uptr bottom = 0;
1211e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  bool is_fake_stack = false;
1221e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  if (AddrIsInStack(addr)) {
1231e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    bottom = stack_bottom();
1241e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  } else {
1251e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    bottom = fake_stack().AddrIsInFakeStack(addr);
1261e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    CHECK(bottom);
1271e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany    is_fake_stack = true;
1281e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  }
1293f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany  uptr aligned_addr = addr & ~(__WORDSIZE/8 - 1);  // align addr.
130ee3925515e4c7966f3ef489f687aa7e5692806a9Kostya Serebryany  u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
131ee3925515e4c7966f3ef489f687aa7e5692806a9Kostya Serebryany  u8 *shadow_bottom = (u8*)MemToShadow(bottom);
1323972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov
1333972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov  while (shadow_ptr >= shadow_bottom &&
1343972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov      *shadow_ptr != kAsanStackLeftRedzoneMagic) {
1353972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov    shadow_ptr--;
1363972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov  }
1373972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov
1383972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov  while (shadow_ptr >= shadow_bottom &&
1393972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov      *shadow_ptr == kAsanStackLeftRedzoneMagic) {
1403972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov    shadow_ptr--;
1411e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany  }
1423972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov
1433972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov  if (shadow_ptr < shadow_bottom) {
1443972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov    *offset = 0;
1453972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov    return "UNKNOWN";
1463972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov  }
1473972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov
1483f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany  uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
1493972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov  CHECK((ptr[0] == kCurrentStackFrameMagic) ||
1503972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov      (is_fake_stack && ptr[0] == kRetiredStackFrameMagic));
1513f4c3875c42078e22c7e5356c5746fd18756d958Kostya Serebryany  *offset = addr - (uptr)ptr;
1523972ea03aa52d81ca324945ba94eea22d403df12Evgeniy Stepanov  return (const char*)ptr[1];
1531e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}
1541e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany
1551e172b4bdec57329bf904f063a29f99cddf2d85fKostya Serebryany}  // namespace __asan
156