LCOV - code coverage report
Current view: top level - test/cctest - test-allocation.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 58 67 86.6 %
Date: 2019-01-20 Functions: 15 17 88.2 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project 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             : #include <stdlib.h>
       5             : #include <string.h>
       6             : 
       7             : #if V8_OS_POSIX
       8             : #include <setjmp.h>
       9             : #include <signal.h>
      10             : #include <unistd.h>  // NOLINT
      11             : #endif
      12             : 
      13             : #include "src/v8.h"
      14             : 
      15             : #include "test/cctest/cctest.h"
      16             : 
      17             : using v8::internal::AccountingAllocator;
      18             : 
      19             : using v8::IdleTask;
      20             : using v8::Isolate;
      21             : using v8::Task;
      22             : 
      23             : #include "src/allocation.h"
      24             : #include "src/zone/accounting-allocator.h"
      25             : 
      26             : // ASAN isn't configured to return nullptr, so skip all of these tests.
      27             : #if !defined(V8_USE_ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
      28             :     !defined(THREAD_SANITIZER)
      29             : 
      30             : namespace {
      31             : 
      32             : // Implementation of v8::Platform that can register OOM callbacks.
      33             : class AllocationPlatform : public TestPlatform {
      34             :  public:
      35          60 :   AllocationPlatform() {
      36          30 :     current_platform = this;
      37             :     // Now that it's completely constructed, make this the current platform.
      38          30 :     i::V8::SetPlatformForTesting(this);
      39          30 :   }
      40          15 :   ~AllocationPlatform() override = default;
      41             : 
      42           5 :   void OnCriticalMemoryPressure() override { oom_callback_called = true; }
      43             : 
      44          50 :   bool OnCriticalMemoryPressure(size_t length) override {
      45          50 :     oom_callback_called = true;
      46          50 :     return true;
      47             :   }
      48             : 
      49             :   static AllocationPlatform* current_platform;
      50             :   bool oom_callback_called = false;
      51             : };
      52             : 
      53             : AllocationPlatform* AllocationPlatform::current_platform = nullptr;
      54             : 
      55             : bool DidCallOnCriticalMemoryPressure() {
      56          15 :   return AllocationPlatform::current_platform &&
      57             :          AllocationPlatform::current_platform->oom_callback_called;
      58             : }
      59             : 
      60             : // No OS should be able to malloc/new this number of bytes. Generate enough
      61             : // random values in the address space to get a very large fraction of it. Using
      62             : // even larger values is that overflow from rounding or padding can cause the
      63             : // allocations to succeed somehow.
      64          30 : size_t GetHugeMemoryAmount() {
      65             :   static size_t huge_memory = 0;
      66          30 :   if (!huge_memory) {
      67        3000 :     for (int i = 0; i < 100; i++) {
      68        6000 :       huge_memory |= bit_cast<size_t>(v8::internal::GetRandomMmapAddr());
      69             :     }
      70             :     // Make it larger than the available address space.
      71          30 :     huge_memory *= 2;
      72          30 :     CHECK_NE(0, huge_memory);
      73             :   }
      74          30 :   return huge_memory;
      75             : }
      76             : 
      77           5 : void OnMallocedOperatorNewOOM(const char* location, const char* message) {
      78             :   // exit(0) if the OOM callback was called and location matches expectation.
      79           5 :   if (DidCallOnCriticalMemoryPressure())
      80           5 :     exit(strcmp(location, "Malloced operator new"));
      81           0 :   exit(1);
      82             : }
      83             : 
      84           5 : void OnNewArrayOOM(const char* location, const char* message) {
      85             :   // exit(0) if the OOM callback was called and location matches expectation.
      86           5 :   if (DidCallOnCriticalMemoryPressure()) exit(strcmp(location, "NewArray"));
      87           0 :   exit(1);
      88             : }
      89             : 
      90           5 : void OnAlignedAllocOOM(const char* location, const char* message) {
      91             :   // exit(0) if the OOM callback was called and location matches expectation.
      92           5 :   if (DidCallOnCriticalMemoryPressure()) exit(strcmp(location, "AlignedAlloc"));
      93           0 :   exit(1);
      94             : }
      95             : 
      96             : }  // namespace
      97             : 
      98       28342 : TEST(AccountingAllocatorOOM) {
      99           5 :   AllocationPlatform platform;
     100          10 :   v8::internal::AccountingAllocator allocator;
     101           5 :   CHECK(!platform.oom_callback_called);
     102           5 :   v8::internal::Segment* result = allocator.GetSegment(GetHugeMemoryAmount());
     103             :   // On a few systems, allocation somehow succeeds.
     104           5 :   CHECK_EQ(result == nullptr, platform.oom_callback_called);
     105           5 : }
     106             : 
     107       28342 : TEST(MallocedOperatorNewOOM) {
     108           5 :   AllocationPlatform platform;
     109           5 :   CHECK(!platform.oom_callback_called);
     110           5 :   CcTest::isolate()->SetFatalErrorHandler(OnMallocedOperatorNewOOM);
     111             :   // On failure, this won't return, since a Malloced::New failure is fatal.
     112             :   // In that case, behavior is checked in OnMallocedOperatorNewOOM before exit.
     113           5 :   void* result = v8::internal::Malloced::New(GetHugeMemoryAmount());
     114             :   // On a few systems, allocation somehow succeeds.
     115           0 :   CHECK_EQ(result == nullptr, platform.oom_callback_called);
     116           0 : }
     117             : 
     118       28342 : TEST(NewArrayOOM) {
     119           5 :   AllocationPlatform platform;
     120           5 :   CHECK(!platform.oom_callback_called);
     121           5 :   CcTest::isolate()->SetFatalErrorHandler(OnNewArrayOOM);
     122             :   // On failure, this won't return, since a NewArray failure is fatal.
     123             :   // In that case, behavior is checked in OnNewArrayOOM before exit.
     124           5 :   int8_t* result = v8::internal::NewArray<int8_t>(GetHugeMemoryAmount());
     125             :   // On a few systems, allocation somehow succeeds.
     126           0 :   CHECK_EQ(result == nullptr, platform.oom_callback_called);
     127           0 : }
     128             : 
     129       28342 : TEST(AlignedAllocOOM) {
     130           5 :   AllocationPlatform platform;
     131           5 :   CHECK(!platform.oom_callback_called);
     132           5 :   CcTest::isolate()->SetFatalErrorHandler(OnAlignedAllocOOM);
     133             :   // On failure, this won't return, since an AlignedAlloc failure is fatal.
     134             :   // In that case, behavior is checked in OnAlignedAllocOOM before exit.
     135             :   void* result = v8::internal::AlignedAlloc(GetHugeMemoryAmount(),
     136           5 :                                             v8::internal::AllocatePageSize());
     137             :   // On a few systems, allocation somehow succeeds.
     138           0 :   CHECK_EQ(result == nullptr, platform.oom_callback_called);
     139           0 : }
     140             : 
     141       28342 : TEST(AllocVirtualMemoryOOM) {
     142           5 :   AllocationPlatform platform;
     143           5 :   CHECK(!platform.oom_callback_called);
     144             :   v8::internal::VirtualMemory result(v8::internal::GetPlatformPageAllocator(),
     145          10 :                                      GetHugeMemoryAmount(), nullptr);
     146             :   // On a few systems, allocation somehow succeeds.
     147           5 :   CHECK_IMPLIES(!result.IsReserved(), platform.oom_callback_called);
     148           5 : }
     149             : 
     150       28342 : TEST(AlignedAllocVirtualMemoryOOM) {
     151           5 :   AllocationPlatform platform;
     152           5 :   CHECK(!platform.oom_callback_called);
     153             :   v8::internal::VirtualMemory result(v8::internal::GetPlatformPageAllocator(),
     154             :                                      GetHugeMemoryAmount(), nullptr,
     155          10 :                                      v8::internal::AllocatePageSize());
     156             :   // On a few systems, allocation somehow succeeds.
     157           5 :   CHECK_IMPLIES(!result.IsReserved(), platform.oom_callback_called);
     158       85016 : }
     159             : 
     160             : #endif  // !defined(V8_USE_ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) &&
     161             :         // !defined(THREAD_SANITIZER)

Generated by: LCOV version 1.10