LCOV - code coverage report
Current view: top level - test/cctest - test-allocation.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 59 68 86.8 %
Date: 2017-10-20 Functions: 14 16 87.5 %

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

Generated by: LCOV version 1.10