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