tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

testMappedArrayBuffer.cpp (5330B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 */
      4 
      5 #include <fcntl.h>
      6 #include <stdio.h>
      7 
      8 #include "js/Array.h"        // JS::NewArrayObject
      9 #include "js/ArrayBuffer.h"  // JS::{{Create,Release}MappedArrayBufferContents,DetachArrayBuffer,GetArrayBuffer{ByteLength,Data},Is{,Detached,Mapped}ArrayBufferObject,NewMappedArrayBufferWithContents,StealArrayBufferContents}
     10 #include "js/StructuredClone.h"
     11 #include "jsapi-tests/tests.h"
     12 #include "vm/ArrayBufferObject.h"
     13 
     14 #ifdef XP_WIN
     15 #  include <io.h>
     16 #  define GET_OS_FD(a) int(_get_osfhandle(a))
     17 #else
     18 #  include <unistd.h>
     19 #  define GET_OS_FD(a) (a)
     20 #endif
     21 
     22 const char test_data[] =
     23    "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     24 const char test_filename[] = "temp-bug945152_MappedArrayBuffer";
     25 
     26 BEGIN_TEST(testMappedArrayBuffer_bug945152) {
     27  TempFile test_file;
     28  FILE* test_stream = test_file.open(test_filename);
     29  CHECK(fputs(test_data, test_stream) != EOF);
     30  test_file.close();
     31 
     32  // Offset 0.
     33  CHECK(TestCreateObject(0, 12));
     34 
     35  // Aligned offset.
     36  CHECK(TestCreateObject(8, 12));
     37 
     38  // Unaligned offset.
     39  CHECK(CreateNewObject(11, 12) == nullptr);
     40 
     41  // Offset + length greater than file size.
     42  CHECK(CreateNewObject(8, sizeof(test_data) - 7) == nullptr);
     43 
     44  // Release the mapped content.
     45  CHECK(TestReleaseContents());
     46 
     47  // Detach mapped array buffer.
     48  CHECK(TestDetachObject());
     49 
     50  // Clone mapped array buffer.
     51  CHECK(TestCloneObject());
     52 
     53  // Steal mapped array buffer contents.
     54  CHECK(TestStealContents());
     55 
     56  // Transfer mapped array buffer contents.
     57  CHECK(TestTransferObject());
     58 
     59  // GC so we can remove the file we created.
     60  GC(cx);
     61 
     62  test_file.remove();
     63 
     64  return true;
     65 }
     66 
     67 JSObject* CreateNewObject(const int offset, const int length) {
     68  int fd = open(test_filename, O_RDONLY);
     69  void* ptr =
     70      JS::CreateMappedArrayBufferContents(GET_OS_FD(fd), offset, length);
     71  close(fd);
     72  if (!ptr) {
     73    return nullptr;
     74  }
     75  JSObject* obj = JS::NewMappedArrayBufferWithContents(cx, length, ptr);
     76  if (!obj) {
     77    JS::ReleaseMappedArrayBufferContents(ptr, length);
     78    return nullptr;
     79  }
     80  return obj;
     81 }
     82 
     83 bool VerifyObject(JS::HandleObject obj, uint32_t offset, uint32_t length,
     84                  const bool mapped) {
     85  JS::AutoCheckCannotGC nogc;
     86 
     87  CHECK(obj);
     88  CHECK(JS::IsArrayBufferObject(obj));
     89  CHECK_EQUAL(JS::GetArrayBufferByteLength(obj), length);
     90  if (mapped) {
     91    CHECK(JS::IsMappedArrayBufferObject(obj));
     92  } else {
     93    CHECK(!JS::IsMappedArrayBufferObject(obj));
     94  }
     95  bool sharedDummy;
     96  const char* data = reinterpret_cast<const char*>(
     97      JS::GetArrayBufferData(obj, &sharedDummy, nogc));
     98  CHECK(data);
     99  CHECK(memcmp(data, test_data + offset, length) == 0);
    100 
    101  return true;
    102 }
    103 
    104 bool TestCreateObject(uint32_t offset, uint32_t length) {
    105  JS::RootedObject obj(cx, CreateNewObject(offset, length));
    106  CHECK(VerifyObject(obj, offset, length, true));
    107 
    108  return true;
    109 }
    110 
    111 bool TestReleaseContents() {
    112  int fd = open(test_filename, O_RDONLY);
    113  void* ptr = JS::CreateMappedArrayBufferContents(GET_OS_FD(fd), 0, 12);
    114  close(fd);
    115  if (!ptr) {
    116    return false;
    117  }
    118  JS::ReleaseMappedArrayBufferContents(ptr, 12);
    119 
    120  return true;
    121 }
    122 
    123 bool TestDetachObject() {
    124  JS::RootedObject obj(cx, CreateNewObject(8, 12));
    125  CHECK(obj);
    126  JS::DetachArrayBuffer(cx, obj);
    127  CHECK(JS::IsDetachedArrayBufferObject(obj));
    128 
    129  return true;
    130 }
    131 
    132 bool TestCloneObject() {
    133  JS::RootedObject obj1(cx, CreateNewObject(8, 12));
    134  CHECK(obj1);
    135  JSAutoStructuredCloneBuffer cloned_buffer(
    136      JS::StructuredCloneScope::SameProcess, nullptr, nullptr);
    137  JS::RootedValue v1(cx, JS::ObjectValue(*obj1));
    138  CHECK(cloned_buffer.write(cx, v1, nullptr, nullptr));
    139  JS::RootedValue v2(cx);
    140  CHECK(cloned_buffer.read(cx, &v2, JS::CloneDataPolicy(), nullptr, nullptr));
    141  JS::RootedObject obj2(cx, v2.toObjectOrNull());
    142  CHECK(VerifyObject(obj2, 8, 12, false));
    143 
    144  return true;
    145 }
    146 
    147 bool TestStealContents() {
    148  JS::RootedObject obj(cx, CreateNewObject(8, 12));
    149  CHECK(obj);
    150  void* contents = JS::StealArrayBufferContents(cx, obj);
    151  CHECK(contents);
    152  CHECK(memcmp(contents, test_data + 8, 12) == 0);
    153  CHECK(JS::IsDetachedArrayBufferObject(obj));
    154 
    155  return true;
    156 }
    157 
    158 bool TestTransferObject() {
    159  JS::RootedObject obj1(cx, CreateNewObject(8, 12));
    160  CHECK(obj1);
    161  JS::RootedValue v1(cx, JS::ObjectValue(*obj1));
    162 
    163  // Create an Array of transferable values.
    164  JS::RootedValueVector argv(cx);
    165  if (!argv.append(v1)) {
    166    return false;
    167  }
    168 
    169  JS::RootedObject obj(
    170      cx, JS::NewArrayObject(cx, JS::HandleValueArray::subarray(argv, 0, 1)));
    171  CHECK(obj);
    172  JS::RootedValue transferable(cx, JS::ObjectValue(*obj));
    173 
    174  JSAutoStructuredCloneBuffer cloned_buffer(
    175      JS::StructuredCloneScope::SameProcess, nullptr, nullptr);
    176  JS::CloneDataPolicy policy;
    177  CHECK(cloned_buffer.write(cx, v1, transferable, policy, nullptr, nullptr));
    178  JS::RootedValue v2(cx);
    179  CHECK(cloned_buffer.read(cx, &v2, policy, nullptr, nullptr));
    180  JS::RootedObject obj2(cx, v2.toObjectOrNull());
    181  CHECK(VerifyObject(obj2, 8, 12, true));
    182  CHECK(JS::IsDetachedArrayBufferObject(obj1));
    183 
    184  return true;
    185 }
    186 
    187 static void GC(JSContext* cx) {
    188  JS_GC(cx);
    189  // Trigger another to wait for background finalization to end.
    190  JS_GC(cx);
    191 }
    192 
    193 END_TEST(testMappedArrayBuffer_bug945152)
    194 
    195 #undef GET_OS_FD