| OLD | NEW |
| 1 // Copyright 2014 Google Inc. All Rights Reserved. | 1 // Copyright 2014 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 private: | 207 private: |
| 208 DISALLOW_COPY_AND_ASSIGN(TestZebraBlockHeap); | 208 DISALLOW_COPY_AND_ASSIGN(TestZebraBlockHeap); |
| 209 }; | 209 }; |
| 210 | 210 |
| 211 // A derived class to expose protected members for unit-testing. | 211 // A derived class to expose protected members for unit-testing. |
| 212 class TestBlockHeapManager : public BlockHeapManager { | 212 class TestBlockHeapManager : public BlockHeapManager { |
| 213 public: | 213 public: |
| 214 using BlockHeapManager::HeapQuarantinePair; | 214 using BlockHeapManager::HeapQuarantinePair; |
| 215 | 215 |
| 216 using BlockHeapManager::FreePotentiallyCorruptBlock; | 216 using BlockHeapManager::FreePotentiallyCorruptBlock; |
| 217 using BlockHeapManager::GetCorruptBlockHeapId; |
| 217 using BlockHeapManager::GetHeapId; | 218 using BlockHeapManager::GetHeapId; |
| 218 using BlockHeapManager::GetHeapFromId; | 219 using BlockHeapManager::GetHeapFromId; |
| 219 using BlockHeapManager::GetHeapTypeUnlocked; | 220 using BlockHeapManager::GetHeapTypeUnlocked; |
| 220 using BlockHeapManager::GetQuarantineFromId; | 221 using BlockHeapManager::GetQuarantineFromId; |
| 221 using BlockHeapManager::HeapMetadata; | 222 using BlockHeapManager::HeapMetadata; |
| 222 using BlockHeapManager::HeapQuarantineMap; | 223 using BlockHeapManager::HeapQuarantineMap; |
| 223 using BlockHeapManager::IsValidHeapIdUnlocked; | 224 using BlockHeapManager::IsValidHeapIdUnlocked; |
| 224 using BlockHeapManager::SetHeapErrorCallback; | 225 using BlockHeapManager::SetHeapErrorCallback; |
| 225 using BlockHeapManager::ShardedBlockQuarantine; | 226 using BlockHeapManager::ShardedBlockQuarantine; |
| 226 using BlockHeapManager::TrimQuarantine; | 227 using BlockHeapManager::TrimQuarantine; |
| 227 | 228 |
| 228 using BlockHeapManager::allocation_filter_flag_tls_; | 229 using BlockHeapManager::allocation_filter_flag_tls_; |
| 230 using BlockHeapManager::corrupt_block_registry_cache_; |
| 231 using BlockHeapManager::enable_page_protections_; |
| 229 using BlockHeapManager::heaps_; | 232 using BlockHeapManager::heaps_; |
| 230 using BlockHeapManager::large_block_heap_id_; | 233 using BlockHeapManager::large_block_heap_id_; |
| 231 using BlockHeapManager::locked_heaps_; | 234 using BlockHeapManager::locked_heaps_; |
| 232 using BlockHeapManager::parameters_; | 235 using BlockHeapManager::parameters_; |
| 236 using BlockHeapManager::shadow_; |
| 233 using BlockHeapManager::shared_quarantine_; | 237 using BlockHeapManager::shared_quarantine_; |
| 234 using BlockHeapManager::zebra_block_heap_; | 238 using BlockHeapManager::zebra_block_heap_; |
| 235 using BlockHeapManager::zebra_block_heap_id_; | 239 using BlockHeapManager::zebra_block_heap_id_; |
| 236 | 240 |
| 237 // A derived class to expose protected members for unit-testing. This has to | 241 // A derived class to expose protected members for unit-testing. This has to |
| 238 // be nested into this one because ShardedBlockQuarantine accesses some | 242 // be nested into this one because ShardedBlockQuarantine accesses some |
| 239 // protected fields of BlockHeapManager. | 243 // protected fields of BlockHeapManager. |
| 240 // | 244 // |
| 241 // This class should only expose some members or expose new functions, no new | 245 // This class should only expose some members or expose new functions, no new |
| 242 // member should be added. | 246 // member should be added. |
| (...skipping 1511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1754 current_size = heap_manager_->shared_quarantine_.GetSizeForTesting(); | 1758 current_size = heap_manager_->shared_quarantine_.GetSizeForTesting(); |
| 1755 EXPECT_EQ(GREEN, | 1759 EXPECT_EQ(GREEN, |
| 1756 heap_manager_->shared_quarantine_.GetQuarantineColor(current_size)); | 1760 heap_manager_->shared_quarantine_.GetQuarantineColor(current_size)); |
| 1757 | 1761 |
| 1758 heap_manager_->DisableDeferredFreeThread(); | 1762 heap_manager_->DisableDeferredFreeThread(); |
| 1759 EXPECT_FALSE(heap_manager_->IsDeferredFreeThreadRunning()); | 1763 EXPECT_FALSE(heap_manager_->IsDeferredFreeThreadRunning()); |
| 1760 } | 1764 } |
| 1761 | 1765 |
| 1762 namespace { | 1766 namespace { |
| 1763 | 1767 |
| 1764 bool ShadowIsConsistentPostAlloc( | 1768 // Helper function for extracting the two default heaps. |
| 1765 Shadow* shadow, const void* alloc, size_t size) { | 1769 void GetHeapIds(TestBlockHeapManager* heap_manager, |
| 1766 uintptr_t index = reinterpret_cast<uintptr_t>(alloc); | 1770 HeapId* large_block_heap, |
| 1767 index >>= kShadowRatioLog; | 1771 HeapId* win_heap) { |
| 1768 uintptr_t index_end = index + (size >> kShadowRatioLog); | 1772 ASSERT_TRUE(heap_manager); |
| 1769 for (size_t i = index; i < index_end; ++i) { | 1773 ASSERT_TRUE(large_block_heap); |
| 1770 if (shadow->shadow()[i] != ShadowMarker::kHeapAddressableMarker) | 1774 ASSERT_TRUE(win_heap); |
| 1771 return false; | 1775 ASSERT_EQ(2u, heap_manager->heaps_.size()); |
| 1772 } | |
| 1773 return true; | |
| 1774 } | |
| 1775 | 1776 |
| 1776 bool ShadowIsConsistentPostFree( | 1777 *large_block_heap = 0; |
| 1777 Shadow* shadow, const void* alloc, size_t size) { | 1778 *win_heap = 0; |
| 1778 DCHECK_NE(static_cast<Shadow*>(nullptr), shadow); | |
| 1779 uintptr_t index = reinterpret_cast<uintptr_t>(alloc); | |
| 1780 index >>= kShadowRatioLog; | |
| 1781 uintptr_t index_end = index + (size >> kShadowRatioLog); | |
| 1782 | 1779 |
| 1783 uint8_t m = shadow->shadow()[index]; | 1780 for (auto h = heap_manager->heaps_.begin(); |
| 1784 if (m != ShadowMarker::kHeapAddressableMarker && | 1781 h != heap_manager->heaps_.end(); ++h) { |
| 1785 m != ShadowMarker::kAsanReservedMarker && | 1782 HeapId heap_id = heap_manager->GetHeapId(h); |
| 1786 m != ShadowMarker::kHeapFreedMarker) { | 1783 if (h->first->GetHeapType() == kWinHeap) { |
| 1787 return false; | 1784 *win_heap = heap_id; |
| 1785 } else { |
| 1786 ASSERT_EQ(kLargeBlockHeap, h->first->GetHeapType()); |
| 1787 *large_block_heap = heap_id; |
| 1788 } |
| 1788 } | 1789 } |
| 1789 | 1790 |
| 1790 // We expect green memory only for large allocations which are directly | 1791 ASSERT_NE(0u, *large_block_heap); |
| 1791 // mapped. Small allocations should be returned to a common pool and | 1792 ASSERT_NE(0u, *win_heap); |
| 1792 // marked as reserved.CtMalloc heap. | |
| 1793 if (m == ShadowMarker::kHeapAddressableMarker && size < 1 * 1024 * 1024) | |
| 1794 return false; | |
| 1795 | |
| 1796 for (size_t i = index; i < index_end; ++i) { | |
| 1797 if (shadow->shadow()[index] != m) | |
| 1798 return false; | |
| 1799 } | |
| 1800 return true; | |
| 1801 } | 1793 } |
| 1802 | 1794 |
| 1803 class BlockHeapManagerIntegrationTest : public testing::Test { | |
| 1804 public: | |
| 1805 BlockHeapManagerIntegrationTest() | |
| 1806 : shadow_() { | |
| 1807 } | |
| 1808 | |
| 1809 void SetUp() override { | |
| 1810 shadow_.SetUp(); | |
| 1811 ASSERT_TRUE(shadow_.IsClean()); | |
| 1812 } | |
| 1813 | |
| 1814 void TearDown() override { | |
| 1815 ASSERT_TRUE(shadow_.IsClean()); | |
| 1816 shadow_.TearDown(); | |
| 1817 } | |
| 1818 | |
| 1819 testing::DebugShadow shadow_; | |
| 1820 }; | |
| 1821 | |
| 1822 } // namespace | 1795 } // namespace |
| 1823 | 1796 |
| 1797 TEST_F(BlockHeapManagerTest, GetCorruptBlockHeapIdTrailerIsGood) { |
| 1798 // Disable page protections so that the LBH allocated block can be |
| 1799 // accessed. |
| 1800 heap_manager_->enable_page_protections_ = false; |
| 1801 |
| 1802 HeapId lbh = 0; |
| 1803 HeapId wh = 0; |
| 1804 GetHeapIds(heap_manager_, &lbh, &wh); |
| 1805 |
| 1806 // Create a second win heap. This means that there are multiple heaps |
| 1807 // not supporting IsAllocated. |
| 1808 heap_manager_->CreateHeap(); |
| 1809 |
| 1810 void* alloc = heap_manager_->Allocate(lbh, 64 * 4096); |
| 1811 BlockInfo bi = {}; |
| 1812 GetBlockInfo( |
| 1813 heap_manager_->shadow_, reinterpret_cast<BlockBody*>(alloc), &bi); |
| 1814 |
| 1815 // Test that the heap ID is correctly returned even in one of many |
| 1816 // non-reporting heaps, given that the correct heap id is actually in the |
| 1817 // trailer. |
| 1818 EXPECT_EQ(lbh, heap_manager_->GetCorruptBlockHeapId(&bi)); |
| 1819 } |
| 1820 |
| 1821 TEST_F(BlockHeapManagerTest, GetCorruptBlockHeapIdInReportingHeap) { |
| 1822 // Disable page protections so that the LBH allocated block can be |
| 1823 // accessed. |
| 1824 heap_manager_->enable_page_protections_ = false; |
| 1825 |
| 1826 HeapId lbh = 0; |
| 1827 HeapId wh = 0; |
| 1828 GetHeapIds(heap_manager_, &lbh, &wh); |
| 1829 |
| 1830 // Create a second win heap. This means that there are multiple heaps |
| 1831 // not supporting IsAllocated. |
| 1832 heap_manager_->CreateHeap(); |
| 1833 |
| 1834 void* alloc = heap_manager_->Allocate(lbh, 32); |
| 1835 BlockInfo bi = {}; |
| 1836 GetBlockInfo( |
| 1837 heap_manager_->shadow_, reinterpret_cast<BlockBody*>(alloc), &bi); |
| 1838 bi.trailer->heap_id = 0; |
| 1839 |
| 1840 // Test the the correct heap is found, even though there are multiple |
| 1841 // non-reporting heaps and the trailer is corrupt. |
| 1842 EXPECT_EQ(lbh, heap_manager_->GetCorruptBlockHeapId(&bi)); |
| 1843 } |
| 1844 |
| 1845 TEST_F(BlockHeapManagerTest, GetCorruptBlockHeapIdInSingleNonReportingHeap) { |
| 1846 HeapId lbh = 0; |
| 1847 HeapId wh = 0; |
| 1848 GetHeapIds(heap_manager_, &lbh, &wh); |
| 1849 |
| 1850 void* alloc = heap_manager_->Allocate(wh, 32); |
| 1851 BlockInfo bi = {}; |
| 1852 GetBlockInfo( |
| 1853 heap_manager_->shadow_, reinterpret_cast<BlockBody*>(alloc), &bi); |
| 1854 bi.trailer->heap_id = 0; |
| 1855 |
| 1856 // Test the the correct heap is found, even though its a non-reporting heap |
| 1857 // and the trailer is corrupt. |
| 1858 EXPECT_EQ(wh, heap_manager_->GetCorruptBlockHeapId(&bi)); |
| 1859 } |
| 1860 |
| 1861 TEST_F(BlockHeapManagerTest, GetCorruptBlockHeapIdNotFound) { |
| 1862 HeapId lbh = 0; |
| 1863 HeapId wh = 0; |
| 1864 GetHeapIds(heap_manager_, &lbh, &wh); |
| 1865 |
| 1866 // Create a second win heap. This means that there are multiple heaps |
| 1867 // not supporting IsAllocated. |
| 1868 heap_manager_->CreateHeap(); |
| 1869 |
| 1870 void* alloc = heap_manager_->Allocate(wh, 32); |
| 1871 BlockInfo bi = {}; |
| 1872 GetBlockInfo( |
| 1873 heap_manager_->shadow_, reinterpret_cast<BlockBody*>(alloc), &bi); |
| 1874 bi.trailer->heap_id = 0; |
| 1875 |
| 1876 // Expect this to fail, as there are multiple non-reporting heaps and |
| 1877 // the block trailer is corrupt. |
| 1878 EXPECT_EQ(0u, heap_manager_->GetCorruptBlockHeapId(&bi)); |
| 1879 } |
| 1880 |
| 1881 TEST_F(BlockHeapManagerTest, FreeCorruptedBlockWorks) { |
| 1882 // Enable to registry filter. |
| 1883 heap_manager_->parameters_.prevent_duplicate_corruption_crashes = true; |
| 1884 |
| 1885 HeapId lbh = 0; |
| 1886 HeapId wh = 0; |
| 1887 GetHeapIds(heap_manager_, &lbh, &wh); |
| 1888 |
| 1889 void* alloc = heap_manager_->Allocate(wh, 32); |
| 1890 BlockInfo bi = {}; |
| 1891 GetBlockInfo( |
| 1892 heap_manager_->shadow_, reinterpret_cast<BlockBody*>(alloc), &bi); |
| 1893 |
| 1894 // Add the stack ID to the registry cache, so that it will decide not |
| 1895 // to crash upon freeing. |
| 1896 heap_manager_->corrupt_block_registry_cache_->AddOrUpdateStackId( |
| 1897 bi.header->alloc_stack->relative_stack_id()); |
| 1898 |
| 1899 // Clear the heap ID and delete the block, expecting this to succeed. |
| 1900 bi.trailer->heap_id = 0; |
| 1901 EXPECT_TRUE(heap_manager_->Free(wh, alloc)); |
| 1902 } |
| 1903 |
| 1824 } // namespace heap_managers | 1904 } // namespace heap_managers |
| 1825 } // namespace asan | 1905 } // namespace asan |
| 1826 } // namespace agent | 1906 } // namespace agent |
| OLD | NEW |