| 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 |