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