| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 #ifndef HeapPage_h | 31 #ifndef HeapPage_h |
| 32 #define HeapPage_h | 32 #define HeapPage_h |
| 33 | 33 |
| 34 #include <stdint.h> |
| 34 #include "base/trace_event/memory_allocator_dump.h" | 35 #include "base/trace_event/memory_allocator_dump.h" |
| 35 #include "platform/PlatformExport.h" | 36 #include "platform/PlatformExport.h" |
| 36 #include "platform/heap/BlinkGC.h" | 37 #include "platform/heap/BlinkGC.h" |
| 37 #include "platform/heap/GCInfo.h" | 38 #include "platform/heap/GCInfo.h" |
| 38 #include "platform/heap/ThreadState.h" | 39 #include "platform/heap/ThreadState.h" |
| 39 #include "platform/heap/Visitor.h" | 40 #include "platform/heap/Visitor.h" |
| 40 #include "wtf/AddressSanitizer.h" | 41 #include "wtf/AddressSanitizer.h" |
| 41 #include "wtf/Allocator.h" | 42 #include "wtf/Allocator.h" |
| 42 #include "wtf/Assertions.h" | 43 #include "wtf/Assertions.h" |
| 43 #include "wtf/ContainerAnnotations.h" | 44 #include "wtf/ContainerAnnotations.h" |
| 44 #include "wtf/Forward.h" | 45 #include "wtf/Forward.h" |
| 45 #include "wtf/allocator/Partitions.h" | 46 #include "wtf/allocator/Partitions.h" |
| 46 #include <stdint.h> | |
| 47 | 47 |
| 48 namespace blink { | 48 namespace blink { |
| 49 | 49 |
| 50 const size_t blinkPageSizeLog2 = 17; | 50 const size_t blinkPageSizeLog2 = 17; |
| 51 const size_t blinkPageSize = 1 << blinkPageSizeLog2; | 51 const size_t blinkPageSize = 1 << blinkPageSizeLog2; |
| 52 const size_t blinkPageOffsetMask = blinkPageSize - 1; | 52 const size_t blinkPageOffsetMask = blinkPageSize - 1; |
| 53 const size_t blinkPageBaseMask = ~blinkPageOffsetMask; | 53 const size_t blinkPageBaseMask = ~blinkPageOffsetMask; |
| 54 | 54 |
| 55 // We allocate pages at random addresses but in groups of | 55 // We allocate pages at random addresses but in groups of |
| 56 // blinkPagesPerRegion at a given random address. We group pages to | 56 // blinkPagesPerRegion at a given random address. We group pages to |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 #else | 117 #else |
| 118 #define SET_MEMORY_INACCESSIBLE(address, size) memset((address), 0, (size)) | 118 #define SET_MEMORY_INACCESSIBLE(address, size) memset((address), 0, (size)) |
| 119 #define SET_MEMORY_ACCESSIBLE(address, size) \ | 119 #define SET_MEMORY_ACCESSIBLE(address, size) \ |
| 120 do { \ | 120 do { \ |
| 121 } while (false) | 121 } while (false) |
| 122 #define CHECK_MEMORY_INACCESSIBLE(address, size) \ | 122 #define CHECK_MEMORY_INACCESSIBLE(address, size) \ |
| 123 do { \ | 123 do { \ |
| 124 } while (false) | 124 } while (false) |
| 125 #endif | 125 #endif |
| 126 | 126 |
| 127 #if !DCHECK_IS_ON() && CPU(64BIT) | |
| 128 #define USE_4BYTE_HEADER_PADDING 1 | |
| 129 #else | |
| 130 #define USE_4BYTE_HEADER_PADDING 0 | |
| 131 #endif | |
| 132 | |
| 133 class NormalPageArena; | 127 class NormalPageArena; |
| 134 class PageMemory; | 128 class PageMemory; |
| 135 | 129 |
| 136 // HeapObjectHeader is 4 byte (32 bit) that has the following layout: | 130 // HeapObjectHeader is 4 byte (32 bit) that has the following layout: |
| 137 // | 131 // |
| 138 // | gcInfoIndex (14 bit) | | 132 // | gcInfoIndex (14 bit) | |
| 139 // | DOM mark bit (1 bit) | | 133 // | DOM mark bit (1 bit) | |
| 140 // | size (14 bit) | | 134 // | size (14 bit) | |
| 141 // | dead bit (1 bit) | | 135 // | dead bit (1 bit) | |
| 142 // | freed bit (1 bit) | | 136 // | freed bit (1 bit) | |
| (...skipping 29 matching lines...) Expand all Loading... |
| 172 nonLargeObjectPageSizeMax >= blinkPageSize, | 166 nonLargeObjectPageSizeMax >= blinkPageSize, |
| 173 "max size supported by HeapObjectHeader must at least be blinkPageSize"); | 167 "max size supported by HeapObjectHeader must at least be blinkPageSize"); |
| 174 | 168 |
| 175 class PLATFORM_EXPORT HeapObjectHeader { | 169 class PLATFORM_EXPORT HeapObjectHeader { |
| 176 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); | 170 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); |
| 177 | 171 |
| 178 public: | 172 public: |
| 179 // If gcInfoIndex is 0, this header is interpreted as a free list header. | 173 // If gcInfoIndex is 0, this header is interpreted as a free list header. |
| 180 NO_SANITIZE_ADDRESS | 174 NO_SANITIZE_ADDRESS |
| 181 HeapObjectHeader(size_t size, size_t gcInfoIndex) { | 175 HeapObjectHeader(size_t size, size_t gcInfoIndex) { |
| 182 #if DCHECK_IS_ON() | 176 m_magic = getMagic(); |
| 183 m_magic = magic; | |
| 184 #endif | |
| 185 // sizeof(HeapObjectHeader) must be equal to or smaller than | 177 // sizeof(HeapObjectHeader) must be equal to or smaller than |
| 186 // allocationGranurarity, because HeapObjectHeader is used as a header | 178 // allocationGranurarity, because HeapObjectHeader is used as a header |
| 187 // for an freed entry. Given that the smallest entry size is | 179 // for an freed entry. Given that the smallest entry size is |
| 188 // allocationGranurarity, HeapObjectHeader must fit into the size. | 180 // allocationGranurarity, HeapObjectHeader must fit into the size. |
| 189 static_assert( | 181 static_assert( |
| 190 sizeof(HeapObjectHeader) <= allocationGranularity, | 182 sizeof(HeapObjectHeader) <= allocationGranularity, |
| 191 "size of HeapObjectHeader must be smaller than allocationGranularity"); | 183 "size of HeapObjectHeader must be smaller than allocationGranularity"); |
| 192 #if CPU(64BIT) | |
| 193 static_assert(sizeof(HeapObjectHeader) == 8, | 184 static_assert(sizeof(HeapObjectHeader) == 8, |
| 194 "size of HeapObjectHeader must be 8 byte aligned"); | 185 "sizeof(HeapObjectHeader) must be 8 bytes"); |
| 195 #endif | |
| 196 | 186 |
| 197 ASSERT(gcInfoIndex < GCInfoTable::maxIndex); | 187 ASSERT(gcInfoIndex < GCInfoTable::maxIndex); |
| 198 ASSERT(size < nonLargeObjectPageSizeMax); | 188 ASSERT(size < nonLargeObjectPageSizeMax); |
| 199 ASSERT(!(size & allocationMask)); | 189 ASSERT(!(size & allocationMask)); |
| 200 m_encoded = static_cast<uint32_t>( | 190 m_encoded = static_cast<uint32_t>( |
| 201 (gcInfoIndex << headerGCInfoIndexShift) | size | | 191 (gcInfoIndex << headerGCInfoIndexShift) | size | |
| 202 (gcInfoIndex == gcInfoIndexForFreeListHeader ? headerFreedBitMask : 0)); | 192 (gcInfoIndex == gcInfoIndexForFreeListHeader ? headerFreedBitMask : 0)); |
| 203 } | 193 } |
| 204 | 194 |
| 205 NO_SANITIZE_ADDRESS | 195 NO_SANITIZE_ADDRESS |
| (...skipping 20 matching lines...) Expand all Loading... |
| 226 void markWrapperHeader(); | 216 void markWrapperHeader(); |
| 227 void unmarkWrapperHeader(); | 217 void unmarkWrapperHeader(); |
| 228 bool isMarked() const; | 218 bool isMarked() const; |
| 229 void mark(); | 219 void mark(); |
| 230 void unmark(); | 220 void unmark(); |
| 231 | 221 |
| 232 Address payload(); | 222 Address payload(); |
| 233 size_t payloadSize(); | 223 size_t payloadSize(); |
| 234 Address payloadEnd(); | 224 Address payloadEnd(); |
| 235 | 225 |
| 236 #if DCHECK_IS_ON() | 226 // TODO(633030): Make |checkHeader| and |zapMagic| private. This class should |
| 227 // manage its integrity on its own, without requiring outside callers to |
| 228 // explicitly check. |
| 237 bool checkHeader() const; | 229 bool checkHeader() const; |
| 238 // Zap magic number with a new magic number that means there was once an | 230 // Zap magic number with a new magic number that means there was once an |
| 239 // object allocated here, but it was freed because nobody marked it during | 231 // object allocated here, but it was freed because nobody marked it during |
| 240 // GC. | 232 // GC. |
| 241 void zapMagic(); | 233 void zapMagic(); |
| 242 #endif | |
| 243 | 234 |
| 244 void finalize(Address, size_t); | 235 void finalize(Address, size_t); |
| 245 static HeapObjectHeader* fromPayload(const void*); | 236 static HeapObjectHeader* fromPayload(const void*); |
| 246 | 237 |
| 247 static const uint16_t magic = 0xfff1; | 238 static const uint32_t zappedMagic = 0xDEAD4321; |
| 248 static const uint16_t zappedMagic = 0x4321; | |
| 249 | 239 |
| 250 private: | 240 private: |
| 241 // Returns a random value. |
| 242 // |
| 243 // The implementation gets its randomness from the locations of 2 independent |
| 244 // sources of address space layout randomization: a function in a Chrome |
| 245 // executable image, and a function in an external DLL/so. This implementation |
| 246 // should be fast and small, and should have the benefit of requiring |
| 247 // attackers to discover and use 2 independent weak infoleak bugs, or 1 |
| 248 // arbitrary infoleak bug (used twice). |
| 249 uint32_t getMagic() const; |
| 250 |
| 251 uint32_t m_magic; |
| 251 uint32_t m_encoded; | 252 uint32_t m_encoded; |
| 252 #if DCHECK_IS_ON() | |
| 253 uint16_t m_magic; | |
| 254 #endif | |
| 255 | |
| 256 // In 64 bit architectures, we intentionally add 4 byte padding immediately | |
| 257 // after the HeapObjectHeader. This is because: | |
| 258 // | |
| 259 // | HeapObjectHeader (4 byte) | <- 8 byte aligned | |
| 260 // | padding (4 byte) | | |
| 261 // | object payload (8 * n byte) | <- 8 byte aligned | |
| 262 // | |
| 263 // is better than: | |
| 264 // | |
| 265 // | HeapObjectHeader (4 byte) | <- 4 byte aligned | |
| 266 // | object payload (8 * n byte) | <- 8 byte aligned | |
| 267 // | padding (4 byte) | <- 4 byte aligned | |
| 268 // | |
| 269 // since the former layout aligns both header and payload to 8 byte. | |
| 270 #if USE_4BYTE_HEADER_PADDING | |
| 271 public: | |
| 272 uint32_t m_padding; | |
| 273 #endif | |
| 274 }; | 253 }; |
| 275 | 254 |
| 276 class FreeListEntry final : public HeapObjectHeader { | 255 class FreeListEntry final : public HeapObjectHeader { |
| 277 public: | 256 public: |
| 278 NO_SANITIZE_ADDRESS | 257 NO_SANITIZE_ADDRESS |
| 279 explicit FreeListEntry(size_t size) | 258 explicit FreeListEntry(size_t size) |
| 280 : HeapObjectHeader(size, gcInfoIndexForFreeListHeader), m_next(nullptr) { | 259 : HeapObjectHeader(size, gcInfoIndexForFreeListHeader), m_next(nullptr) { |
| 281 #if DCHECK_IS_ON() | 260 #if DCHECK_IS_ON() |
| 282 ASSERT(size >= sizeof(HeapObjectHeader)); | 261 ASSERT(size >= sizeof(HeapObjectHeader)); |
| 283 zapMagic(); | 262 zapMagic(); |
| (...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 849 NO_SANITIZE_ADDRESS inline size_t HeapObjectHeader::size() const { | 828 NO_SANITIZE_ADDRESS inline size_t HeapObjectHeader::size() const { |
| 850 size_t result = m_encoded & headerSizeMask; | 829 size_t result = m_encoded & headerSizeMask; |
| 851 // Large objects should not refer to header->size(). | 830 // Large objects should not refer to header->size(). |
| 852 // The actual size of a large object is stored in | 831 // The actual size of a large object is stored in |
| 853 // LargeObjectPage::m_payloadSize. | 832 // LargeObjectPage::m_payloadSize. |
| 854 ASSERT(result != largeObjectSizeInHeader); | 833 ASSERT(result != largeObjectSizeInHeader); |
| 855 ASSERT(!pageFromObject(this)->isLargeObjectPage()); | 834 ASSERT(!pageFromObject(this)->isLargeObjectPage()); |
| 856 return result; | 835 return result; |
| 857 } | 836 } |
| 858 | 837 |
| 859 #if DCHECK_IS_ON() | |
| 860 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::checkHeader() const { | 838 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::checkHeader() const { |
| 861 return m_magic == magic; | 839 return m_magic == getMagic(); |
| 862 } | 840 } |
| 863 #endif | |
| 864 | 841 |
| 865 inline Address HeapObjectHeader::payload() { | 842 inline Address HeapObjectHeader::payload() { |
| 866 return reinterpret_cast<Address>(this) + sizeof(HeapObjectHeader); | 843 return reinterpret_cast<Address>(this) + sizeof(HeapObjectHeader); |
| 867 } | 844 } |
| 868 | 845 |
| 869 inline Address HeapObjectHeader::payloadEnd() { | 846 inline Address HeapObjectHeader::payloadEnd() { |
| 870 return reinterpret_cast<Address>(this) + size(); | 847 return reinterpret_cast<Address>(this) + size(); |
| 871 } | 848 } |
| 872 | 849 |
| 873 NO_SANITIZE_ADDRESS inline size_t HeapObjectHeader::payloadSize() { | 850 NO_SANITIZE_ADDRESS inline size_t HeapObjectHeader::payloadSize() { |
| 874 size_t size = m_encoded & headerSizeMask; | 851 size_t size = m_encoded & headerSizeMask; |
| 875 if (UNLIKELY(size == largeObjectSizeInHeader)) { | 852 if (UNLIKELY(size == largeObjectSizeInHeader)) { |
| 876 ASSERT(pageFromObject(this)->isLargeObjectPage()); | 853 ASSERT(pageFromObject(this)->isLargeObjectPage()); |
| 877 return static_cast<LargeObjectPage*>(pageFromObject(this))->payloadSize(); | 854 return static_cast<LargeObjectPage*>(pageFromObject(this))->payloadSize(); |
| 878 } | 855 } |
| 879 ASSERT(!pageFromObject(this)->isLargeObjectPage()); | 856 ASSERT(!pageFromObject(this)->isLargeObjectPage()); |
| 880 return size - sizeof(HeapObjectHeader); | 857 return size - sizeof(HeapObjectHeader); |
| 881 } | 858 } |
| 882 | 859 |
| 883 inline HeapObjectHeader* HeapObjectHeader::fromPayload(const void* payload) { | 860 inline HeapObjectHeader* HeapObjectHeader::fromPayload(const void* payload) { |
| 884 Address addr = reinterpret_cast<Address>(const_cast<void*>(payload)); | 861 Address addr = reinterpret_cast<Address>(const_cast<void*>(payload)); |
| 885 HeapObjectHeader* header = | 862 HeapObjectHeader* header = |
| 886 reinterpret_cast<HeapObjectHeader*>(addr - sizeof(HeapObjectHeader)); | 863 reinterpret_cast<HeapObjectHeader*>(addr - sizeof(HeapObjectHeader)); |
| 887 ASSERT(header->checkHeader()); | 864 ASSERT(header->checkHeader()); |
| 888 return header; | 865 return header; |
| 889 } | 866 } |
| 890 | 867 |
| 868 inline uint32_t HeapObjectHeader::getMagic() const { |
| 869 const uintptr_t random1 = |
| 870 ~(reinterpret_cast<uintptr_t>( |
| 871 base::trace_event::MemoryAllocatorDump::kNameSize) >> |
| 872 16); |
| 873 |
| 874 #if OS(WIN) |
| 875 const uintptr_t random2 = ~(reinterpret_cast<uintptr_t>(::ReadFile) << 16); |
| 876 #elif OS(POSIX) |
| 877 const uintptr_t random2 = ~(reinterpret_cast<uintptr_t>(::read) << 16); |
| 878 #else |
| 879 #error OS not supported |
| 880 #endif |
| 881 |
| 882 #if CPU(64BIT) |
| 883 static_assert(sizeof(uintptr_t) == sizeof(uint64_t), |
| 884 "uintptr_t is not uint64_t"); |
| 885 const uint32_t random = static_cast<uint32_t>( |
| 886 (random1 & 0x0FFFFULL) | ((random2 >> 32) & 0x0FFFF0000ULL)); |
| 887 #elif CPU(32BIT) |
| 888 static_assert(sizeof(uintptr_t) == sizeof(uint32_t), |
| 889 "uintptr_t is not uint32_t"); |
| 890 const uint32_t random = (random1 & 0x0FFFFUL) | (random2 & 0xFFFF0000UL); |
| 891 #else |
| 892 #error architecture not supported |
| 893 #endif |
| 894 |
| 895 return random; |
| 896 } |
| 897 |
| 891 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::isWrapperHeaderMarked() | 898 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::isWrapperHeaderMarked() |
| 892 const { | 899 const { |
| 893 ASSERT(checkHeader()); | 900 ASSERT(checkHeader()); |
| 894 return m_encoded & headerWrapperMarkBitMask; | 901 return m_encoded & headerWrapperMarkBitMask; |
| 895 } | 902 } |
| 896 | 903 |
| 897 NO_SANITIZE_ADDRESS inline void HeapObjectHeader::markWrapperHeader() { | 904 NO_SANITIZE_ADDRESS inline void HeapObjectHeader::markWrapperHeader() { |
| 898 ASSERT(checkHeader()); | 905 ASSERT(checkHeader()); |
| 899 ASSERT(!isWrapperHeaderMarked()); | 906 ASSERT(!isWrapperHeaderMarked()); |
| 900 m_encoded |= headerWrapperMarkBitMask; | 907 m_encoded |= headerWrapperMarkBitMask; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 941 return outOfLineAllocate(allocationSize, gcInfoIndex); | 948 return outOfLineAllocate(allocationSize, gcInfoIndex); |
| 942 } | 949 } |
| 943 | 950 |
| 944 inline NormalPageArena* NormalPage::arenaForNormalPage() const { | 951 inline NormalPageArena* NormalPage::arenaForNormalPage() const { |
| 945 return static_cast<NormalPageArena*>(arena()); | 952 return static_cast<NormalPageArena*>(arena()); |
| 946 } | 953 } |
| 947 | 954 |
| 948 } // namespace blink | 955 } // namespace blink |
| 949 | 956 |
| 950 #endif // HeapPage_h | 957 #endif // HeapPage_h |
| OLD | NEW |