asan_fake_stack.cc revision c70fa28caaaec2134f2c2230821fcc0f0d7ac27e
153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)//===-- asan_fake_stack.cc ------------------------------------------------===//
253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)//
353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)//                     The LLVM Compiler Infrastructure
453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)//
553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source
653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)// License. See LICENSE.TXT for details.
753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)//
853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)//===----------------------------------------------------------------------===//
953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)//
1053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)// This file is a part of AddressSanitizer, an address sanity checker.
1153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)//
1253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)// FakeStack is used to detect use-after-return bugs.
1353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)//===----------------------------------------------------------------------===//
1453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "asan_allocator.h"
1553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "asan_thread.h"
1653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "asan_thread_registry.h"
1753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
1853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)namespace __asan {
1953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
2053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)FakeStack::FakeStack() {
2153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  CHECK(REAL(memset) != 0);
2253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  REAL(memset)(this, 0, sizeof(*this));
2353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}
2453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
2553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)bool FakeStack::AddrIsInSizeClass(uptr addr, uptr size_class) {
2653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  uptr mem = allocated_size_classes_[size_class];
2753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  uptr size = ClassMmapSize(size_class);
28a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  bool res = mem && addr >= mem && addr < mem + size;
2953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  return res;
305d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)}
311e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)uptr FakeStack::AddrIsInFakeStack(uptr addr) {
33a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
3419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    if (AddrIsInSizeClass(addr, i)) return allocated_size_classes_[i];
35a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  }
36a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  return 0;
371e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)}
38a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
3951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)// We may want to compute this during compilation.
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)inline uptr FakeStack::ComputeSizeClass(uptr alloc_size) {
41197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch  uptr rounded_size = RoundUpToPowerOfTwo(alloc_size);
4253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  uptr log = Log2(rounded_size);
4353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  CHECK(alloc_size <= (1UL << log));
4409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)  if (!(alloc_size > (1UL << (log-1)))) {
4519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    Printf("alloc_size %zu log %zu\n", alloc_size, log);
46591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch  }
4793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  CHECK(alloc_size > (1UL << (log-1)));
48d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)  uptr res = log < kMinStackFrameSizeLog ? 0 : log - kMinStackFrameSizeLog;
4953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  CHECK(res < kNumberOfSizeClasses);
50591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch  CHECK(ClassSize(res) >= rounded_size);
511e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)  return res;
52a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)}
53a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
54521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)void FakeFrameFifo::FifoPush(FakeFrame *node) {
55521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)  CHECK(node);
5653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  node->next = 0;
5753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  if (first_ == 0 && last_ == 0) {
58a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    first_ = last_ = node;
5953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  } else {
6053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    CHECK(first_);
6153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    CHECK(last_);
62a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    last_->next = node;
63a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    last_ = node;
64a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  }
65a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)}
66a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
67d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)FakeFrame *FakeFrameFifo::FifoPop() {
68a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  CHECK(first_ && last_ && "Exhausted fake stack");
69d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)  FakeFrame *res = 0;
70a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  if (first_ == last_) {
71a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    res = first_;
72a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    first_ = last_ = 0;
73a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  } else {
74d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    res = first_;
75d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    first_ = first_->next;
76d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)  }
77a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  return res;
78a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)}
79a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
80d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)void FakeStack::Init(uptr stack_size) {
81a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  stack_size_ = stack_size;
82a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  alive_ = true;
83a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)}
84a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
85a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)void FakeStack::Cleanup() {
86a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  alive_ = false;
87a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)  for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
88d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    uptr mem = allocated_size_classes_[i];
89a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)    if (mem) {
90a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)      PoisonShadow(mem, ClassMmapSize(i), 0);
91a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)      allocated_size_classes_[i] = 0;
92a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)      UnmapOrDie((void*)mem, ClassMmapSize(i));
9309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
9407a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch  }
9507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch}
9681a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)
9707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochuptr FakeStack::ClassMmapSize(uptr size_class) {
9881a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)  return RoundUpToPowerOfTwo(stack_size_);
9981a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)}
10081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)
10119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)void FakeStack::AllocateOneSizeClass(uptr size_class) {
10251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)  CHECK(ClassMmapSize(size_class) >= GetPageSizeCached());
10351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)  uptr new_mem = (uptr)MmapOrDie(
10419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)      ClassMmapSize(size_class), __FUNCTION__);
10551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)  // Printf("T%d new_mem[%zu]: %p-%p mmap %zu\n",
10619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)  //       asanThreadRegistry().GetCurrent()->tid(),
10719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)  //       size_class, new_mem, new_mem + ClassMmapSize(size_class),
10819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)  //       ClassMmapSize(size_class));
10919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)  uptr i;
11019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)  for (i = 0; i < ClassMmapSize(size_class);
11151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)       i += ClassSize(size_class)) {
11219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    size_classes_[size_class].FifoPush((FakeFrame*)(new_mem + i));
11319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)  }
114323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)  CHECK(i == ClassMmapSize(size_class));
11581a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)  allocated_size_classes_[size_class] = new_mem;
11609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
11709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
11807a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdochuptr FakeStack::AllocateStack(uptr size, uptr real_stack) {
1195267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)  if (!alive_) return real_stack;
120197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch  CHECK(size <= kMaxStackMallocSize && size > 1);
1215267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)  uptr size_class = ComputeSizeClass(size);
122c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles)  if (!allocated_size_classes_[size_class]) {
123f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    AllocateOneSizeClass(size_class);
12481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)  }
125323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)  FakeFrame *fake_frame = size_classes_[size_class].FifoPop();
12653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  CHECK(fake_frame);
12793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)  fake_frame->size_minus_one = size - 1;
12853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  fake_frame->real_stack = real_stack;
12953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  while (FakeFrame *top = call_stack_.top()) {
13053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    if (top->real_stack > real_stack) break;
13153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    call_stack_.LifoPop();
13253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    DeallocateFrame(top);
133aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch  }
13453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  call_stack_.LifoPush(fake_frame);
135323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)  uptr ptr = (uptr)fake_frame;
136323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)  PoisonShadow(ptr, size, 0);
137323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)  return ptr;
13809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
13909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
14009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void FakeStack::DeallocateFrame(FakeFrame *fake_frame) {
14109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)  CHECK(alive_);
14253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  uptr size = fake_frame->size_minus_one + 1;
14353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  uptr size_class = ComputeSizeClass(size);
14453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  CHECK(allocated_size_classes_[size_class]);
14553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  uptr ptr = (uptr)fake_frame;
146197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch  CHECK(AddrIsInSizeClass(ptr, size_class));
147f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)  CHECK(AddrIsInSizeClass(ptr + size - 1, size_class));
148f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)  size_classes_[size_class].FifoPush(fake_frame);
149f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)}
150f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
151f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)void FakeStack::OnFree(uptr ptr, uptr size, uptr real_stack) {
152f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)  FakeFrame *fake_frame = (FakeFrame*)ptr;
153f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)  CHECK(fake_frame->magic = kRetiredStackFrameMagic);
154f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)  CHECK(fake_frame->descr != 0);
155f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu  CHECK(fake_frame->size_minus_one == size - 1);
15653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  PoisonShadow(ptr, size, kAsanStackAfterReturnMagic);
15753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}
15853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
15953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}  // namespace __asan
160323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)
16153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)// ---------------------- Interface ---------------- {{{1
16253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)using namespace __asan;  // NOLINT
163d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
16481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles)uptr __asan_stack_malloc(uptr size, uptr real_stack) {
16507a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch  if (!flags()->use_fake_stack) return real_stack;
16607a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch  AsanThread *t = asanThreadRegistry().GetCurrent();
16753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  if (!t) {
16853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // TSD is gone, use the real stack.
16953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    return real_stack;
17053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  }
171323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)  uptr ptr = t->fake_stack().AllocateStack(size, real_stack);
17253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  // Printf("__asan_stack_malloc %p %zu %p\n", ptr, size, real_stack);
17353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  return ptr;
174d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
175a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)
17653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)void __asan_stack_free(uptr ptr, uptr size, uptr real_stack) {
17753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  if (!flags()->use_fake_stack) return;
17853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)  if (ptr != real_stack) {
179d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    FakeStack::OnFree(ptr, size, real_stack);
180d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)  }
18109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
18209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)