| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "gin/array_buffer.h" |
| #include "build/build_config.h" |
| #include "gin/per_isolate_data.h" |
| #include "gin/public/isolate_holder.h" |
| #include "gin/test/v8_test.h" |
| |
| #if defined(OS_POSIX) |
| #include <setjmp.h> |
| #include <signal.h> |
| #endif |
| |
| namespace gin { |
| |
| using ArrayBufferTest = V8Test; |
| |
| namespace { |
| const size_t kBufferLength = 65536; |
| } |
| |
| TEST_F(ArrayBufferTest, AllocateAndFreeBuffer) { |
| v8::Isolate* const isolate = instance_->isolate(); |
| v8::ArrayBuffer::Allocator* const allocator = |
| PerIsolateData::From(isolate)->allocator(); |
| |
| void* buffer = allocator->Allocate(kBufferLength); |
| allocator->Free(buffer, kBufferLength); |
| } |
| |
| TEST_F(ArrayBufferTest, ReserveAndReleaseBuffer) { |
| v8::Isolate* const isolate = instance_->isolate(); |
| v8::ArrayBuffer::Allocator* const allocator = |
| PerIsolateData::From(isolate)->allocator(); |
| |
| void* buffer = allocator->Reserve(kBufferLength); |
| allocator->Free(buffer, kBufferLength, |
| v8::ArrayBuffer::Allocator::AllocationMode::kReservation); |
| } |
| |
| TEST_F(ArrayBufferTest, SetProtectionReadWrite) { |
| v8::Isolate* const isolate = instance_->isolate(); |
| v8::ArrayBuffer::Allocator* const allocator = |
| PerIsolateData::From(isolate)->allocator(); |
| |
| void* buffer = allocator->Reserve(kBufferLength); |
| allocator->SetProtection(buffer, kBufferLength, |
| v8::ArrayBuffer::Allocator::Protection::kReadWrite); |
| volatile int* int_buffer = static_cast<volatile int*>(buffer); |
| // Try assigning to the buffer. This will fault if we don't SetProtection |
| // first. |
| int_buffer[0] = 42; |
| allocator->Free(buffer, kBufferLength, |
| v8::ArrayBuffer::Allocator::AllocationMode::kReservation); |
| } |
| |
| #if defined(OS_POSIX) |
| |
| namespace { |
| sigjmp_buf g_continuation_; |
| |
| void SignalHandler(int signal, siginfo_t* info, void*) { |
| siglongjmp(g_continuation_, 1); |
| } |
| } // namespace |
| |
| TEST_F(ArrayBufferTest, ReservationReadOnlyByDefault) { |
| v8::Isolate* const isolate = instance_->isolate(); |
| v8::ArrayBuffer::Allocator* const allocator = |
| PerIsolateData::From(isolate)->allocator(); |
| |
| void* buffer = allocator->Reserve(kBufferLength); |
| volatile int* int_buffer = static_cast<volatile int*>(buffer); |
| |
| // Install a signal handler so we can catch the fault we're about to trigger. |
| struct sigaction action = {}; |
| struct sigaction old_action = {}; |
| action.sa_sigaction = SignalHandler; |
| sigemptyset(&action.sa_mask); |
| action.sa_flags = SA_SIGINFO; |
| sigaction(SIGSEGV, &action, &old_action); |
| #if defined(OS_MACOSX) |
| // On Mac, sometimes we get SIGBUS instead of SIGSEGV. |
| struct sigaction old_bus_action; |
| sigaction(SIGBUS, &action, &old_bus_action); |
| #endif |
| |
| int const save_sigs = 1; |
| if (!sigsetjmp(g_continuation_, save_sigs)) { |
| // Try assigning to the buffer. This will fault if we don't SetProtection |
| // first. |
| int_buffer[0] = 42; |
| } else { |
| // if sigsetjmp returns nonzero, then we are returning from our handler. |
| |
| sigaction(SIGSEGV, &old_action, nullptr); |
| #if defined(OS_MACOSX) |
| sigaction(SIGBUS, &old_bus_action, nullptr); |
| #endif |
| |
| allocator->Free(buffer, kBufferLength, |
| v8::ArrayBuffer::Allocator::AllocationMode::kReservation); |
| SUCCEED(); |
| return; |
| } |
| |
| FAIL(); |
| } |
| |
| #endif // OS_POSIX |
| |
| } // namespace gin |