| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 #define _CRT_SECURE_NO_WARNINGS | |
| 6 | |
| 7 #include "base/process/memory.h" | |
| 8 | |
| 9 #include <limits> | |
| 10 | |
| 11 #include "base/compiler_specific.h" | |
| 12 #include "base/debug/alias.h" | |
| 13 #include "base/strings/stringprintf.h" | |
| 14 #include "testing/gtest/include/gtest/gtest.h" | |
| 15 | |
| 16 #if defined(OS_WIN) | |
| 17 #include <windows.h> | |
| 18 #endif | |
| 19 #if defined(OS_POSIX) | |
| 20 #include <errno.h> | |
| 21 #endif | |
| 22 #if defined(OS_MACOSX) | |
| 23 #include <malloc/malloc.h> | |
| 24 #include "base/mac/mac_util.h" | |
| 25 #include "base/process/memory_unittest_mac.h" | |
| 26 #endif | |
| 27 #if defined(OS_LINUX) | |
| 28 #include <malloc.h> | |
| 29 #include "base/test/malloc_wrapper.h" | |
| 30 #endif | |
| 31 | |
| 32 #if defined(OS_WIN) | |
| 33 // HeapQueryInformation function pointer. | |
| 34 typedef BOOL (WINAPI* HeapQueryFn) \ | |
| 35 (HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); | |
| 36 | |
| 37 const int kConstantInModule = 42; | |
| 38 | |
| 39 TEST(ProcessMemoryTest, GetModuleFromAddress) { | |
| 40 // Since the unit tests are their own EXE, this should be | |
| 41 // equivalent to the EXE's HINSTANCE. | |
| 42 // | |
| 43 // kConstantInModule is a constant in this file and | |
| 44 // therefore within the unit test EXE. | |
| 45 EXPECT_EQ(::GetModuleHandle(NULL), | |
| 46 base::GetModuleFromAddress( | |
| 47 const_cast<int*>(&kConstantInModule))); | |
| 48 | |
| 49 // Any address within the kernel32 module should return | |
| 50 // kernel32's HMODULE. Our only assumption here is that | |
| 51 // kernel32 is larger than 4 bytes. | |
| 52 HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll"); | |
| 53 HMODULE kernel32_from_address = | |
| 54 base::GetModuleFromAddress(reinterpret_cast<DWORD*>(kernel32) + 1); | |
| 55 EXPECT_EQ(kernel32, kernel32_from_address); | |
| 56 } | |
| 57 | |
| 58 TEST(ProcessMemoryTest, EnableLFH) { | |
| 59 ASSERT_TRUE(base::EnableLowFragmentationHeap()); | |
| 60 if (IsDebuggerPresent()) { | |
| 61 // Under these conditions, LFH can't be enabled. There's no point to test | |
| 62 // anything. | |
| 63 const char* no_debug_env = getenv("_NO_DEBUG_HEAP"); | |
| 64 if (!no_debug_env || strcmp(no_debug_env, "1")) | |
| 65 return; | |
| 66 } | |
| 67 HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); | |
| 68 ASSERT_TRUE(kernel32 != NULL); | |
| 69 HeapQueryFn heap_query = reinterpret_cast<HeapQueryFn>(GetProcAddress( | |
| 70 kernel32, | |
| 71 "HeapQueryInformation")); | |
| 72 | |
| 73 // On Windows 2000, the function is not exported. This is not a reason to | |
| 74 // fail but we won't be able to retrieves information about the heap, so we | |
| 75 // should stop here. | |
| 76 if (heap_query == NULL) | |
| 77 return; | |
| 78 | |
| 79 HANDLE heaps[1024] = { 0 }; | |
| 80 unsigned number_heaps = GetProcessHeaps(1024, heaps); | |
| 81 EXPECT_GT(number_heaps, 0u); | |
| 82 for (unsigned i = 0; i < number_heaps; ++i) { | |
| 83 ULONG flag = 0; | |
| 84 SIZE_T length; | |
| 85 ASSERT_NE(0, heap_query(heaps[i], | |
| 86 HeapCompatibilityInformation, | |
| 87 &flag, | |
| 88 sizeof(flag), | |
| 89 &length)); | |
| 90 // If flag is 0, the heap is a standard heap that does not support | |
| 91 // look-asides. If flag is 1, the heap supports look-asides. If flag is 2, | |
| 92 // the heap is a low-fragmentation heap (LFH). Note that look-asides are not | |
| 93 // supported on the LFH. | |
| 94 | |
| 95 // We don't have any documented way of querying the HEAP_NO_SERIALIZE flag. | |
| 96 EXPECT_LE(flag, 2u); | |
| 97 EXPECT_NE(flag, 1u); | |
| 98 } | |
| 99 } | |
| 100 #endif // defined(OS_WIN) | |
| 101 | |
| 102 #if defined(OS_MACOSX) | |
| 103 | |
| 104 // For the following Mac tests: | |
| 105 // Note that base::EnableTerminationOnHeapCorruption() is called as part of | |
| 106 // test suite setup and does not need to be done again, else mach_override | |
| 107 // will fail. | |
| 108 | |
| 109 TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) { | |
| 110 // Assert that freeing an unallocated pointer will crash the process. | |
| 111 char buf[9]; | |
| 112 asm("" : "=r" (buf)); // Prevent clang from being too smart. | |
| 113 #if ARCH_CPU_64_BITS | |
| 114 // On 64 bit Macs, the malloc system automatically abort()s on heap corruption | |
| 115 // but does not output anything. | |
| 116 ASSERT_DEATH(free(buf), ""); | |
| 117 #elif defined(ADDRESS_SANITIZER) | |
| 118 // AddressSanitizer replaces malloc() and prints a different error message on | |
| 119 // heap corruption. | |
| 120 ASSERT_DEATH(free(buf), "attempting free on address which " | |
| 121 "was not malloc\\(\\)-ed"); | |
| 122 #else | |
| 123 ADD_FAILURE() << "This test is not supported in this build configuration."; | |
| 124 #endif | |
| 125 } | |
| 126 | |
| 127 #endif // defined(OS_MACOSX) | |
| 128 | |
| 129 // Android doesn't implement set_new_handler, so we can't use the | |
| 130 // OutOfMemoryTest cases. OpenBSD does not support these tests either. | |
| 131 // Don't test these on ASan/TSan/MSan configurations: only test the real | |
| 132 // allocator. | |
| 133 // TODO(vandebo) make this work on Windows too. | |
| 134 #if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) && \ | |
| 135 !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | |
| 136 | |
| 137 #if defined(USE_TCMALLOC) | |
| 138 extern "C" { | |
| 139 int tc_set_new_mode(int mode); | |
| 140 } | |
| 141 #endif // defined(USE_TCMALLOC) | |
| 142 | |
| 143 namespace { | |
| 144 const char *kOomRegex = "Out of memory"; | |
| 145 } // namespace | |
| 146 | |
| 147 class OutOfMemoryTest : public testing::Test { | |
| 148 public: | |
| 149 OutOfMemoryTest() | |
| 150 : value_(NULL), | |
| 151 // Make test size as large as possible minus a few pages so | |
| 152 // that alignment or other rounding doesn't make it wrap. | |
| 153 test_size_(std::numeric_limits<std::size_t>::max() - 12 * 1024), | |
| 154 signed_test_size_(std::numeric_limits<ssize_t>::max()) { | |
| 155 } | |
| 156 | |
| 157 #if defined(USE_TCMALLOC) | |
| 158 void SetUp() override { tc_set_new_mode(1); } | |
| 159 | |
| 160 void TearDown() override { tc_set_new_mode(0); } | |
| 161 #endif // defined(USE_TCMALLOC) | |
| 162 | |
| 163 protected: | |
| 164 void* value_; | |
| 165 size_t test_size_; | |
| 166 ssize_t signed_test_size_; | |
| 167 }; | |
| 168 | |
| 169 class OutOfMemoryDeathTest : public OutOfMemoryTest { | |
| 170 public: | |
| 171 void SetUpInDeathAssert() { | |
| 172 // Must call EnableTerminationOnOutOfMemory() because that is called from | |
| 173 // chrome's main function and therefore hasn't been called yet. | |
| 174 // Since this call may result in another thread being created and death | |
| 175 // tests shouldn't be started in a multithread environment, this call | |
| 176 // should be done inside of the ASSERT_DEATH. | |
| 177 base::EnableTerminationOnOutOfMemory(); | |
| 178 } | |
| 179 }; | |
| 180 | |
| 181 TEST_F(OutOfMemoryDeathTest, New) { | |
| 182 ASSERT_DEATH({ | |
| 183 SetUpInDeathAssert(); | |
| 184 value_ = operator new(test_size_); | |
| 185 }, kOomRegex); | |
| 186 } | |
| 187 | |
| 188 TEST_F(OutOfMemoryDeathTest, NewArray) { | |
| 189 ASSERT_DEATH({ | |
| 190 SetUpInDeathAssert(); | |
| 191 value_ = new char[test_size_]; | |
| 192 }, kOomRegex); | |
| 193 } | |
| 194 | |
| 195 TEST_F(OutOfMemoryDeathTest, Malloc) { | |
| 196 ASSERT_DEATH({ | |
| 197 SetUpInDeathAssert(); | |
| 198 value_ = malloc(test_size_); | |
| 199 }, kOomRegex); | |
| 200 } | |
| 201 | |
| 202 TEST_F(OutOfMemoryDeathTest, Realloc) { | |
| 203 ASSERT_DEATH({ | |
| 204 SetUpInDeathAssert(); | |
| 205 value_ = realloc(NULL, test_size_); | |
| 206 }, kOomRegex); | |
| 207 } | |
| 208 | |
| 209 TEST_F(OutOfMemoryDeathTest, Calloc) { | |
| 210 ASSERT_DEATH({ | |
| 211 SetUpInDeathAssert(); | |
| 212 value_ = calloc(1024, test_size_ / 1024L); | |
| 213 }, kOomRegex); | |
| 214 } | |
| 215 | |
| 216 TEST_F(OutOfMemoryDeathTest, Valloc) { | |
| 217 ASSERT_DEATH({ | |
| 218 SetUpInDeathAssert(); | |
| 219 value_ = valloc(test_size_); | |
| 220 }, kOomRegex); | |
| 221 } | |
| 222 | |
| 223 #if defined(OS_LINUX) | |
| 224 | |
| 225 #if PVALLOC_AVAILABLE == 1 | |
| 226 TEST_F(OutOfMemoryDeathTest, Pvalloc) { | |
| 227 ASSERT_DEATH({ | |
| 228 SetUpInDeathAssert(); | |
| 229 value_ = pvalloc(test_size_); | |
| 230 }, kOomRegex); | |
| 231 } | |
| 232 #endif // PVALLOC_AVAILABLE == 1 | |
| 233 | |
| 234 TEST_F(OutOfMemoryDeathTest, Memalign) { | |
| 235 ASSERT_DEATH({ | |
| 236 SetUpInDeathAssert(); | |
| 237 value_ = memalign(4, test_size_); | |
| 238 }, kOomRegex); | |
| 239 } | |
| 240 | |
| 241 TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) { | |
| 242 // This tests that the run-time symbol resolution is overriding malloc for | |
| 243 // shared libraries as well as for our code. | |
| 244 ASSERT_DEATH({ | |
| 245 SetUpInDeathAssert(); | |
| 246 value_ = MallocWrapper(test_size_); | |
| 247 }, kOomRegex); | |
| 248 } | |
| 249 #endif // OS_LINUX | |
| 250 | |
| 251 // Android doesn't implement posix_memalign(). | |
| 252 #if defined(OS_POSIX) && !defined(OS_ANDROID) | |
| 253 TEST_F(OutOfMemoryDeathTest, Posix_memalign) { | |
| 254 // Grab the return value of posix_memalign to silence a compiler warning | |
| 255 // about unused return values. We don't actually care about the return | |
| 256 // value, since we're asserting death. | |
| 257 ASSERT_DEATH({ | |
| 258 SetUpInDeathAssert(); | |
| 259 EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_)); | |
| 260 }, kOomRegex); | |
| 261 } | |
| 262 #endif // defined(OS_POSIX) && !defined(OS_ANDROID) | |
| 263 | |
| 264 #if defined(OS_MACOSX) | |
| 265 | |
| 266 // Purgeable zone tests | |
| 267 | |
| 268 TEST_F(OutOfMemoryDeathTest, MallocPurgeable) { | |
| 269 malloc_zone_t* zone = malloc_default_purgeable_zone(); | |
| 270 ASSERT_DEATH({ | |
| 271 SetUpInDeathAssert(); | |
| 272 value_ = malloc_zone_malloc(zone, test_size_); | |
| 273 }, kOomRegex); | |
| 274 } | |
| 275 | |
| 276 TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) { | |
| 277 malloc_zone_t* zone = malloc_default_purgeable_zone(); | |
| 278 ASSERT_DEATH({ | |
| 279 SetUpInDeathAssert(); | |
| 280 value_ = malloc_zone_realloc(zone, NULL, test_size_); | |
| 281 }, kOomRegex); | |
| 282 } | |
| 283 | |
| 284 TEST_F(OutOfMemoryDeathTest, CallocPurgeable) { | |
| 285 malloc_zone_t* zone = malloc_default_purgeable_zone(); | |
| 286 ASSERT_DEATH({ | |
| 287 SetUpInDeathAssert(); | |
| 288 value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L); | |
| 289 }, kOomRegex); | |
| 290 } | |
| 291 | |
| 292 TEST_F(OutOfMemoryDeathTest, VallocPurgeable) { | |
| 293 malloc_zone_t* zone = malloc_default_purgeable_zone(); | |
| 294 ASSERT_DEATH({ | |
| 295 SetUpInDeathAssert(); | |
| 296 value_ = malloc_zone_valloc(zone, test_size_); | |
| 297 }, kOomRegex); | |
| 298 } | |
| 299 | |
| 300 TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) { | |
| 301 malloc_zone_t* zone = malloc_default_purgeable_zone(); | |
| 302 ASSERT_DEATH({ | |
| 303 SetUpInDeathAssert(); | |
| 304 value_ = malloc_zone_memalign(zone, 8, test_size_); | |
| 305 }, kOomRegex); | |
| 306 } | |
| 307 | |
| 308 // Since these allocation functions take a signed size, it's possible that | |
| 309 // calling them just once won't be enough to exhaust memory. In the 32-bit | |
| 310 // environment, it's likely that these allocation attempts will fail because | |
| 311 // not enough contiguous address space is available. In the 64-bit environment, | |
| 312 // it's likely that they'll fail because they would require a preposterous | |
| 313 // amount of (virtual) memory. | |
| 314 | |
| 315 TEST_F(OutOfMemoryDeathTest, CFAllocatorSystemDefault) { | |
| 316 ASSERT_DEATH({ | |
| 317 SetUpInDeathAssert(); | |
| 318 while ((value_ = | |
| 319 base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {} | |
| 320 }, kOomRegex); | |
| 321 } | |
| 322 | |
| 323 TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) { | |
| 324 ASSERT_DEATH({ | |
| 325 SetUpInDeathAssert(); | |
| 326 while ((value_ = | |
| 327 base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {} | |
| 328 }, kOomRegex); | |
| 329 } | |
| 330 | |
| 331 TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) { | |
| 332 ASSERT_DEATH({ | |
| 333 SetUpInDeathAssert(); | |
| 334 while ((value_ = | |
| 335 base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {} | |
| 336 }, kOomRegex); | |
| 337 } | |
| 338 | |
| 339 #if !defined(ARCH_CPU_64_BITS) | |
| 340 | |
| 341 // See process_util_unittest_mac.mm for an explanation of why this test isn't | |
| 342 // run in the 64-bit environment. | |
| 343 | |
| 344 TEST_F(OutOfMemoryDeathTest, PsychoticallyBigObjCObject) { | |
| 345 ASSERT_DEATH({ | |
| 346 SetUpInDeathAssert(); | |
| 347 while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {} | |
| 348 }, kOomRegex); | |
| 349 } | |
| 350 | |
| 351 #endif // !ARCH_CPU_64_BITS | |
| 352 #endif // OS_MACOSX | |
| 353 | |
| 354 class OutOfMemoryHandledTest : public OutOfMemoryTest { | |
| 355 public: | |
| 356 static const size_t kSafeMallocSize = 512; | |
| 357 static const size_t kSafeCallocSize = 128; | |
| 358 static const size_t kSafeCallocItems = 4; | |
| 359 | |
| 360 void SetUp() override { | |
| 361 OutOfMemoryTest::SetUp(); | |
| 362 | |
| 363 // We enable termination on OOM - just as Chrome does at early | |
| 364 // initialization - and test that UncheckedMalloc and UncheckedCalloc | |
| 365 // properly by-pass this in order to allow the caller to handle OOM. | |
| 366 base::EnableTerminationOnOutOfMemory(); | |
| 367 } | |
| 368 }; | |
| 369 | |
| 370 // TODO(b.kelemen): make UncheckedMalloc and UncheckedCalloc work | |
| 371 // on Windows as well. | |
| 372 // UncheckedMalloc() and UncheckedCalloc() work as regular malloc()/calloc() | |
| 373 // under sanitizer tools. | |
| 374 #if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | |
| 375 TEST_F(OutOfMemoryHandledTest, UncheckedMalloc) { | |
| 376 #if defined(OS_MACOSX) && ARCH_CPU_32_BITS | |
| 377 // The Mavericks malloc library changed in a way which breaks the tricks used | |
| 378 // to implement EnableTerminationOnOutOfMemory() with UncheckedMalloc() under | |
| 379 // 32-bit. The 64-bit malloc library works as desired without tricks. | |
| 380 if (base::mac::IsOSMavericksOrLater()) | |
| 381 return; | |
| 382 #endif | |
| 383 EXPECT_TRUE(base::UncheckedMalloc(kSafeMallocSize, &value_)); | |
| 384 EXPECT_TRUE(value_ != NULL); | |
| 385 free(value_); | |
| 386 | |
| 387 EXPECT_FALSE(base::UncheckedMalloc(test_size_, &value_)); | |
| 388 EXPECT_TRUE(value_ == NULL); | |
| 389 } | |
| 390 | |
| 391 TEST_F(OutOfMemoryHandledTest, UncheckedCalloc) { | |
| 392 #if defined(OS_MACOSX) && ARCH_CPU_32_BITS | |
| 393 // The Mavericks malloc library changed in a way which breaks the tricks used | |
| 394 // to implement EnableTerminationOnOutOfMemory() with UncheckedCalloc() under | |
| 395 // 32-bit. The 64-bit malloc library works as desired without tricks. | |
| 396 if (base::mac::IsOSMavericksOrLater()) | |
| 397 return; | |
| 398 #endif | |
| 399 EXPECT_TRUE(base::UncheckedCalloc(1, kSafeMallocSize, &value_)); | |
| 400 EXPECT_TRUE(value_ != NULL); | |
| 401 const char* bytes = static_cast<const char*>(value_); | |
| 402 for (size_t i = 0; i < kSafeMallocSize; ++i) | |
| 403 EXPECT_EQ(0, bytes[i]); | |
| 404 free(value_); | |
| 405 | |
| 406 EXPECT_TRUE( | |
| 407 base::UncheckedCalloc(kSafeCallocItems, kSafeCallocSize, &value_)); | |
| 408 EXPECT_TRUE(value_ != NULL); | |
| 409 bytes = static_cast<const char*>(value_); | |
| 410 for (size_t i = 0; i < (kSafeCallocItems * kSafeCallocSize); ++i) | |
| 411 EXPECT_EQ(0, bytes[i]); | |
| 412 free(value_); | |
| 413 | |
| 414 EXPECT_FALSE(base::UncheckedCalloc(1, test_size_, &value_)); | |
| 415 EXPECT_TRUE(value_ == NULL); | |
| 416 } | |
| 417 #endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | |
| 418 #endif // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) && | |
| 419 // !defined(ADDRESS_SANITIZER) | |
| OLD | NEW |