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)