OLD | NEW |
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/metrics/persistent_memory_allocator.h" | 5 #include "base/metrics/persistent_memory_allocator.h" |
6 | 6 |
7 #include <assert.h> | 7 #include <assert.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 | 9 |
10 #include "base/files/memory_mapped_file.h" | 10 #include "base/files/memory_mapped_file.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/memory/shared_memory.h" | 12 #include "base/memory/shared_memory.h" |
13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
14 | 14 |
15 namespace { | 15 namespace { |
16 | 16 |
17 // Required range of memory segment sizes. It has to fit in an unsigned 32-bit | 17 // Limit of memory segment size. It has to fit in an unsigned 32-bit number |
18 // number and should be a power of 2 in order to accomodate almost any page | 18 // and should be a power of 2 in order to accomodate almost any page size. |
19 // size. | |
20 const uint32_t kSegmentMinSize = 1 << 10; // 1 KiB | |
21 const uint32_t kSegmentMaxSize = 1 << 30; // 1 GiB | 19 const uint32_t kSegmentMaxSize = 1 << 30; // 1 GiB |
22 | 20 |
23 // A constant (random) value placed in the shared metadata to identify | 21 // A constant (random) value placed in the shared metadata to identify |
24 // an already initialized memory segment. | 22 // an already initialized memory segment. |
25 const uint32_t kGlobalCookie = 0x408305DC; | 23 const uint32_t kGlobalCookie = 0x408305DC; |
26 | 24 |
27 // The current version of the metadata. If updates are made that change | 25 // The current version of the metadata. If updates are made that change |
28 // the metadata, the version number can be queried to operate in a backward- | 26 // the metadata, the version number can be queried to operate in a backward- |
29 // compatible manner until the memory segment is completely re-initalized. | 27 // compatible manner until the memory segment is completely re-initalized. |
30 const uint32_t kGlobalVersion = 1; | 28 const uint32_t kGlobalVersion = 1; |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 } | 230 } |
233 | 231 |
234 | 232 |
235 // static | 233 // static |
236 bool PersistentMemoryAllocator::IsMemoryAcceptable(const void* base, | 234 bool PersistentMemoryAllocator::IsMemoryAcceptable(const void* base, |
237 size_t size, | 235 size_t size, |
238 size_t page_size, | 236 size_t page_size, |
239 bool readonly) { | 237 bool readonly) { |
240 return ((base && reinterpret_cast<uintptr_t>(base) % kAllocAlignment == 0) && | 238 return ((base && reinterpret_cast<uintptr_t>(base) % kAllocAlignment == 0) && |
241 (size >= sizeof(SharedMetadata) && size <= kSegmentMaxSize) && | 239 (size >= sizeof(SharedMetadata) && size <= kSegmentMaxSize) && |
242 (size >= kSegmentMinSize || readonly) && | |
243 (size % kAllocAlignment == 0 || readonly) && | 240 (size % kAllocAlignment == 0 || readonly) && |
244 (page_size == 0 || size % page_size == 0 || readonly)); | 241 (page_size == 0 || size % page_size == 0 || readonly)); |
245 } | 242 } |
246 | 243 |
247 PersistentMemoryAllocator::PersistentMemoryAllocator( | 244 PersistentMemoryAllocator::PersistentMemoryAllocator( |
248 void* base, | 245 void* base, |
249 size_t size, | 246 size_t size, |
250 size_t page_size, | 247 size_t page_size, |
251 uint64_t id, | 248 uint64_t id, |
252 base::StringPiece name, | 249 base::StringPiece name, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 shared_meta()->id != 0 || | 291 shared_meta()->id != 0 || |
295 shared_meta()->name != 0 || | 292 shared_meta()->name != 0 || |
296 shared_meta()->tailptr != 0 || | 293 shared_meta()->tailptr != 0 || |
297 shared_meta()->queue.cookie != 0 || | 294 shared_meta()->queue.cookie != 0 || |
298 shared_meta()->queue.next.load(std::memory_order_relaxed) != 0 || | 295 shared_meta()->queue.next.load(std::memory_order_relaxed) != 0 || |
299 first_block->size != 0 || | 296 first_block->size != 0 || |
300 first_block->cookie != 0 || | 297 first_block->cookie != 0 || |
301 first_block->type_id != 0 || | 298 first_block->type_id != 0 || |
302 first_block->next != 0) { | 299 first_block->next != 0) { |
303 // ...or something malicious has been playing with the metadata. | 300 // ...or something malicious has been playing with the metadata. |
304 NOTREACHED(); | |
305 SetCorrupt(); | 301 SetCorrupt(); |
306 } | 302 } |
307 | 303 |
308 // This is still safe to do even if corruption has been detected. | 304 // This is still safe to do even if corruption has been detected. |
309 shared_meta()->cookie = kGlobalCookie; | 305 shared_meta()->cookie = kGlobalCookie; |
310 shared_meta()->size = mem_size_; | 306 shared_meta()->size = mem_size_; |
311 shared_meta()->page_size = mem_page_; | 307 shared_meta()->page_size = mem_page_; |
312 shared_meta()->version = kGlobalVersion; | 308 shared_meta()->version = kGlobalVersion; |
313 shared_meta()->id = id; | 309 shared_meta()->id = id; |
314 shared_meta()->freeptr.store(sizeof(SharedMetadata), | 310 shared_meta()->freeptr.store(sizeof(SharedMetadata), |
(...skipping 17 matching lines...) Expand all Loading... |
332 if (shared_meta()->size == 0 || | 328 if (shared_meta()->size == 0 || |
333 shared_meta()->version == 0 || | 329 shared_meta()->version == 0 || |
334 shared_meta()->freeptr.load(std::memory_order_relaxed) == 0 || | 330 shared_meta()->freeptr.load(std::memory_order_relaxed) == 0 || |
335 shared_meta()->tailptr == 0 || | 331 shared_meta()->tailptr == 0 || |
336 shared_meta()->queue.cookie == 0 || | 332 shared_meta()->queue.cookie == 0 || |
337 shared_meta()->queue.next.load(std::memory_order_relaxed) == 0) { | 333 shared_meta()->queue.next.load(std::memory_order_relaxed) == 0) { |
338 SetCorrupt(); | 334 SetCorrupt(); |
339 } | 335 } |
340 if (!readonly) { | 336 if (!readonly) { |
341 // The allocator is attaching to a previously initialized segment of | 337 // The allocator is attaching to a previously initialized segment of |
342 // memory. Make sure the embedded data matches what has been passed. | 338 // memory. If the initialization parameters differ, make the best of it |
343 if (shared_meta()->size != mem_size_ || | 339 // by reducing the local construction parameters to match those of |
344 shared_meta()->page_size != mem_page_) { | 340 // the actual memory area. This ensures that the local object never |
345 NOTREACHED(); | 341 // tries to write outside of the original bounds. |
| 342 // Because the fields are const to ensure that no code other than the |
| 343 // constructor makes changes to them as well as to give optimization |
| 344 // hints to the compiler, it's necessary to const-cast them for changes |
| 345 // here. |
| 346 if (shared_meta()->size < mem_size_) |
| 347 *const_cast<uint32_t*>(&mem_size_) = shared_meta()->size; |
| 348 if (shared_meta()->page_size < mem_page_) |
| 349 *const_cast<uint32_t*>(&mem_page_) = shared_meta()->page_size; |
| 350 |
| 351 // Ensure that settings are still valid after the above adjustments. |
| 352 if (!IsMemoryAcceptable(base, mem_size_, mem_page_, readonly)) |
346 SetCorrupt(); | 353 SetCorrupt(); |
347 } | |
348 } | 354 } |
349 } | 355 } |
350 } | 356 } |
351 | 357 |
352 PersistentMemoryAllocator::~PersistentMemoryAllocator() { | 358 PersistentMemoryAllocator::~PersistentMemoryAllocator() { |
353 // It's strictly forbidden to do any memory access here in case there is | 359 // It's strictly forbidden to do any memory access here in case there is |
354 // some issue with the underlying memory segment. The "Local" allocator | 360 // some issue with the underlying memory segment. The "Local" allocator |
355 // makes use of this to allow deletion of the segment on the heap from | 361 // makes use of this to allow deletion of the segment on the heap from |
356 // within its destructor. | 362 // within its destructor. |
357 } | 363 } |
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
737 id, | 743 id, |
738 name, | 744 name, |
739 read_only), | 745 read_only), |
740 shared_memory_(std::move(memory)) {} | 746 shared_memory_(std::move(memory)) {} |
741 | 747 |
742 SharedPersistentMemoryAllocator::~SharedPersistentMemoryAllocator() {} | 748 SharedPersistentMemoryAllocator::~SharedPersistentMemoryAllocator() {} |
743 | 749 |
744 // static | 750 // static |
745 bool SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable( | 751 bool SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable( |
746 const SharedMemory& memory) { | 752 const SharedMemory& memory) { |
747 return IsMemoryAcceptable(memory.memory(), memory.mapped_size(), 0, true); | 753 return IsMemoryAcceptable(memory.memory(), memory.mapped_size(), 0, false); |
748 } | 754 } |
749 | 755 |
750 | 756 |
751 //----- FilePersistentMemoryAllocator ------------------------------------------ | 757 //----- FilePersistentMemoryAllocator ------------------------------------------ |
752 | 758 |
753 FilePersistentMemoryAllocator::FilePersistentMemoryAllocator( | 759 FilePersistentMemoryAllocator::FilePersistentMemoryAllocator( |
754 std::unique_ptr<MemoryMappedFile> file, | 760 std::unique_ptr<MemoryMappedFile> file, |
| 761 size_t max_size, |
755 uint64_t id, | 762 uint64_t id, |
756 base::StringPiece name) | 763 base::StringPiece name, |
| 764 bool read_only) |
757 : PersistentMemoryAllocator(const_cast<uint8_t*>(file->data()), | 765 : PersistentMemoryAllocator(const_cast<uint8_t*>(file->data()), |
758 file->length(), | 766 max_size != 0 ? max_size : file->length(), |
759 0, | 767 0, |
760 id, | 768 id, |
761 name, | 769 name, |
762 true), | 770 read_only), |
763 mapped_file_(std::move(file)) {} | 771 mapped_file_(std::move(file)) {} |
764 | 772 |
765 FilePersistentMemoryAllocator::~FilePersistentMemoryAllocator() {} | 773 FilePersistentMemoryAllocator::~FilePersistentMemoryAllocator() {} |
766 | 774 |
767 // static | 775 // static |
768 bool FilePersistentMemoryAllocator::IsFileAcceptable( | 776 bool FilePersistentMemoryAllocator::IsFileAcceptable( |
769 const MemoryMappedFile& file) { | 777 const MemoryMappedFile& file, |
770 return IsMemoryAcceptable(file.data(), file.length(), 0, true); | 778 bool read_only) { |
| 779 return IsMemoryAcceptable(file.data(), file.length(), 0, read_only); |
771 } | 780 } |
772 | 781 |
773 } // namespace base | 782 } // namespace base |
OLD | NEW |