1 // Copyright (c) 2009, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 #ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_ 31 #define GOOGLE_BREAKPAD_COMMON_MEMORY_H_ 32 33 #include <stdint.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <sys/mman.h> 37 38 #include <memory> 39 #include <vector> 40 41 #if defined(MEMORY_SANITIZER) 42 #include <sanitizer/msan_interface.h> 43 #endif 44 45 #ifdef __APPLE__ 46 #define sys_mmap mmap 47 #define sys_mmap2 mmap 48 #define sys_munmap munmap 49 #define MAP_ANONYMOUS MAP_ANON 50 #else 51 #include "third_party/lss/linux_syscall_support.h" 52 #endif 53 54 namespace google_breakpad { 55 56 // This is very simple allocator which fetches pages from the kernel directly. 57 // Thus, it can be used even when the heap may be corrupted. 58 // 59 // There is no free operation. The pages are only freed when the object is 60 // destroyed. 61 class PageAllocator { 62 public: 63 PageAllocator() 64 : page_size_(getpagesize()), 65 last_(NULL), 66 current_page_(NULL), 67 page_offset_(0) { 68 } 69 70 ~PageAllocator() { 71 FreeAll(); 72 } 73 74 void *Alloc(size_t bytes) { 75 if (!bytes) 76 return NULL; 77 78 if (current_page_ && page_size_ - page_offset_ >= bytes) { 79 uint8_t *const ret = current_page_ + page_offset_; 80 page_offset_ += bytes; 81 if (page_offset_ == page_size_) { 82 page_offset_ = 0; 83 current_page_ = NULL; 84 } 85 86 return ret; 87 } 88 89 const size_t pages = 90 (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_; 91 uint8_t *const ret = GetNPages(pages); 92 if (!ret) 93 return NULL; 94 95 page_offset_ = 96 (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % 97 page_size_; 98 current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL; 99 100 return ret + sizeof(PageHeader); 101 } 102 103 // Checks whether the page allocator owns the passed-in pointer. 104 // This method exists for testing pursposes only. 105 bool OwnsPointer(const void* p) { 106 for (PageHeader* header = last_; header; header = header->next) { 107 const char* current = reinterpret_cast<char*>(header); 108 if ((p >= current) && (p < current + header->num_pages * page_size_)) 109 return true; 110 } 111 112 return false; 113 } 114 115 private: 116 uint8_t *GetNPages(size_t num_pages) { 117 #if defined(__x86_64__) || defined(__aarch64__) || defined(__aarch64__) || \ 118 ((defined(__mips__) && _MIPS_SIM == _ABI64)) 119 void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, 120 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 121 #else 122 void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, 123 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 124 #endif 125 if (a == MAP_FAILED) 126 return NULL; 127 128 #if defined(MEMORY_SANITIZER) 129 // We need to indicate to MSan that memory allocated through sys_mmap is 130 // initialized, since linux_syscall_support.h doesn't have MSan hooks. 131 __msan_unpoison(a, page_size_ * num_pages); 132 #endif 133 134 struct PageHeader *header = reinterpret_cast<PageHeader*>(a); 135 header->next = last_; 136 header->num_pages = num_pages; 137 last_ = header; 138 139 return reinterpret_cast<uint8_t*>(a); 140 } 141 142 void FreeAll() { 143 PageHeader *next; 144 145 for (PageHeader *cur = last_; cur; cur = next) { 146 next = cur->next; 147 sys_munmap(cur, cur->num_pages * page_size_); 148 } 149 } 150 151 struct PageHeader { 152 PageHeader *next; // pointer to the start of the next set of pages. 153 size_t num_pages; // the number of pages in this set. 154 }; 155 156 const size_t page_size_; 157 PageHeader *last_; 158 uint8_t *current_page_; 159 size_t page_offset_; 160 }; 161 162 // Wrapper to use with STL containers 163 template <typename T> 164 struct PageStdAllocator : public std::allocator<T> { 165 typedef typename std::allocator<T>::pointer pointer; 166 typedef typename std::allocator<T>::size_type size_type; 167 168 explicit PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {} 169 template <class Other> PageStdAllocator(const PageStdAllocator<Other>& other) 170 : allocator_(other.allocator_) {} 171 172 inline pointer allocate(size_type n, const void* = 0) { 173 return static_cast<pointer>(allocator_.Alloc(sizeof(T) * n)); 174 } 175 176 inline void deallocate(pointer, size_type) { 177 // The PageAllocator doesn't free. 178 } 179 180 template <typename U> struct rebind { 181 typedef PageStdAllocator<U> other; 182 }; 183 184 private: 185 // Silly workaround for the gcc from Android's ndk (gcc 4.6), which will 186 // otherwise complain that `other.allocator_` is private in the constructor 187 // code. 188 template<typename Other> friend struct PageStdAllocator; 189 190 PageAllocator& allocator_; 191 }; 192 193 // A wasteful vector is a std::vector, except that it allocates memory from a 194 // PageAllocator. It's wasteful because, when resizing, it always allocates a 195 // whole new array since the PageAllocator doesn't support realloc. 196 template<class T> 197 class wasteful_vector : public std::vector<T, PageStdAllocator<T> > { 198 public: 199 wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16) 200 : std::vector<T, PageStdAllocator<T> >(PageStdAllocator<T>(*allocator)) { 201 std::vector<T, PageStdAllocator<T> >::reserve(size_hint); 202 } 203 }; 204 205 } // namespace google_breakpad 206 207 inline void* operator new(size_t nbytes, 208 google_breakpad::PageAllocator& allocator) { 209 return allocator.Alloc(nbytes); 210 } 211 212 #endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_ 213