LCOV - code coverage report
Current view: top level - test/unittests - allocation-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 70 72 97.2 %
Date: 2019-04-17 Functions: 13 16 81.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             : 
       5             : #include "src/allocation.h"
       6             : 
       7             : #if V8_OS_POSIX
       8             : #include <setjmp.h>
       9             : #include <signal.h>
      10             : #include <unistd.h>  // NOLINT
      11             : #endif               // V8_OS_POSIX
      12             : 
      13             : #include "testing/gtest/include/gtest/gtest.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : // TODO(eholk): Add a windows version of permissions tests.
      19             : #if V8_OS_POSIX
      20             : namespace {
      21             : 
      22             : // These tests make sure the routines to allocate memory do so with the correct
      23             : // permissions.
      24             : //
      25             : // Unfortunately, there is no API to find the protection of a memory address,
      26             : // so instead we test permissions by installing a signal handler, probing a
      27             : // memory location and recovering from the fault.
      28             : //
      29             : // We don't test the execution permission because to do so we'd have to
      30             : // dynamically generate code and test if we can execute it.
      31             : 
      32           2 : class MemoryAllocationPermissionsTest : public ::testing::Test {
      33           4 :   static void SignalHandler(int signal, siginfo_t* info, void*) {
      34           4 :     siglongjmp(continuation_, 1);
      35             :   }
      36             :   struct sigaction old_action_;
      37             : // On Mac, sometimes we get SIGBUS instead of SIGSEGV.
      38             : #if V8_OS_MACOSX
      39             :   struct sigaction old_bus_action_;
      40             : #endif
      41             : 
      42             :  protected:
      43           1 :   void SetUp() override {
      44             :     struct sigaction action;
      45           1 :     action.sa_sigaction = SignalHandler;
      46           1 :     sigemptyset(&action.sa_mask);
      47           1 :     action.sa_flags = SA_SIGINFO;
      48           1 :     sigaction(SIGSEGV, &action, &old_action_);
      49             : #if V8_OS_MACOSX
      50             :     sigaction(SIGBUS, &action, &old_bus_action_);
      51             : #endif
      52           1 :   }
      53             : 
      54           1 :   void TearDown() override {
      55             :     // Be a good citizen and restore the old signal handler.
      56           1 :     sigaction(SIGSEGV, &old_action_, nullptr);
      57             : #if V8_OS_MACOSX
      58             :     sigaction(SIGBUS, &old_bus_action_, nullptr);
      59             : #endif
      60           1 :   }
      61             : 
      62             :  public:
      63             :   static sigjmp_buf continuation_;
      64             : 
      65             :   enum class MemoryAction { kRead, kWrite };
      66             : 
      67          10 :   void ProbeMemory(volatile int* buffer, MemoryAction action,
      68             :                    bool should_succeed) {
      69             :     const int save_sigs = 1;
      70          10 :     if (!sigsetjmp(continuation_, save_sigs)) {
      71           6 :       switch (action) {
      72             :         case MemoryAction::kRead: {
      73             :           // static_cast to remove the reference and force a memory read.
      74           5 :           USE(static_cast<int>(*buffer));
      75           5 :           break;
      76             :         }
      77             :         case MemoryAction::kWrite: {
      78           5 :           *buffer = 0;
      79           5 :           break;
      80             :         }
      81             :       }
      82           6 :       if (should_succeed) {
      83          12 :         SUCCEED();
      84             :       } else {
      85           0 :         FAIL();
      86             :       }
      87           6 :       return;
      88             :     }
      89           4 :     if (should_succeed) {
      90           0 :       FAIL();
      91             :     } else {
      92           8 :       SUCCEED();
      93             :     }
      94             :   }
      95             : 
      96           5 :   void TestPermissions(PageAllocator::Permission permission, bool can_read,
      97             :                        bool can_write) {
      98             :     v8::PageAllocator* page_allocator =
      99           5 :         v8::internal::GetPlatformPageAllocator();
     100           5 :     const size_t page_size = page_allocator->AllocatePageSize();
     101             :     int* buffer = static_cast<int*>(AllocatePages(
     102           5 :         page_allocator, nullptr, page_size, page_size, permission));
     103           5 :     ProbeMemory(buffer, MemoryAction::kRead, can_read);
     104           5 :     ProbeMemory(buffer, MemoryAction::kWrite, can_write);
     105           5 :     CHECK(FreePages(page_allocator, buffer, page_size));
     106           5 :   }
     107             : };
     108             : 
     109             : sigjmp_buf MemoryAllocationPermissionsTest::continuation_;
     110             : 
     111             : }  // namespace
     112             : 
     113       15444 : TEST_F(MemoryAllocationPermissionsTest, DoTest) {
     114           1 :   TestPermissions(PageAllocator::Permission::kNoAccess, false, false);
     115           1 :   TestPermissions(PageAllocator::Permission::kRead, true, false);
     116           1 :   TestPermissions(PageAllocator::Permission::kReadWrite, true, true);
     117           1 :   TestPermissions(PageAllocator::Permission::kReadWriteExecute, true, true);
     118           1 :   TestPermissions(PageAllocator::Permission::kReadExecute, true, false);
     119           1 : }
     120             : #endif  // V8_OS_POSIX
     121             : 
     122             : // Basic tests of allocation.
     123             : 
     124             : class AllocationTest : public ::testing::Test {};
     125             : 
     126       15443 : TEST(AllocationTest, AllocateAndFree) {
     127           1 :   size_t page_size = v8::internal::AllocatePageSize();
     128           1 :   CHECK_NE(0, page_size);
     129             : 
     130           1 :   v8::PageAllocator* page_allocator = v8::internal::GetPlatformPageAllocator();
     131             : 
     132             :   // A large allocation, aligned at native allocation granularity.
     133             :   const size_t kAllocationSize = 1 * v8::internal::MB;
     134           1 :   void* mem_addr = v8::internal::AllocatePages(
     135           1 :       page_allocator, page_allocator->GetRandomMmapAddr(), kAllocationSize,
     136           1 :       page_size, PageAllocator::Permission::kReadWrite);
     137           1 :   CHECK_NOT_NULL(mem_addr);
     138           1 :   CHECK(v8::internal::FreePages(page_allocator, mem_addr, kAllocationSize));
     139             : 
     140             :   // A large allocation, aligned significantly beyond native granularity.
     141             :   const size_t kBigAlignment = 64 * v8::internal::MB;
     142           1 :   void* aligned_mem_addr = v8::internal::AllocatePages(
     143             :       page_allocator,
     144           1 :       AlignedAddress(page_allocator->GetRandomMmapAddr(), kBigAlignment),
     145           1 :       kAllocationSize, kBigAlignment, PageAllocator::Permission::kReadWrite);
     146           1 :   CHECK_NOT_NULL(aligned_mem_addr);
     147           1 :   CHECK_EQ(aligned_mem_addr, AlignedAddress(aligned_mem_addr, kBigAlignment));
     148           1 :   CHECK(v8::internal::FreePages(page_allocator, aligned_mem_addr,
     149             :                                 kAllocationSize));
     150           1 : }
     151             : 
     152       15443 : TEST(AllocationTest, ReserveMemory) {
     153           1 :   v8::PageAllocator* page_allocator = v8::internal::GetPlatformPageAllocator();
     154           1 :   size_t page_size = v8::internal::AllocatePageSize();
     155             :   const size_t kAllocationSize = 1 * v8::internal::MB;
     156           1 :   void* mem_addr = v8::internal::AllocatePages(
     157           1 :       page_allocator, page_allocator->GetRandomMmapAddr(), kAllocationSize,
     158           1 :       page_size, PageAllocator::Permission::kReadWrite);
     159           1 :   CHECK_NE(0, page_size);
     160           1 :   CHECK_NOT_NULL(mem_addr);
     161           1 :   size_t commit_size = page_allocator->CommitPageSize();
     162           1 :   CHECK(v8::internal::SetPermissions(page_allocator, mem_addr, commit_size,
     163             :                                      PageAllocator::Permission::kReadWrite));
     164             :   // Check whether we can write to memory.
     165             :   int* addr = static_cast<int*>(mem_addr);
     166           1 :   addr[v8::internal::KB - 1] = 2;
     167           1 :   CHECK(v8::internal::SetPermissions(page_allocator, mem_addr, commit_size,
     168             :                                      PageAllocator::Permission::kNoAccess));
     169           1 :   CHECK(v8::internal::FreePages(page_allocator, mem_addr, kAllocationSize));
     170           1 : }
     171             : 
     172             : }  // namespace internal
     173        9264 : }  // namespace v8

Generated by: LCOV version 1.10