| 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 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 return ret; | 656 return ret; |
| 617 } | 657 } |
| 618 | 658 |
| 619 ALWAYS_INLINE void* partitionAlloc(PartitionRoot* root, size_t size) | 659 ALWAYS_INLINE void* partitionAlloc(PartitionRoot* root, size_t size) |
| 620 { | 660 { |
| 621 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 661 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 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 |
| 666 size_t requestedSize = size; |
| 626 size = partitionCookieSizeAdjustAdd(size); | 667 size = partitionCookieSizeAdjustAdd(size); |
| 627 ASSERT(root->initialized); | 668 ASSERT(root->initialized); |
| 628 size_t index = size >> kBucketShift; | 669 size_t index = size >> kBucketShift; |
| 629 ASSERT(index < root->numBuckets); | 670 ASSERT(index < root->numBuckets); |
| 630 ASSERT(size == index << kBucketShift); | 671 ASSERT(size == index << kBucketShift); |
| 631 PartitionBucket* bucket = &root->buckets()[index]; | 672 PartitionBucket* bucket = &root->buckets()[index]; |
| 632 return partitionBucketAlloc(root, 0, size, bucket); | 673 void* result = partitionBucketAlloc(root, 0, size, bucket); |
| 674 PartitionAllocHooks::allocationHookIfEnabled(result, requestedSize); |
| 675 return result; |
| 633 #endif // defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 676 #endif // defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 634 } | 677 } |
| 635 | 678 |
| 636 ALWAYS_INLINE void partitionFreeWithPage(void* ptr, PartitionPage* page) | 679 ALWAYS_INLINE void partitionFreeWithPage(void* ptr, PartitionPage* page) |
| 637 { | 680 { |
| 638 // If these asserts fire, you probably corrupted memory. | 681 // If these asserts fire, you probably corrupted memory. |
| 639 #if ENABLE(ASSERT) | 682 #if ENABLE(ASSERT) |
| 640 size_t slotSize = page->bucket->slotSize; | 683 size_t slotSize = page->bucket->slotSize; |
| 641 size_t rawSize = partitionPageGetRawSize(page); | 684 size_t rawSize = partitionPageGetRawSize(page); |
| 642 if (rawSize) | 685 if (rawSize) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 661 // correctly update the size metadata. | 704 // correctly update the size metadata. |
| 662 ASSERT(partitionPageGetRawSize(page) == 0); | 705 ASSERT(partitionPageGetRawSize(page) == 0); |
| 663 } | 706 } |
| 664 } | 707 } |
| 665 | 708 |
| 666 ALWAYS_INLINE void partitionFree(void* ptr) | 709 ALWAYS_INLINE void partitionFree(void* ptr) |
| 667 { | 710 { |
| 668 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 711 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 669 free(ptr); | 712 free(ptr); |
| 670 #else | 713 #else |
| 714 PartitionAllocHooks::freeHookIfEnabled(ptr); |
| 671 ptr = partitionCookieFreePointerAdjust(ptr); | 715 ptr = partitionCookieFreePointerAdjust(ptr); |
| 672 ASSERT(partitionPointerIsValid(ptr)); | 716 ASSERT(partitionPointerIsValid(ptr)); |
| 673 PartitionPage* page = partitionPointerToPage(ptr); | 717 PartitionPage* page = partitionPointerToPage(ptr); |
| 674 partitionFreeWithPage(ptr, page); | 718 partitionFreeWithPage(ptr, page); |
| 675 #endif | 719 #endif |
| 676 } | 720 } |
| 677 | 721 |
| 678 ALWAYS_INLINE PartitionBucket* partitionGenericSizeToBucket(PartitionRootGeneric
* root, size_t size) | 722 ALWAYS_INLINE PartitionBucket* partitionGenericSizeToBucket(PartitionRootGeneric
* root, size_t size) |
| 679 { | 723 { |
| 680 size_t order = kBitsPerSizet - countLeadingZerosSizet(size); | 724 size_t order = kBitsPerSizet - countLeadingZerosSizet(size); |
| 681 // The order index is simply the next few bits after the most significant bi
t. | 725 // 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); | 726 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. | 727 // And if the remaining bits are non-zero we must bump the bucket up. |
| 684 size_t subOrderIndex = size & root->orderSubIndexMasks[order]; | 728 size_t subOrderIndex = size & root->orderSubIndexMasks[order]; |
| 685 PartitionBucket* bucket = root->bucketLookups[(order << kGenericNumBucketsPe
rOrderBits) + orderIndex + !!subOrderIndex]; | 729 PartitionBucket* bucket = root->bucketLookups[(order << kGenericNumBucketsPe
rOrderBits) + orderIndex + !!subOrderIndex]; |
| 686 ASSERT(!bucket->slotSize || bucket->slotSize >= size); | 730 ASSERT(!bucket->slotSize || bucket->slotSize >= size); |
| 687 ASSERT(!(bucket->slotSize % kGenericSmallestBucket)); | 731 ASSERT(!(bucket->slotSize % kGenericSmallestBucket)); |
| 688 return bucket; | 732 return bucket; |
| 689 } | 733 } |
| 690 | 734 |
| 691 ALWAYS_INLINE void* partitionAllocGenericFlags(PartitionRootGeneric* root, int f
lags, size_t size) | 735 ALWAYS_INLINE void* partitionAllocGenericFlags(PartitionRootGeneric* root, int f
lags, size_t size) |
| 692 { | 736 { |
| 693 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 737 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 694 void* result = malloc(size); | 738 void* result = malloc(size); |
| 695 RELEASE_ASSERT(result); | 739 RELEASE_ASSERT(result); |
| 696 return result; | 740 return result; |
| 697 #else | 741 #else |
| 698 ASSERT(root->initialized); | 742 ASSERT(root->initialized); |
| 743 size_t requestedSize = size; |
| 699 size = partitionCookieSizeAdjustAdd(size); | 744 size = partitionCookieSizeAdjustAdd(size); |
| 700 PartitionBucket* bucket = partitionGenericSizeToBucket(root, size); | 745 PartitionBucket* bucket = partitionGenericSizeToBucket(root, size); |
| 701 spinLockLock(&root->lock); | 746 spinLockLock(&root->lock); |
| 702 void* ret = partitionBucketAlloc(root, flags, size, bucket); | 747 void* ret = partitionBucketAlloc(root, flags, size, bucket); |
| 703 spinLockUnlock(&root->lock); | 748 spinLockUnlock(&root->lock); |
| 749 PartitionAllocHooks::allocationHookIfEnabled(ret, requestedSize); |
| 704 return ret; | 750 return ret; |
| 705 #endif | 751 #endif |
| 706 } | 752 } |
| 707 | 753 |
| 708 ALWAYS_INLINE void* partitionAllocGeneric(PartitionRootGeneric* root, size_t siz
e) | 754 ALWAYS_INLINE void* partitionAllocGeneric(PartitionRootGeneric* root, size_t siz
e) |
| 709 { | 755 { |
| 710 return partitionAllocGenericFlags(root, 0, size); | 756 return partitionAllocGenericFlags(root, 0, size); |
| 711 } | 757 } |
| 712 | 758 |
| 713 ALWAYS_INLINE void partitionFreeGeneric(PartitionRootGeneric* root, void* ptr) | 759 ALWAYS_INLINE void partitionFreeGeneric(PartitionRootGeneric* root, void* ptr) |
| 714 { | 760 { |
| 715 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 761 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 716 free(ptr); | 762 free(ptr); |
| 717 #else | 763 #else |
| 718 ASSERT(root->initialized); | 764 ASSERT(root->initialized); |
| 719 | 765 |
| 720 if (UNLIKELY(!ptr)) | 766 if (UNLIKELY(!ptr)) |
| 721 return; | 767 return; |
| 722 | 768 |
| 769 PartitionAllocHooks::freeHookIfEnabled(ptr); |
| 723 ptr = partitionCookieFreePointerAdjust(ptr); | 770 ptr = partitionCookieFreePointerAdjust(ptr); |
| 724 ASSERT(partitionPointerIsValid(ptr)); | 771 ASSERT(partitionPointerIsValid(ptr)); |
| 725 PartitionPage* page = partitionPointerToPage(ptr); | 772 PartitionPage* page = partitionPointerToPage(ptr); |
| 726 spinLockLock(&root->lock); | 773 spinLockLock(&root->lock); |
| 727 partitionFreeWithPage(ptr, page); | 774 partitionFreeWithPage(ptr, page); |
| 728 spinLockUnlock(&root->lock); | 775 spinLockUnlock(&root->lock); |
| 729 #endif | 776 #endif |
| 730 } | 777 } |
| 731 | 778 |
| 732 ALWAYS_INLINE size_t partitionDirectMapSize(size_t size) | 779 ALWAYS_INLINE size_t partitionDirectMapSize(size_t size) |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 814 using WTF::partitionAlloc; | 861 using WTF::partitionAlloc; |
| 815 using WTF::partitionFree; | 862 using WTF::partitionFree; |
| 816 using WTF::partitionAllocGeneric; | 863 using WTF::partitionAllocGeneric; |
| 817 using WTF::partitionFreeGeneric; | 864 using WTF::partitionFreeGeneric; |
| 818 using WTF::partitionReallocGeneric; | 865 using WTF::partitionReallocGeneric; |
| 819 using WTF::partitionAllocActualSize; | 866 using WTF::partitionAllocActualSize; |
| 820 using WTF::partitionAllocSupportsGetSize; | 867 using WTF::partitionAllocSupportsGetSize; |
| 821 using WTF::partitionAllocGetSize; | 868 using WTF::partitionAllocGetSize; |
| 822 | 869 |
| 823 #endif // WTF_PartitionAlloc_h | 870 #endif // WTF_PartitionAlloc_h |
| OLD | NEW |