Chromium Code Reviews| 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 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 WTF_EXPORT void partitionPurgeMemory(PartitionRoot*, int); | 404 WTF_EXPORT void partitionPurgeMemory(PartitionRoot*, int); |
| 405 WTF_EXPORT void partitionPurgeMemoryGeneric(PartitionRootGeneric*, int); | 405 WTF_EXPORT void partitionPurgeMemoryGeneric(PartitionRootGeneric*, int); |
| 406 | 406 |
| 407 WTF_EXPORT NEVER_INLINE void* partitionAllocSlowPath(PartitionRootBase*, int, si ze_t, PartitionBucket*); | 407 WTF_EXPORT NEVER_INLINE void* partitionAllocSlowPath(PartitionRootBase*, int, si ze_t, PartitionBucket*); |
| 408 WTF_EXPORT NEVER_INLINE void partitionFreeSlowPath(PartitionPage*); | 408 WTF_EXPORT NEVER_INLINE void partitionFreeSlowPath(PartitionPage*); |
| 409 WTF_EXPORT NEVER_INLINE void* partitionReallocGeneric(PartitionRootGeneric*, voi d*, size_t); | 409 WTF_EXPORT NEVER_INLINE void* partitionReallocGeneric(PartitionRootGeneric*, voi d*, size_t); |
| 410 | 410 |
| 411 WTF_EXPORT void partitionDumpStats(PartitionRoot*, const char* partitionName, bo ol isLightDump, PartitionStatsDumper*); | 411 WTF_EXPORT void partitionDumpStats(PartitionRoot*, const char* partitionName, bo ol isLightDump, PartitionStatsDumper*); |
| 412 WTF_EXPORT void partitionDumpStatsGeneric(PartitionRootGeneric*, const char* par titionName, bool isLightDump, PartitionStatsDumper*); | 412 WTF_EXPORT void partitionDumpStatsGeneric(PartitionRootGeneric*, const char* par titionName, bool isLightDump, PartitionStatsDumper*); |
| 413 | 413 |
| 414 class WTF_EXPORT PartitionAllocHooks { | |
| 415 public: | |
| 416 typedef void AllocationHook(void* address, size_t); | |
| 417 typedef void FreeHook(void* address); | |
| 418 | |
| 419 static void setAllocationHook(AllocationHook* hook) { m_allocationHook = hoo k; } | |
| 420 static void setFreeHook(FreeHook* hook) { m_freeHook = hook; } | |
| 421 | |
| 422 static void allocationHookIfEnabled(void* address, size_t size) | |
| 423 { | |
| 424 AllocationHook* allocationHook = m_allocationHook; | |
| 425 if (UNLIKELY(allocationHook != nullptr)) | |
| 426 allocationHook(address, size); | |
| 427 } | |
| 428 | |
| 429 static void freeHookIfEnabled(void* address) | |
| 430 { | |
| 431 FreeHook* freeHook = m_freeHook; | |
| 432 if (UNLIKELY(freeHook != nullptr)) | |
| 433 freeHook(address); | |
| 434 } | |
| 435 | |
| 436 static void reallocHookIfEnabled(void* oldAddress, void* newAddress, size_t size) | |
| 437 { | |
| 438 // Report a reallocation as a free followed by an allocation. | |
| 439 AllocationHook* allocationHook = m_allocationHook; | |
| 440 FreeHook* freeHook = m_freeHook; | |
| 441 if (UNLIKELY(allocationHook && freeHook)) { | |
| 442 freeHook(oldAddress); | |
| 443 allocationHook(newAddress, size); | |
| 444 } | |
| 445 } | |
| 446 | |
| 447 private: | |
| 448 // Pointers to hook functions that PartitionAlloc will call on allocation an d | |
| 449 // free if the pointers are non-null. | |
| 450 static AllocationHook* m_allocationHook; | |
| 451 static FreeHook* m_freeHook; | |
| 452 }; | |
| 453 | |
| 414 ALWAYS_INLINE PartitionFreelistEntry* partitionFreelistMask(PartitionFreelistEnt ry* ptr) | 454 ALWAYS_INLINE PartitionFreelistEntry* partitionFreelistMask(PartitionFreelistEnt ry* ptr) |
| 415 { | 455 { |
| 416 // We use bswap on little endian as a fast mask for two reasons: | 456 // We use bswap on little endian as a fast mask for two reasons: |
| 417 // 1) If an object is freed and its vtable used where the attacker doesn't | 457 // 1) If an object is freed and its vtable used where the attacker doesn't |
| 418 // get the chance to run allocations between the free and use, the vtable | 458 // get the chance to run allocations between the free and use, the vtable |
| 419 // dereference is likely to fault. | 459 // dereference is likely to fault. |
| 420 // 2) If the attacker has a linear buffer overflow and elects to try and | 460 // 2) If the attacker has a linear buffer overflow and elects to try and |
| 421 // corrupt a freelist pointer, partial pointer overwrite attacks are | 461 // corrupt a freelist pointer, partial pointer overwrite attacks are |
| 422 // thwarted. | 462 // thwarted. |
| 423 // For big endian, similar guarantees are arrived at with a negation. | 463 // For big endian, similar guarantees are arrived at with a negation. |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 622 void* result = malloc(size); | 662 void* result = malloc(size); |
| 623 RELEASE_ASSERT(result); | 663 RELEASE_ASSERT(result); |
| 624 return result; | 664 return result; |
| 625 #else | 665 #else |
| 626 size = partitionCookieSizeAdjustAdd(size); | 666 size = partitionCookieSizeAdjustAdd(size); |
| 627 ASSERT(root->initialized); | 667 ASSERT(root->initialized); |
| 628 size_t index = size >> kBucketShift; | 668 size_t index = size >> kBucketShift; |
| 629 ASSERT(index < root->numBuckets); | 669 ASSERT(index < root->numBuckets); |
| 630 ASSERT(size == index << kBucketShift); | 670 ASSERT(size == index << kBucketShift); |
| 631 PartitionBucket* bucket = &root->buckets()[index]; | 671 PartitionBucket* bucket = &root->buckets()[index]; |
| 632 return partitionBucketAlloc(root, 0, size, bucket); | 672 void* result = partitionBucketAlloc(root, 0, size, bucket); |
| 673 PartitionAllocHooks::allocationHookIfEnabled(result, size); | |
| 674 return result; | |
| 633 #endif // defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 675 #endif // defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 634 } | 676 } |
| 635 | 677 |
| 636 ALWAYS_INLINE void partitionFreeWithPage(void* ptr, PartitionPage* page) | 678 ALWAYS_INLINE void partitionFreeWithPage(void* ptr, PartitionPage* page) |
| 637 { | 679 { |
| 638 // If these asserts fire, you probably corrupted memory. | 680 // If these asserts fire, you probably corrupted memory. |
| 639 #if ENABLE(ASSERT) | 681 #if ENABLE(ASSERT) |
| 640 size_t slotSize = page->bucket->slotSize; | 682 size_t slotSize = page->bucket->slotSize; |
| 641 size_t rawSize = partitionPageGetRawSize(page); | 683 size_t rawSize = partitionPageGetRawSize(page); |
| 642 if (rawSize) | 684 if (rawSize) |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 665 | 707 |
| 666 ALWAYS_INLINE void partitionFree(void* ptr) | 708 ALWAYS_INLINE void partitionFree(void* ptr) |
| 667 { | 709 { |
| 668 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 710 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 669 free(ptr); | 711 free(ptr); |
| 670 #else | 712 #else |
| 671 ptr = partitionCookieFreePointerAdjust(ptr); | 713 ptr = partitionCookieFreePointerAdjust(ptr); |
| 672 ASSERT(partitionPointerIsValid(ptr)); | 714 ASSERT(partitionPointerIsValid(ptr)); |
| 673 PartitionPage* page = partitionPointerToPage(ptr); | 715 PartitionPage* page = partitionPointerToPage(ptr); |
| 674 partitionFreeWithPage(ptr, page); | 716 partitionFreeWithPage(ptr, page); |
| 717 PartitionAllocHooks::freeHookIfEnabled(ptr); | |
|
Jens Widell
2015/10/21 13:56:51
In debug, |ptr| here doesn't match what we called
Ruud van Asseldonk
2015/10/21 15:00:27
The pointers in the allocation hook and free hook
| |
| 675 #endif | 718 #endif |
| 676 } | 719 } |
| 677 | 720 |
| 678 ALWAYS_INLINE PartitionBucket* partitionGenericSizeToBucket(PartitionRootGeneric * root, size_t size) | 721 ALWAYS_INLINE PartitionBucket* partitionGenericSizeToBucket(PartitionRootGeneric * root, size_t size) |
| 679 { | 722 { |
| 680 size_t order = kBitsPerSizet - countLeadingZerosSizet(size); | 723 size_t order = kBitsPerSizet - countLeadingZerosSizet(size); |
| 681 // The order index is simply the next few bits after the most significant bi t. | 724 // The order index is simply the next few bits after the most significant bi t. |
| 682 size_t orderIndex = (size >> root->orderIndexShifts[order]) & (kGenericNumBu cketsPerOrder - 1); | 725 size_t orderIndex = (size >> root->orderIndexShifts[order]) & (kGenericNumBu cketsPerOrder - 1); |
| 683 // And if the remaining bits are non-zero we must bump the bucket up. | 726 // And if the remaining bits are non-zero we must bump the bucket up. |
| 684 size_t subOrderIndex = size & root->orderSubIndexMasks[order]; | 727 size_t subOrderIndex = size & root->orderSubIndexMasks[order]; |
| 685 PartitionBucket* bucket = root->bucketLookups[(order << kGenericNumBucketsPe rOrderBits) + orderIndex + !!subOrderIndex]; | 728 PartitionBucket* bucket = root->bucketLookups[(order << kGenericNumBucketsPe rOrderBits) + orderIndex + !!subOrderIndex]; |
| 686 ASSERT(!bucket->slotSize || bucket->slotSize >= size); | 729 ASSERT(!bucket->slotSize || bucket->slotSize >= size); |
| 687 ASSERT(!(bucket->slotSize % kGenericSmallestBucket)); | 730 ASSERT(!(bucket->slotSize % kGenericSmallestBucket)); |
| 688 return bucket; | 731 return bucket; |
| 689 } | 732 } |
| 690 | 733 |
| 691 ALWAYS_INLINE void* partitionAllocGenericFlags(PartitionRootGeneric* root, int f lags, size_t size) | 734 ALWAYS_INLINE void* partitionAllocGenericFlags(PartitionRootGeneric* root, int f lags, size_t size) |
| 692 { | 735 { |
| 693 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 736 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 694 void* result = malloc(size); | 737 void* result = malloc(size); |
| 695 RELEASE_ASSERT(result); | 738 RELEASE_ASSERT(result); |
| 696 return result; | 739 return result; |
| 697 #else | 740 #else |
| 698 ASSERT(root->initialized); | 741 ASSERT(root->initialized); |
| 699 size = partitionCookieSizeAdjustAdd(size); | 742 size = partitionCookieSizeAdjustAdd(size); |
| 700 PartitionBucket* bucket = partitionGenericSizeToBucket(root, size); | 743 PartitionBucket* bucket = partitionGenericSizeToBucket(root, size); |
| 701 spinLockLock(&root->lock); | 744 spinLockLock(&root->lock); |
| 702 void* ret = partitionBucketAlloc(root, flags, size, bucket); | 745 void* ret = partitionBucketAlloc(root, flags, size, bucket); |
| 703 spinLockUnlock(&root->lock); | 746 spinLockUnlock(&root->lock); |
| 747 PartitionAllocHooks::allocationHookIfEnabled(ret, size); | |
|
Jens Widell
2015/10/21 13:56:51
Note that |size| here isn't necessarily the size o
Ruud van Asseldonk
2015/10/21 15:00:27
Good point. I want to record the requested size. I
| |
| 704 return ret; | 748 return ret; |
| 705 #endif | 749 #endif |
| 706 } | 750 } |
| 707 | 751 |
| 708 ALWAYS_INLINE void* partitionAllocGeneric(PartitionRootGeneric* root, size_t siz e) | 752 ALWAYS_INLINE void* partitionAllocGeneric(PartitionRootGeneric* root, size_t siz e) |
| 709 { | 753 { |
| 710 return partitionAllocGenericFlags(root, 0, size); | 754 return partitionAllocGenericFlags(root, 0, size); |
| 711 } | 755 } |
| 712 | 756 |
| 713 ALWAYS_INLINE void partitionFreeGeneric(PartitionRootGeneric* root, void* ptr) | 757 ALWAYS_INLINE void partitionFreeGeneric(PartitionRootGeneric* root, void* ptr) |
| 714 { | 758 { |
| 715 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 759 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 716 free(ptr); | 760 free(ptr); |
| 717 #else | 761 #else |
| 718 ASSERT(root->initialized); | 762 ASSERT(root->initialized); |
| 719 | 763 |
| 720 if (UNLIKELY(!ptr)) | 764 if (UNLIKELY(!ptr)) |
| 721 return; | 765 return; |
| 722 | 766 |
| 723 ptr = partitionCookieFreePointerAdjust(ptr); | 767 ptr = partitionCookieFreePointerAdjust(ptr); |
| 724 ASSERT(partitionPointerIsValid(ptr)); | 768 ASSERT(partitionPointerIsValid(ptr)); |
| 725 PartitionPage* page = partitionPointerToPage(ptr); | 769 PartitionPage* page = partitionPointerToPage(ptr); |
| 726 spinLockLock(&root->lock); | 770 spinLockLock(&root->lock); |
| 727 partitionFreeWithPage(ptr, page); | 771 partitionFreeWithPage(ptr, page); |
| 728 spinLockUnlock(&root->lock); | 772 spinLockUnlock(&root->lock); |
| 773 PartitionAllocHooks::freeHookIfEnabled(ptr); | |
|
Jens Widell
2015/10/21 13:56:51
Same kCookieSize adjustment issue here.
Ruud van Asseldonk
2015/10/21 15:00:27
Fixed.
| |
| 729 #endif | 774 #endif |
| 730 } | 775 } |
| 731 | 776 |
| 732 ALWAYS_INLINE size_t partitionDirectMapSize(size_t size) | 777 ALWAYS_INLINE size_t partitionDirectMapSize(size_t size) |
| 733 { | 778 { |
| 734 // Caller must check that the size is not above the kGenericMaxDirectMapped | 779 // Caller must check that the size is not above the kGenericMaxDirectMapped |
| 735 // limit before calling. This also guards against integer overflow in the | 780 // limit before calling. This also guards against integer overflow in the |
| 736 // calculation here. | 781 // calculation here. |
| 737 ASSERT(size <= kGenericMaxDirectMapped); | 782 ASSERT(size <= kGenericMaxDirectMapped); |
| 738 return (size + kSystemPageOffsetMask) & kSystemPageBaseMask; | 783 return (size + kSystemPageOffsetMask) & kSystemPageBaseMask; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 814 using WTF::partitionAlloc; | 859 using WTF::partitionAlloc; |
| 815 using WTF::partitionFree; | 860 using WTF::partitionFree; |
| 816 using WTF::partitionAllocGeneric; | 861 using WTF::partitionAllocGeneric; |
| 817 using WTF::partitionFreeGeneric; | 862 using WTF::partitionFreeGeneric; |
| 818 using WTF::partitionReallocGeneric; | 863 using WTF::partitionReallocGeneric; |
| 819 using WTF::partitionAllocActualSize; | 864 using WTF::partitionAllocActualSize; |
| 820 using WTF::partitionAllocSupportsGetSize; | 865 using WTF::partitionAllocSupportsGetSize; |
| 821 using WTF::partitionAllocGetSize; | 866 using WTF::partitionAllocGetSize; |
| 822 | 867 |
| 823 #endif // WTF_PartitionAlloc_h | 868 #endif // WTF_PartitionAlloc_h |
| OLD | NEW |