OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "components/metrics/leak_detector/leak_detector.h" |
| 6 |
| 7 #include <set> |
| 8 |
| 9 #include "base/allocator/allocator_extension.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/macros.h" |
| 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "components/metrics/leak_detector/custom_allocator.h" |
| 14 #include "components/metrics/leak_detector/leak_detector_value_type.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 |
| 17 namespace metrics { |
| 18 |
| 19 namespace { |
| 20 |
| 21 // Observer class that receives leak reports and stores them in |reports_|. |
| 22 // Only one copy of each unique report will be stored. |
| 23 class TestObserver : public LeakDetector::LeakDetector::Observer { |
| 24 public: |
| 25 TestObserver() {} |
| 26 |
| 27 void OnLeakFound(const LeakDetector::LeakReport& report) override { |
| 28 reports_.insert(report); |
| 29 } |
| 30 |
| 31 const std::set<LeakDetector::LeakReport>& reports() const { return reports_; } |
| 32 |
| 33 private: |
| 34 std::set<LeakDetector::LeakReport> reports_; |
| 35 |
| 36 DISALLOW_COPY_AND_ASSIGN(TestObserver); |
| 37 }; |
| 38 |
| 39 // Used by CheckStackFrameInfoAlloc() as a return value. |
| 40 bool g_has_stack_frame_info = false; |
| 41 |
| 42 // Attempt to get a call stack. If the operation returned a positive number of |
| 43 // frames and the first frame is valid, that means the stack frame info is |
| 44 // available. Sets |g_has_stack_frame_info| to indicate whether stack frame info |
| 45 // is available. |
| 46 void CheckStackFrameInfoAlloc(const void* ptr, size_t size) { |
| 47 void* stack[16]; |
| 48 stack[0] = nullptr; |
| 49 int depth = base::allocator::GetCallStack(stack, arraysize(stack), 0); |
| 50 g_has_stack_frame_info = depth > 0 && stack[0]; |
| 51 } |
| 52 |
| 53 // Returns true if stack frame info is available. |
| 54 bool HasStackFrameInfo() { |
| 55 g_has_stack_frame_info = false; |
| 56 // Register the hook function from the above class. |
| 57 auto existing_hook = |
| 58 base::allocator::SetSingleAllocHook(&CheckStackFrameInfoAlloc); |
| 59 |
| 60 // This will invoke the hook. |
| 61 int* dummy = new int; |
| 62 delete dummy; |
| 63 |
| 64 // Restore any existing hook. |
| 65 base::allocator::SetSingleAllocHook(existing_hook); |
| 66 |
| 67 return g_has_stack_frame_info; |
| 68 } |
| 69 |
| 70 } // namespace |
| 71 |
| 72 class LeakDetectorTest : public ::testing::Test { |
| 73 public: |
| 74 LeakDetectorTest() {} |
| 75 |
| 76 void SetUp() override { |
| 77 // Make sure there are no preexisting hooks registered with the allocator. |
| 78 ASSERT_EQ(nullptr, base::allocator::GetSingleAllocHook()); |
| 79 ASSERT_EQ(nullptr, base::allocator::GetSingleFreeHook()); |
| 80 } |
| 81 |
| 82 void TearDown() override { |
| 83 // Make sure any hooks have been removed after LeakDetector is destroyed |
| 84 // after the test. |
| 85 ASSERT_EQ(nullptr, base::allocator::GetSingleAllocHook()); |
| 86 ASSERT_EQ(nullptr, base::allocator::GetSingleFreeHook()); |
| 87 } |
| 88 |
| 89 private: |
| 90 DISALLOW_COPY_AND_ASSIGN(LeakDetectorTest); |
| 91 }; |
| 92 |
| 93 TEST_F(LeakDetectorTest, SingleInstance) { |
| 94 LeakDetector detector; |
| 95 |
| 96 // Make sure some hooks have been set. |
| 97 EXPECT_NE(nullptr, base::allocator::GetSingleAllocHook()); |
| 98 EXPECT_NE(nullptr, base::allocator::GetSingleFreeHook()); |
| 99 } |
| 100 |
| 101 TEST_F(LeakDetectorTest, AddAndRemoveObservers) { |
| 102 LeakDetector detector; |
| 103 TestObserver obs1, obs2, obs3; |
| 104 |
| 105 // There are no registered observers at first. Make sure RemoveObserver() |
| 106 // returns false in this case. |
| 107 EXPECT_FALSE(detector.RemoveObserver(&obs1)); |
| 108 EXPECT_FALSE(detector.RemoveObserver(&obs2)); |
| 109 EXPECT_FALSE(detector.RemoveObserver(&obs3)); |
| 110 |
| 111 // Add observer and then remove it. |
| 112 EXPECT_TRUE(detector.AddObserver(&obs1)); |
| 113 EXPECT_TRUE(detector.RemoveObserver(&obs1)); |
| 114 EXPECT_FALSE(detector.RemoveObserver(&obs1)); |
| 115 |
| 116 // Add all three observers at once, then remove them. |
| 117 EXPECT_TRUE(detector.AddObserver(&obs1)); |
| 118 EXPECT_TRUE(detector.AddObserver(&obs2)); |
| 119 EXPECT_TRUE(detector.AddObserver(&obs3)); |
| 120 |
| 121 EXPECT_TRUE(detector.RemoveObserver(&obs1)); |
| 122 EXPECT_FALSE(detector.RemoveObserver(&obs1)); |
| 123 EXPECT_TRUE(detector.RemoveObserver(&obs2)); |
| 124 EXPECT_FALSE(detector.RemoveObserver(&obs2)); |
| 125 EXPECT_TRUE(detector.RemoveObserver(&obs3)); |
| 126 EXPECT_FALSE(detector.RemoveObserver(&obs3)); |
| 127 } |
| 128 |
| 129 TEST_F(LeakDetectorTest, NotifyObservers) { |
| 130 // Generate two sets of leak reports. |
| 131 std::vector<LeakDetector::LeakReport> reports1(3); |
| 132 reports1[0].alloc_size_bytes = 8; |
| 133 reports1[0].call_stack = {1, 2, 3, 4}; |
| 134 reports1[1].alloc_size_bytes = 16; |
| 135 reports1[1].call_stack = {5, 6, 7, 8}; |
| 136 reports1[2].alloc_size_bytes = 24; |
| 137 reports1[2].call_stack = {9, 10, 11, 12}; |
| 138 |
| 139 std::vector<LeakDetector::LeakReport> reports2(3); |
| 140 reports2[0].alloc_size_bytes = 32; |
| 141 reports2[0].call_stack = {1, 2, 4, 8}; |
| 142 reports2[1].alloc_size_bytes = 40; |
| 143 reports2[1].call_stack = {16, 32, 64, 128}; |
| 144 reports2[2].alloc_size_bytes = 48; |
| 145 reports2[2].call_stack = {256, 512, 1024, 2048}; |
| 146 |
| 147 scoped_ptr<LeakDetector> detector(new LeakDetector); |
| 148 |
| 149 // Register three observers; |
| 150 TestObserver obs1, obs2, obs3; |
| 151 ASSERT_TRUE(detector->AddObserver(&obs1)); |
| 152 ASSERT_TRUE(detector->AddObserver(&obs2)); |
| 153 ASSERT_TRUE(detector->AddObserver(&obs3)); |
| 154 |
| 155 // Pass both sets of reports to the leak detector. |
| 156 detector->NotifyObservers(reports1); |
| 157 detector->NotifyObservers(reports2); |
| 158 |
| 159 // Shut down the leak detector before checking the reports, so that the |
| 160 // stored reports can be examined without new reports being generated. |
| 161 detector.reset(); |
| 162 |
| 163 // Check that all three observers got both sets of reports, passed in |
| 164 // separately. |
| 165 for (const TestObserver* obs : {&obs1, &obs2, &obs3}) { |
| 166 EXPECT_EQ(6U, obs->reports().size()); |
| 167 for (const auto& report : {reports1[0], reports1[1], reports1[2], |
| 168 reports2[0], reports2[1], reports2[2]}) { |
| 169 EXPECT_TRUE(obs->reports().find(report) != obs->reports().end()); |
| 170 } |
| 171 } |
| 172 } |
| 173 |
| 174 TEST_F(LeakDetectorTest, SimpleLeak) { |
| 175 // The leak detector cannot run properly without call stack frame info. |
| 176 if (!HasStackFrameInfo()) { |
| 177 LOG(INFO) << "No stack frame info found, skipping."; |
| 178 return; |
| 179 } |
| 180 |
| 181 // Initialize with a low analysis interval to quickly find some leaks. The |
| 182 // value is chosen to be larger than the number of bytes allocated in one |
| 183 // iteration of the for loop below. |
| 184 scoped_ptr<LeakDetector> detector( |
| 185 new LeakDetector(1.0f, // sampling_factor |
| 186 8, // max_stack_depth |
| 187 1024, // analysis_interval_bytes |
| 188 4, // size_suspicion_threshold |
| 189 4)); // call_stack_suspicion_threshold |
| 190 |
| 191 // Create two observers. |
| 192 TestObserver obs1, obs2; |
| 193 ASSERT_TRUE(detector->AddObserver(&obs1)); |
| 194 ASSERT_TRUE(detector->AddObserver(&obs2)); |
| 195 |
| 196 // Store all allocated pointers here so they can be deleted later. |
| 197 std::vector<scoped_ptr<char[]>> allocated_ptrs; |
| 198 allocated_ptrs.reserve(4096); |
| 199 |
| 200 // The following loop allocates a bunch of memory of various sizes. Sizes 32 |
| 201 // and 48 are the ones with many more allocations, and from multiple call |
| 202 // sites locations. They should trigger leaks. |
| 203 for (int j = 0; j < 100; ++j) { |
| 204 allocated_ptrs.push_back(scoped_ptr<char[]>(new char[16])); |
| 205 allocated_ptrs.push_back(scoped_ptr<char[]>(new char[32])); |
| 206 allocated_ptrs.push_back(scoped_ptr<char[]>(new char[48])); |
| 207 allocated_ptrs.push_back(scoped_ptr<char[]>(new char[16])); |
| 208 for (int i = 0; i < 4; ++i) { |
| 209 allocated_ptrs.push_back(scoped_ptr<char[]>(new char[32])); |
| 210 allocated_ptrs.push_back(scoped_ptr<char[]>(new char[48])); |
| 211 } |
| 212 allocated_ptrs.push_back(scoped_ptr<char[]>(new char[32])); |
| 213 allocated_ptrs.push_back(scoped_ptr<char[]>(new char[24])); |
| 214 allocated_ptrs.push_back(scoped_ptr<char[]>(new char[48])); |
| 215 } |
| 216 // Shut down the leak detector before checking the reports, so that the |
| 217 // stored reports can be examined without new reports being generated. |
| 218 detector.reset(); |
| 219 |
| 220 for (const TestObserver* observer : {&obs1, &obs2}) { |
| 221 // Check that reports were generated for sizes 32 and 48. |
| 222 const auto& reports = observer->reports(); |
| 223 ASSERT_EQ(2U, reports.size()); |
| 224 |
| 225 auto iter = reports.begin(); |
| 226 const LeakDetector::LeakReport& report1 = *iter; |
| 227 EXPECT_EQ(32U, report1.alloc_size_bytes); |
| 228 |
| 229 ++iter; |
| 230 const LeakDetector::LeakReport& report2 = *iter; |
| 231 EXPECT_EQ(48U, report2.alloc_size_bytes); |
| 232 |
| 233 // We don't know what the exact call stacks are, but make sure they are |
| 234 // distinct. |
| 235 EXPECT_NE(report1.call_stack, report2.call_stack); |
| 236 } |
| 237 } |
| 238 |
| 239 } // namespace metrics |
OLD | NEW |