memory_unittest.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  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. #define _CRT_SECURE_NO_WARNINGS
  5. #include "base/process/memory.h"
  6. #include <stddef.h>
  7. #include <limits>
  8. #include <tuple>
  9. #include <vector>
  10. #include "base/allocator/allocator_check.h"
  11. #include "base/allocator/buildflags.h"
  12. #include "base/allocator/partition_allocator/page_allocator.h"
  13. #include "base/compiler_specific.h"
  14. #include "base/debug/alias.h"
  15. #include "base/memory/aligned_memory.h"
  16. #include "base/memory/page_size.h"
  17. #include "build/build_config.h"
  18. #include "testing/gtest/include/gtest/gtest.h"
  19. #if BUILDFLAG(IS_WIN)
  20. #include <windows.h>
  21. #endif
  22. #if BUILDFLAG(IS_POSIX)
  23. #include <errno.h>
  24. #endif
  25. #if BUILDFLAG(IS_MAC)
  26. #include <malloc/malloc.h>
  27. #include "base/allocator/allocator_interception_mac.h"
  28. #include "base/allocator/allocator_shim.h"
  29. #include "base/allocator/buildflags.h"
  30. #include "base/process/memory_unittest_mac.h"
  31. #endif
  32. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  33. #include <malloc.h>
  34. #include "base/test/malloc_wrapper.h"
  35. #endif
  36. #if BUILDFLAG(IS_ANDROID)
  37. #include "base/android/build_info.h"
  38. #endif
  39. #if BUILDFLAG(IS_WIN)
  40. #if defined(COMPILER_MSVC)
  41. // ssize_t needed for OutOfMemoryTest.
  42. #if defined(_WIN64)
  43. typedef __int64 ssize_t;
  44. #else
  45. typedef long ssize_t;
  46. #endif
  47. #endif
  48. // HeapQueryInformation function pointer.
  49. typedef BOOL (WINAPI* HeapQueryFn) \
  50. (HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
  51. #endif // BUILDFLAG(IS_WIN)
  52. #if BUILDFLAG(IS_MAC)
  53. // For the following Mac tests:
  54. // Note that base::EnableTerminationOnHeapCorruption() is called as part of
  55. // test suite setup and does not need to be done again, else mach_override
  56. // will fail.
  57. // Wrap free() in a function to thwart Clang's -Wfree-nonheap-object warning.
  58. static void callFree(void *ptr) {
  59. free(ptr);
  60. }
  61. TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) {
  62. #if BUILDFLAG(USE_ALLOCATOR_SHIM)
  63. base::allocator::InitializeAllocatorShim();
  64. #endif
  65. // Assert that freeing an unallocated pointer will crash the process.
  66. char buf[9];
  67. asm("" : "=m"(buf)); // Prevent clang from being too smart.
  68. #if ARCH_CPU_64_BITS
  69. // On 64 bit Macs, the malloc system automatically abort()s on heap corruption
  70. // but does not output anything.
  71. ASSERT_DEATH(callFree(buf), "");
  72. #elif defined(ADDRESS_SANITIZER)
  73. // AddressSanitizer replaces malloc() and prints a different error message on
  74. // heap corruption.
  75. ASSERT_DEATH(callFree(buf), "attempting free on address which "
  76. "was not malloc\\(\\)-ed");
  77. #else
  78. ADD_FAILURE() << "This test is not supported in this build configuration.";
  79. #endif
  80. #if BUILDFLAG(USE_ALLOCATOR_SHIM)
  81. base::allocator::UninterceptMallocZonesForTesting();
  82. #endif
  83. }
  84. #endif // BUILDFLAG(IS_MAC)
  85. TEST(MemoryTest, AllocatorShimWorking) {
  86. #if BUILDFLAG(IS_MAC)
  87. #if BUILDFLAG(USE_ALLOCATOR_SHIM)
  88. base::allocator::InitializeAllocatorShim();
  89. #endif
  90. base::allocator::InterceptAllocationsMac();
  91. #endif
  92. ASSERT_TRUE(base::allocator::IsAllocatorInitialized());
  93. #if BUILDFLAG(IS_MAC)
  94. base::allocator::UninterceptMallocZonesForTesting();
  95. #endif
  96. }
  97. // OpenBSD does not support these tests. Don't test these on ASan/TSan/MSan
  98. // configurations: only test the real allocator.
  99. #if !BUILDFLAG(IS_OPENBSD) && BUILDFLAG(USE_ALLOCATOR_SHIM) && \
  100. !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
  101. namespace {
  102. #if BUILDFLAG(IS_WIN)
  103. // Windows raises an exception in order to make the exit code unique to OOM.
  104. #define ASSERT_OOM_DEATH(statement) \
  105. ASSERT_EXIT(statement, \
  106. testing::ExitedWithCode(base::win::kOomExceptionCode), "")
  107. #else
  108. #define ASSERT_OOM_DEATH(statement) ASSERT_DEATH(statement, "")
  109. #endif // BUILDFLAG(IS_WIN)
  110. } // namespace
  111. class OutOfMemoryTest : public testing::Test {
  112. public:
  113. OutOfMemoryTest()
  114. : value_(nullptr),
  115. // Make test size as large as possible minus a few pages so that
  116. // alignment or other rounding doesn't make it wrap.
  117. test_size_(std::numeric_limits<std::size_t>::max() -
  118. 3 * base::GetPageSize()),
  119. // A test size that is > 2Gb and will cause the allocators to reject
  120. // the allocation due to security restrictions. See crbug.com/169327.
  121. insecure_test_size_(std::numeric_limits<int>::max()),
  122. signed_test_size_(std::numeric_limits<ssize_t>::max()) {}
  123. protected:
  124. void* value_;
  125. size_t test_size_;
  126. size_t insecure_test_size_;
  127. ssize_t signed_test_size_;
  128. };
  129. class OutOfMemoryDeathTest : public OutOfMemoryTest {
  130. public:
  131. void SetUpInDeathAssert() {
  132. #if BUILDFLAG(IS_MAC) && BUILDFLAG(USE_ALLOCATOR_SHIM)
  133. base::allocator::InitializeAllocatorShim();
  134. #endif
  135. // Must call EnableTerminationOnOutOfMemory() because that is called from
  136. // chrome's main function and therefore hasn't been called yet.
  137. // Since this call may result in another thread being created and death
  138. // tests shouldn't be started in a multithread environment, this call
  139. // should be done inside of the ASSERT_DEATH.
  140. base::EnableTerminationOnOutOfMemory();
  141. }
  142. #if BUILDFLAG(IS_MAC)
  143. void TearDown() override {
  144. base::allocator::UninterceptMallocZonesForTesting();
  145. }
  146. #endif
  147. // These tests don't work properly on old x86 Android; crbug.com/1181112
  148. bool ShouldSkipTest() {
  149. #if BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_X86)
  150. return base::android::BuildInfo::GetInstance()->sdk_int() <
  151. base::android::SDK_VERSION_NOUGAT;
  152. #else
  153. return false;
  154. #endif
  155. }
  156. };
  157. TEST_F(OutOfMemoryDeathTest, New) {
  158. if (ShouldSkipTest()) {
  159. return;
  160. }
  161. ASSERT_OOM_DEATH({
  162. SetUpInDeathAssert();
  163. value_ = operator new(test_size_);
  164. });
  165. }
  166. TEST_F(OutOfMemoryDeathTest, NewArray) {
  167. if (ShouldSkipTest()) {
  168. return;
  169. }
  170. ASSERT_OOM_DEATH({
  171. SetUpInDeathAssert();
  172. value_ = new char[test_size_];
  173. });
  174. }
  175. TEST_F(OutOfMemoryDeathTest, Malloc) {
  176. if (ShouldSkipTest()) {
  177. return;
  178. }
  179. ASSERT_OOM_DEATH({
  180. SetUpInDeathAssert();
  181. value_ = malloc(test_size_);
  182. });
  183. }
  184. TEST_F(OutOfMemoryDeathTest, Realloc) {
  185. if (ShouldSkipTest()) {
  186. return;
  187. }
  188. ASSERT_OOM_DEATH({
  189. SetUpInDeathAssert();
  190. value_ = realloc(nullptr, test_size_);
  191. });
  192. }
  193. TEST_F(OutOfMemoryDeathTest, Calloc) {
  194. if (ShouldSkipTest()) {
  195. return;
  196. }
  197. ASSERT_OOM_DEATH({
  198. SetUpInDeathAssert();
  199. value_ = calloc(1024, test_size_ / 1024L);
  200. });
  201. }
  202. TEST_F(OutOfMemoryDeathTest, AlignedAlloc) {
  203. if (ShouldSkipTest()) {
  204. return;
  205. }
  206. ASSERT_OOM_DEATH({
  207. SetUpInDeathAssert();
  208. value_ = base::AlignedAlloc(test_size_, 8);
  209. });
  210. }
  211. // POSIX does not define an aligned realloc function.
  212. #if BUILDFLAG(IS_WIN)
  213. TEST_F(OutOfMemoryDeathTest, AlignedRealloc) {
  214. if (ShouldSkipTest()) {
  215. return;
  216. }
  217. ASSERT_OOM_DEATH({
  218. SetUpInDeathAssert();
  219. value_ = _aligned_realloc(nullptr, test_size_, 8);
  220. });
  221. }
  222. namespace {
  223. constexpr uint32_t kUnhandledExceptionExitCode = 0xBADA55;
  224. // This unhandled exception filter exits the process with an exit code distinct
  225. // from the exception code. This is to verify that the out of memory new handler
  226. // causes an unhandled exception.
  227. LONG WINAPI ExitingUnhandledExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo) {
  228. _exit(kUnhandledExceptionExitCode);
  229. }
  230. } // namespace
  231. TEST_F(OutOfMemoryDeathTest, NewHandlerGeneratesUnhandledException) {
  232. ASSERT_EXIT(
  233. {
  234. SetUpInDeathAssert();
  235. SetUnhandledExceptionFilter(&ExitingUnhandledExceptionFilter);
  236. value_ = new char[test_size_];
  237. },
  238. testing::ExitedWithCode(kUnhandledExceptionExitCode), "");
  239. }
  240. #endif // BUILDFLAG(IS_WIN)
  241. // OS X has no 2Gb allocation limit.
  242. // See https://crbug.com/169327.
  243. #if !BUILDFLAG(IS_MAC)
  244. TEST_F(OutOfMemoryDeathTest, SecurityNew) {
  245. if (ShouldSkipTest()) {
  246. return;
  247. }
  248. ASSERT_OOM_DEATH({
  249. SetUpInDeathAssert();
  250. value_ = operator new(insecure_test_size_);
  251. });
  252. }
  253. TEST_F(OutOfMemoryDeathTest, SecurityNewArray) {
  254. if (ShouldSkipTest()) {
  255. return;
  256. }
  257. ASSERT_OOM_DEATH({
  258. SetUpInDeathAssert();
  259. value_ = new char[insecure_test_size_];
  260. });
  261. }
  262. TEST_F(OutOfMemoryDeathTest, SecurityMalloc) {
  263. if (ShouldSkipTest()) {
  264. return;
  265. }
  266. ASSERT_OOM_DEATH({
  267. SetUpInDeathAssert();
  268. value_ = malloc(insecure_test_size_);
  269. });
  270. }
  271. TEST_F(OutOfMemoryDeathTest, SecurityRealloc) {
  272. if (ShouldSkipTest()) {
  273. return;
  274. }
  275. ASSERT_OOM_DEATH({
  276. SetUpInDeathAssert();
  277. value_ = realloc(nullptr, insecure_test_size_);
  278. });
  279. }
  280. TEST_F(OutOfMemoryDeathTest, SecurityCalloc) {
  281. if (ShouldSkipTest()) {
  282. return;
  283. }
  284. ASSERT_OOM_DEATH({
  285. SetUpInDeathAssert();
  286. value_ = calloc(1024, insecure_test_size_ / 1024L);
  287. });
  288. }
  289. TEST_F(OutOfMemoryDeathTest, SecurityAlignedAlloc) {
  290. if (ShouldSkipTest()) {
  291. return;
  292. }
  293. ASSERT_OOM_DEATH({
  294. SetUpInDeathAssert();
  295. value_ = base::AlignedAlloc(insecure_test_size_, 8);
  296. });
  297. }
  298. // POSIX does not define an aligned realloc function.
  299. #if BUILDFLAG(IS_WIN)
  300. TEST_F(OutOfMemoryDeathTest, SecurityAlignedRealloc) {
  301. if (ShouldSkipTest()) {
  302. return;
  303. }
  304. ASSERT_OOM_DEATH({
  305. SetUpInDeathAssert();
  306. value_ = _aligned_realloc(nullptr, insecure_test_size_, 8);
  307. });
  308. }
  309. #endif // BUILDFLAG(IS_WIN)
  310. #endif // !BUILDFLAG(IS_MAC)
  311. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  312. TEST_F(OutOfMemoryDeathTest, Valloc) {
  313. ASSERT_OOM_DEATH({
  314. SetUpInDeathAssert();
  315. value_ = valloc(test_size_);
  316. EXPECT_TRUE(value_);
  317. });
  318. }
  319. TEST_F(OutOfMemoryDeathTest, SecurityValloc) {
  320. ASSERT_OOM_DEATH({
  321. SetUpInDeathAssert();
  322. value_ = valloc(insecure_test_size_);
  323. });
  324. }
  325. TEST_F(OutOfMemoryDeathTest, Pvalloc) {
  326. ASSERT_OOM_DEATH({
  327. SetUpInDeathAssert();
  328. value_ = pvalloc(test_size_);
  329. });
  330. }
  331. TEST_F(OutOfMemoryDeathTest, SecurityPvalloc) {
  332. ASSERT_OOM_DEATH({
  333. SetUpInDeathAssert();
  334. value_ = pvalloc(insecure_test_size_);
  335. });
  336. }
  337. TEST_F(OutOfMemoryDeathTest, Memalign) {
  338. ASSERT_OOM_DEATH({
  339. SetUpInDeathAssert();
  340. value_ = memalign(4, test_size_);
  341. });
  342. }
  343. TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) {
  344. // This tests that the run-time symbol resolution is overriding malloc for
  345. // shared libraries as well as for our code.
  346. ASSERT_OOM_DEATH({
  347. SetUpInDeathAssert();
  348. value_ = MallocWrapper(test_size_);
  349. });
  350. }
  351. #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  352. // Android doesn't implement posix_memalign().
  353. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID)
  354. TEST_F(OutOfMemoryDeathTest, Posix_memalign) {
  355. // Grab the return value of posix_memalign to silence a compiler warning
  356. // about unused return values. We don't actually care about the return
  357. // value, since we're asserting death.
  358. ASSERT_OOM_DEATH({
  359. SetUpInDeathAssert();
  360. EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_));
  361. });
  362. }
  363. #endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID)
  364. #if BUILDFLAG(IS_MAC)
  365. // Purgeable zone tests
  366. TEST_F(OutOfMemoryDeathTest, MallocPurgeable) {
  367. malloc_zone_t* zone = malloc_default_purgeable_zone();
  368. ASSERT_OOM_DEATH({
  369. SetUpInDeathAssert();
  370. value_ = malloc_zone_malloc(zone, test_size_);
  371. });
  372. }
  373. TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) {
  374. malloc_zone_t* zone = malloc_default_purgeable_zone();
  375. ASSERT_OOM_DEATH({
  376. SetUpInDeathAssert();
  377. value_ = malloc_zone_realloc(zone, nullptr, test_size_);
  378. });
  379. }
  380. TEST_F(OutOfMemoryDeathTest, CallocPurgeable) {
  381. malloc_zone_t* zone = malloc_default_purgeable_zone();
  382. ASSERT_OOM_DEATH({
  383. SetUpInDeathAssert();
  384. value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L);
  385. });
  386. }
  387. TEST_F(OutOfMemoryDeathTest, VallocPurgeable) {
  388. malloc_zone_t* zone = malloc_default_purgeable_zone();
  389. ASSERT_OOM_DEATH({
  390. SetUpInDeathAssert();
  391. value_ = malloc_zone_valloc(zone, test_size_);
  392. });
  393. }
  394. TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) {
  395. malloc_zone_t* zone = malloc_default_purgeable_zone();
  396. ASSERT_OOM_DEATH({
  397. SetUpInDeathAssert();
  398. value_ = malloc_zone_memalign(zone, 8, test_size_);
  399. });
  400. }
  401. // Since these allocation functions take a signed size, it's possible that
  402. // calling them just once won't be enough to exhaust memory. In the 32-bit
  403. // environment, it's likely that these allocation attempts will fail because
  404. // not enough contiguous address space is available. In the 64-bit environment,
  405. // it's likely that they'll fail because they would require a preposterous
  406. // amount of (virtual) memory.
  407. TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) {
  408. ASSERT_OOM_DEATH({
  409. SetUpInDeathAssert();
  410. while ((value_ = base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {
  411. }
  412. });
  413. }
  414. #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
  415. // PartitionAlloc-Everywhere does not intercept other malloc zones than the
  416. // default (the top) malloc zone. Plus,
  417. // CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0) does not call the
  418. // default (the top) malloc zone on macOS 10.xx (does call it on macOS 11 and
  419. // later though).
  420. #define MAYBE_CFAllocatorSystemDefault DISABLED_CFAllocatorSystemDefault
  421. #else
  422. #define MAYBE_CFAllocatorSystemDefault CFAllocatorSystemDefault
  423. #endif
  424. TEST_F(OutOfMemoryDeathTest, MAYBE_CFAllocatorSystemDefault) {
  425. ASSERT_OOM_DEATH({
  426. SetUpInDeathAssert();
  427. while ((value_ =
  428. base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {
  429. }
  430. });
  431. }
  432. #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
  433. // PartitionAlloc-Everywhere does not intercept other malloc zones than the
  434. // default (the top) malloc zone. Plus,
  435. // CFAllocatorAllocate(kCFAllocatorMallocZone, size, 0) does not call the
  436. // default (the top) malloc zone on macOS 10.xx (does call it on macOS 11 and
  437. // later though).
  438. #define MAYBE_CFAllocatorMallocZone DISABLED_CFAllocatorMallocZone
  439. #else
  440. #define MAYBE_CFAllocatorMallocZone CFAllocatorMallocZone
  441. #endif
  442. TEST_F(OutOfMemoryDeathTest, MAYBE_CFAllocatorMallocZone) {
  443. ASSERT_OOM_DEATH({
  444. SetUpInDeathAssert();
  445. while (
  446. (value_ = base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {
  447. }
  448. });
  449. }
  450. #endif // BUILDFLAG(IS_MAC)
  451. class OutOfMemoryHandledTest : public OutOfMemoryTest {
  452. public:
  453. static const size_t kSafeMallocSize = 512;
  454. static const size_t kSafeCallocSize = 128;
  455. static const size_t kSafeCallocItems = 4;
  456. void SetUp() override {
  457. OutOfMemoryTest::SetUp();
  458. // We enable termination on OOM - just as Chrome does at early
  459. // initialization - and test that UncheckedMalloc and UncheckedCalloc
  460. // properly by-pass this in order to allow the caller to handle OOM.
  461. base::EnableTerminationOnOutOfMemory();
  462. }
  463. void TearDown() override {
  464. #if BUILDFLAG(IS_MAC)
  465. base::allocator::UninterceptMallocZonesForTesting();
  466. #endif
  467. }
  468. };
  469. #if BUILDFLAG(IS_WIN)
  470. namespace {
  471. DWORD HandleOutOfMemoryException(EXCEPTION_POINTERS* exception_ptrs,
  472. size_t expected_size) {
  473. EXPECT_EQ(base::win::kOomExceptionCode,
  474. exception_ptrs->ExceptionRecord->ExceptionCode);
  475. EXPECT_LE(1U, exception_ptrs->ExceptionRecord->NumberParameters);
  476. EXPECT_EQ(expected_size,
  477. exception_ptrs->ExceptionRecord->ExceptionInformation[0]);
  478. return EXCEPTION_EXECUTE_HANDLER;
  479. }
  480. } // namespace
  481. TEST_F(OutOfMemoryTest, TerminateBecauseOutOfMemoryReportsAllocSize) {
  482. // On Windows, TerminateBecauseOutOfMemory reports the attempted allocation
  483. // size in the exception raised.
  484. #if defined(ARCH_CPU_64_BITS)
  485. // Test with a size larger than 32 bits on 64 bit machines.
  486. const size_t kAttemptedAllocationSize = 0xBADA55F00DULL;
  487. #else
  488. const size_t kAttemptedAllocationSize = 0xBADA55;
  489. #endif
  490. __try {
  491. base::TerminateBecauseOutOfMemory(kAttemptedAllocationSize);
  492. } __except (HandleOutOfMemoryException(GetExceptionInformation(),
  493. kAttemptedAllocationSize)) {
  494. }
  495. }
  496. #endif // BUILDFLAG(IS_WIN)
  497. #if defined(ARCH_CPU_32_BITS) && \
  498. (BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
  499. void TestAllocationsReleaseReservation(void* (*alloc_fn)(size_t),
  500. void (*free_fn)(void*)) {
  501. partition_alloc::ReleaseReservation();
  502. base::EnableTerminationOnOutOfMemory();
  503. constexpr size_t kMiB = 1 << 20;
  504. constexpr size_t kReservationSize = 512 * kMiB; // MiB.
  505. size_t reservation_size = kReservationSize;
  506. while (!partition_alloc::ReserveAddressSpace(reservation_size)) {
  507. reservation_size -= 16 * kMiB;
  508. }
  509. ASSERT_TRUE(partition_alloc::HasReservationForTesting());
  510. ASSERT_GT(reservation_size, 0u);
  511. // Allocate a large area at a time to bump into address space exhaustion
  512. // before other limits. It is important not to do a larger allocation, to
  513. // verify that we can allocate without removing the reservation. On the other
  514. // hand, must be large enough to make the underlying implementation call
  515. // mmap()/VirtualAlloc().
  516. size_t allocation_size = reservation_size / 2;
  517. std::vector<void*> areas;
  518. // Pre-reserve the vector to make sure that we don't hit the address space
  519. // limit while resizing the array.
  520. areas.reserve(((2 * 4096 * kMiB) / allocation_size) + 1);
  521. while (true) {
  522. void* area = alloc_fn(allocation_size / 2);
  523. ASSERT_TRUE(area);
  524. areas.push_back(area);
  525. // Working as intended, the allocation was successful, and the reservation
  526. // was dropped instead of crashing.
  527. //
  528. // Meaning that the test is either successful, or crashes.
  529. if (!partition_alloc::HasReservationForTesting())
  530. break;
  531. }
  532. EXPECT_GE(areas.size(), 2u)
  533. << "Should be able to allocate without releasing the reservation";
  534. for (void* ptr : areas)
  535. free_fn(ptr);
  536. }
  537. TEST_F(OutOfMemoryHandledTest, MallocReleasesReservation) {
  538. TestAllocationsReleaseReservation(malloc, free);
  539. }
  540. TEST_F(OutOfMemoryHandledTest, NewReleasesReservation) {
  541. TestAllocationsReleaseReservation(
  542. [](size_t size) { return static_cast<void*>(new char[size]); },
  543. [](void* ptr) { delete[] static_cast<char*>(ptr); });
  544. }
  545. #endif // defined(ARCH_CPU_32_BITS) && (BUILDFLAG(IS_WIN) ||
  546. // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
  547. #if BUILDFLAG(IS_ANDROID)
  548. // Android's allocator does not allow overcommits, so very large
  549. // UncheckedMallocs will yield OOM errors.
  550. // TODO(crbug.com/1112840): Fails on some Android bots.
  551. #define MAYBE_UncheckedMallocDies DISABLED_UncheckedMallocDies
  552. #define MAYBE_UncheckedCallocDies DISABLED_UncheckedCallocDies
  553. TEST_F(OutOfMemoryDeathTest, MAYBE_UncheckedMallocDies) {
  554. ASSERT_OOM_DEATH({
  555. SetUpInDeathAssert();
  556. void* data;
  557. std::ignore = base::UncheckedMalloc(test_size_, &data);
  558. // Death expected here.
  559. });
  560. }
  561. TEST_F(OutOfMemoryDeathTest, MAYBE_UncheckedCallocDies) {
  562. ASSERT_OOM_DEATH({
  563. SetUpInDeathAssert();
  564. void* data;
  565. std::ignore = base::UncheckedCalloc(1, test_size_, &data);
  566. // Death expected here.
  567. });
  568. }
  569. #else
  570. TEST_F(OutOfMemoryHandledTest, UncheckedMalloc) {
  571. EXPECT_TRUE(base::UncheckedMalloc(kSafeMallocSize, &value_));
  572. EXPECT_TRUE(value_ != nullptr);
  573. base::UncheckedFree(value_);
  574. EXPECT_FALSE(base::UncheckedMalloc(test_size_, &value_));
  575. EXPECT_TRUE(value_ == nullptr);
  576. }
  577. TEST_F(OutOfMemoryHandledTest, UncheckedCalloc) {
  578. EXPECT_TRUE(base::UncheckedCalloc(1, kSafeMallocSize, &value_));
  579. EXPECT_TRUE(value_ != nullptr);
  580. const char* bytes = static_cast<const char*>(value_);
  581. for (size_t i = 0; i < kSafeMallocSize; ++i)
  582. EXPECT_EQ(0, bytes[i]);
  583. base::UncheckedFree(value_);
  584. EXPECT_TRUE(
  585. base::UncheckedCalloc(kSafeCallocItems, kSafeCallocSize, &value_));
  586. EXPECT_TRUE(value_ != nullptr);
  587. bytes = static_cast<const char*>(value_);
  588. for (size_t i = 0; i < (kSafeCallocItems * kSafeCallocSize); ++i)
  589. EXPECT_EQ(0, bytes[i]);
  590. base::UncheckedFree(value_);
  591. EXPECT_FALSE(base::UncheckedCalloc(1, test_size_, &value_));
  592. EXPECT_TRUE(value_ == nullptr);
  593. }
  594. #endif // BUILDFLAG(IS_ANDROID)
  595. #endif // !BUILDFLAG(IS_OPENBSD) && BUILDFLAG(USE_ALLOCATOR_SHIM) &&
  596. // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)