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 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 nonLargeObjectPageSizeMax >= blinkPageSize, | 167 nonLargeObjectPageSizeMax >= blinkPageSize, |
168 "max size supported by HeapObjectHeader must at least be blinkPageSize"); | 168 "max size supported by HeapObjectHeader must at least be blinkPageSize"); |
169 | 169 |
170 class PLATFORM_EXPORT HeapObjectHeader { | 170 class PLATFORM_EXPORT HeapObjectHeader { |
171 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); | 171 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); |
172 | 172 |
173 public: | 173 public: |
174 // If |gcInfoIndex| is 0, this header is interpreted as a free list header. | 174 // If |gcInfoIndex| is 0, this header is interpreted as a free list header. |
175 NO_SANITIZE_ADDRESS | 175 NO_SANITIZE_ADDRESS |
176 HeapObjectHeader(size_t size, size_t gcInfoIndex) { | 176 HeapObjectHeader(size_t size, size_t gcInfoIndex) { |
177 m_magic = getMagic(); | |
178 // sizeof(HeapObjectHeader) must be equal to or smaller than | 177 // sizeof(HeapObjectHeader) must be equal to or smaller than |
179 // |allocationGranularity|, because |HeapObjectHeader| is used as a header | 178 // |allocationGranularity|, because |HeapObjectHeader| is used as a header |
180 // for a freed entry. Given that the smallest entry size is | 179 // for a freed entry. Given that the smallest entry size is |
181 // |allocationGranurarity|, |HeapObjectHeader| must fit into the size. | 180 // |allocationGranurarity|, |HeapObjectHeader| must fit into the size. |
182 static_assert( | 181 static_assert( |
183 sizeof(HeapObjectHeader) <= allocationGranularity, | 182 sizeof(HeapObjectHeader) <= allocationGranularity, |
184 "size of HeapObjectHeader must be smaller than allocationGranularity"); | 183 "size of HeapObjectHeader must be smaller than allocationGranularity"); |
| 184 #if CPU(64BIT) |
185 static_assert(sizeof(HeapObjectHeader) == 8, | 185 static_assert(sizeof(HeapObjectHeader) == 8, |
186 "sizeof(HeapObjectHeader) must be 8 bytes"); | 186 "sizeof(HeapObjectHeader) must be 8 bytes"); |
| 187 m_magic = getMagic(); |
| 188 #endif |
187 | 189 |
188 ASSERT(gcInfoIndex < GCInfoTable::maxIndex); | 190 ASSERT(gcInfoIndex < GCInfoTable::maxIndex); |
189 ASSERT(size < nonLargeObjectPageSizeMax); | 191 ASSERT(size < nonLargeObjectPageSizeMax); |
190 ASSERT(!(size & allocationMask)); | 192 ASSERT(!(size & allocationMask)); |
191 m_encoded = static_cast<uint32_t>( | 193 m_encoded = static_cast<uint32_t>( |
192 (gcInfoIndex << headerGCInfoIndexShift) | size | | 194 (gcInfoIndex << headerGCInfoIndexShift) | size | |
193 (gcInfoIndex == gcInfoIndexForFreeListHeader ? headerFreedBitMask : 0)); | 195 (gcInfoIndex == gcInfoIndexForFreeListHeader ? headerFreedBitMask : 0)); |
194 } | 196 } |
195 | 197 |
196 NO_SANITIZE_ADDRESS | 198 NO_SANITIZE_ADDRESS |
(...skipping 25 matching lines...) Expand all Loading... |
222 | 224 |
223 Address payload(); | 225 Address payload(); |
224 size_t payloadSize(); | 226 size_t payloadSize(); |
225 Address payloadEnd(); | 227 Address payloadEnd(); |
226 | 228 |
227 // TODO(633030): Make |checkHeader| and |zapMagic| private. This class should | 229 // TODO(633030): Make |checkHeader| and |zapMagic| private. This class should |
228 // manage its integrity on its own, without requiring outside callers to | 230 // manage its integrity on its own, without requiring outside callers to |
229 // explicitly check. | 231 // explicitly check. |
230 bool checkHeader() const; | 232 bool checkHeader() const; |
231 | 233 |
| 234 #if DCHECK_IS_ON() && CPU(64BIT) |
232 // Zap |m_magic| with a new magic number that means there was once an object | 235 // Zap |m_magic| with a new magic number that means there was once an object |
233 // allocated here, but it was freed because nobody marked it during GC. | 236 // allocated here, but it was freed because nobody marked it during GC. |
234 void zapMagic(); | 237 void zapMagic(); |
| 238 #endif |
235 | 239 |
236 void finalize(Address, size_t); | 240 void finalize(Address, size_t); |
237 static HeapObjectHeader* fromPayload(const void*); | 241 static HeapObjectHeader* fromPayload(const void*); |
238 | 242 |
239 static const uint32_t zappedMagic = 0xDEAD4321; | 243 static const uint32_t zappedMagic = 0xDEAD4321; |
240 | 244 |
241 private: | 245 private: |
| 246 #if CPU(64BIT) |
242 // Returns a random value. | 247 // Returns a random value. |
243 // | 248 // |
244 // The implementation gets its randomness from the locations of 2 independent | 249 // The implementation gets its randomness from the locations of 2 independent |
245 // sources of address space layout randomization: a function in a Chrome | 250 // sources of address space layout randomization: a function in a Chrome |
246 // executable image, and a function in an external DLL/so. This implementation | 251 // executable image, and a function in an external DLL/so. This implementation |
247 // should be fast and small, and should have the benefit of requiring | 252 // should be fast and small, and should have the benefit of requiring |
248 // attackers to discover and use 2 independent weak infoleak bugs, or 1 | 253 // attackers to discover and use 2 independent weak infoleak bugs, or 1 |
249 // arbitrary infoleak bug (used twice). | 254 // arbitrary infoleak bug (used twice). |
250 uint32_t getMagic() const; | 255 uint32_t getMagic() const; |
| 256 uint32_t m_magic; |
| 257 #endif |
251 | 258 |
252 uint32_t m_magic; | |
253 uint32_t m_encoded; | 259 uint32_t m_encoded; |
254 }; | 260 }; |
255 | 261 |
256 class FreeListEntry final : public HeapObjectHeader { | 262 class FreeListEntry final : public HeapObjectHeader { |
257 public: | 263 public: |
258 NO_SANITIZE_ADDRESS | 264 NO_SANITIZE_ADDRESS |
259 explicit FreeListEntry(size_t size) | 265 explicit FreeListEntry(size_t size) |
260 : HeapObjectHeader(size, gcInfoIndexForFreeListHeader), m_next(nullptr) { | 266 : HeapObjectHeader(size, gcInfoIndexForFreeListHeader), m_next(nullptr) { |
261 #if DCHECK_IS_ON() | 267 #if DCHECK_IS_ON() && CPU(64BIT) |
262 ASSERT(size >= sizeof(HeapObjectHeader)); | 268 ASSERT(size >= sizeof(HeapObjectHeader)); |
263 zapMagic(); | 269 zapMagic(); |
264 #endif | 270 #endif |
265 } | 271 } |
266 | 272 |
267 Address getAddress() { return reinterpret_cast<Address>(this); } | 273 Address getAddress() { return reinterpret_cast<Address>(this); } |
268 | 274 |
269 NO_SANITIZE_ADDRESS | 275 NO_SANITIZE_ADDRESS |
270 void unlink(FreeListEntry** prevNext) { | 276 void unlink(FreeListEntry** prevNext) { |
271 *prevNext = m_next; | 277 *prevNext = m_next; |
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
826 NO_SANITIZE_ADDRESS inline size_t HeapObjectHeader::size() const { | 832 NO_SANITIZE_ADDRESS inline size_t HeapObjectHeader::size() const { |
827 size_t result = m_encoded & headerSizeMask; | 833 size_t result = m_encoded & headerSizeMask; |
828 // Large objects should not refer to header->size(). The actual size of a | 834 // Large objects should not refer to header->size(). The actual size of a |
829 // large object is stored in |LargeObjectPage::m_payloadSize|. | 835 // large object is stored in |LargeObjectPage::m_payloadSize|. |
830 ASSERT(result != largeObjectSizeInHeader); | 836 ASSERT(result != largeObjectSizeInHeader); |
831 ASSERT(!pageFromObject(this)->isLargeObjectPage()); | 837 ASSERT(!pageFromObject(this)->isLargeObjectPage()); |
832 return result; | 838 return result; |
833 } | 839 } |
834 | 840 |
835 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::checkHeader() const { | 841 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::checkHeader() const { |
| 842 #if CPU(64BIT) |
836 return m_magic == getMagic(); | 843 return m_magic == getMagic(); |
| 844 #else |
| 845 return true; |
| 846 #endif |
837 } | 847 } |
838 | 848 |
839 inline Address HeapObjectHeader::payload() { | 849 inline Address HeapObjectHeader::payload() { |
840 return reinterpret_cast<Address>(this) + sizeof(HeapObjectHeader); | 850 return reinterpret_cast<Address>(this) + sizeof(HeapObjectHeader); |
841 } | 851 } |
842 | 852 |
843 inline Address HeapObjectHeader::payloadEnd() { | 853 inline Address HeapObjectHeader::payloadEnd() { |
844 return reinterpret_cast<Address>(this) + size(); | 854 return reinterpret_cast<Address>(this) + size(); |
845 } | 855 } |
846 | 856 |
847 NO_SANITIZE_ADDRESS inline size_t HeapObjectHeader::payloadSize() { | 857 NO_SANITIZE_ADDRESS inline size_t HeapObjectHeader::payloadSize() { |
848 size_t size = m_encoded & headerSizeMask; | 858 size_t size = m_encoded & headerSizeMask; |
849 if (UNLIKELY(size == largeObjectSizeInHeader)) { | 859 if (UNLIKELY(size == largeObjectSizeInHeader)) { |
850 ASSERT(pageFromObject(this)->isLargeObjectPage()); | 860 ASSERT(pageFromObject(this)->isLargeObjectPage()); |
851 return static_cast<LargeObjectPage*>(pageFromObject(this))->payloadSize(); | 861 return static_cast<LargeObjectPage*>(pageFromObject(this))->payloadSize(); |
852 } | 862 } |
853 ASSERT(!pageFromObject(this)->isLargeObjectPage()); | 863 ASSERT(!pageFromObject(this)->isLargeObjectPage()); |
854 return size - sizeof(HeapObjectHeader); | 864 return size - sizeof(HeapObjectHeader); |
855 } | 865 } |
856 | 866 |
857 inline HeapObjectHeader* HeapObjectHeader::fromPayload(const void* payload) { | 867 inline HeapObjectHeader* HeapObjectHeader::fromPayload(const void* payload) { |
858 Address addr = reinterpret_cast<Address>(const_cast<void*>(payload)); | 868 Address addr = reinterpret_cast<Address>(const_cast<void*>(payload)); |
859 HeapObjectHeader* header = | 869 HeapObjectHeader* header = |
860 reinterpret_cast<HeapObjectHeader*>(addr - sizeof(HeapObjectHeader)); | 870 reinterpret_cast<HeapObjectHeader*>(addr - sizeof(HeapObjectHeader)); |
861 ASSERT(header->checkHeader()); | 871 ASSERT(header->checkHeader()); |
862 return header; | 872 return header; |
863 } | 873 } |
864 | 874 |
| 875 #if CPU(64BIT) |
865 inline uint32_t HeapObjectHeader::getMagic() const { | 876 inline uint32_t HeapObjectHeader::getMagic() const { |
866 const uintptr_t random1 = | 877 const uintptr_t random1 = |
867 ~(reinterpret_cast<uintptr_t>( | 878 ~(reinterpret_cast<uintptr_t>( |
868 base::trace_event::MemoryAllocatorDump::kNameSize) >> | 879 base::trace_event::MemoryAllocatorDump::kNameSize) >> |
869 16); | 880 16); |
870 | 881 |
871 #if OS(WIN) | 882 #if OS(WIN) |
872 const uintptr_t random2 = ~(reinterpret_cast<uintptr_t>(::ReadFile) << 16); | 883 const uintptr_t random2 = ~(reinterpret_cast<uintptr_t>(::ReadFile) << 16); |
873 #elif OS(POSIX) | 884 #elif OS(POSIX) |
874 const uintptr_t random2 = ~(reinterpret_cast<uintptr_t>(::read) << 16); | 885 const uintptr_t random2 = ~(reinterpret_cast<uintptr_t>(::read) << 16); |
875 #else | 886 #else |
876 #error OS not supported | 887 #error OS not supported |
877 #endif | 888 #endif |
878 | 889 |
879 #if CPU(64BIT) | 890 #if CPU(64BIT) |
880 static_assert(sizeof(uintptr_t) == sizeof(uint64_t), | 891 static_assert(sizeof(uintptr_t) == sizeof(uint64_t), |
881 "uintptr_t is not uint64_t"); | 892 "uintptr_t is not uint64_t"); |
882 const uint32_t random = static_cast<uint32_t>( | 893 const uint32_t random = static_cast<uint32_t>( |
883 (random1 & 0x0FFFFULL) | ((random2 >> 32) & 0x0FFFF0000ULL)); | 894 (random1 & 0x0FFFFULL) | ((random2 >> 32) & 0x0FFFF0000ULL)); |
884 #elif CPU(32BIT) | 895 #elif CPU(32BIT) |
| 896 // Although we don't use heap metadata canaries on 32-bit due to memory |
| 897 // pressure, keep this code around just in case we do, someday. |
885 static_assert(sizeof(uintptr_t) == sizeof(uint32_t), | 898 static_assert(sizeof(uintptr_t) == sizeof(uint32_t), |
886 "uintptr_t is not uint32_t"); | 899 "uintptr_t is not uint32_t"); |
887 const uint32_t random = (random1 & 0x0FFFFUL) | (random2 & 0xFFFF0000UL); | 900 const uint32_t random = (random1 & 0x0FFFFUL) | (random2 & 0xFFFF0000UL); |
888 #else | 901 #else |
889 #error architecture not supported | 902 #error architecture not supported |
890 #endif | 903 #endif |
891 | 904 |
892 return random; | 905 return random; |
893 } | 906 } |
| 907 #endif |
894 | 908 |
895 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::isWrapperHeaderMarked() | 909 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::isWrapperHeaderMarked() |
896 const { | 910 const { |
897 ASSERT(checkHeader()); | 911 ASSERT(checkHeader()); |
898 return m_encoded & headerWrapperMarkBitMask; | 912 return m_encoded & headerWrapperMarkBitMask; |
899 } | 913 } |
900 | 914 |
901 NO_SANITIZE_ADDRESS inline void HeapObjectHeader::markWrapperHeader() { | 915 NO_SANITIZE_ADDRESS inline void HeapObjectHeader::markWrapperHeader() { |
902 ASSERT(checkHeader()); | 916 ASSERT(checkHeader()); |
903 ASSERT(!isWrapperHeaderMarked()); | 917 ASSERT(!isWrapperHeaderMarked()); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 return outOfLineAllocate(allocationSize, gcInfoIndex); | 959 return outOfLineAllocate(allocationSize, gcInfoIndex); |
946 } | 960 } |
947 | 961 |
948 inline NormalPageArena* NormalPage::arenaForNormalPage() const { | 962 inline NormalPageArena* NormalPage::arenaForNormalPage() const { |
949 return static_cast<NormalPageArena*>(arena()); | 963 return static_cast<NormalPageArena*>(arena()); |
950 } | 964 } |
951 | 965 |
952 } // namespace blink | 966 } // namespace blink |
953 | 967 |
954 #endif // HeapPage_h | 968 #endif // HeapPage_h |
OLD | NEW |