1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsapi-tests/testMappedArrayBuffer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,188 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + */ 1.7 + 1.8 +#ifdef XP_UNIX 1.9 +#include <fcntl.h> 1.10 +#include <stdio.h> 1.11 +#include <string.h> 1.12 +#include <sys/stat.h> 1.13 +#include <sys/types.h> 1.14 +#include <unistd.h> 1.15 + 1.16 +#include "jsfriendapi.h" 1.17 +#include "js/StructuredClone.h" 1.18 +#include "jsapi-tests/tests.h" 1.19 +#include "vm/ArrayBufferObject.h" 1.20 + 1.21 +const char test_data[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 1.22 +const char test_filename[] = "temp-bug945152_MappedArrayBuffer"; 1.23 + 1.24 +BEGIN_TEST(testMappedArrayBuffer_bug945152) 1.25 +{ 1.26 + TempFile test_file; 1.27 + FILE *test_stream = test_file.open(test_filename); 1.28 + CHECK(fputs(test_data, test_stream) != EOF); 1.29 + test_file.close(); 1.30 + 1.31 + // Offset 0. 1.32 + CHECK(TestCreateObject(0, 12)); 1.33 + 1.34 + // Aligned offset. 1.35 + CHECK(TestCreateObject(8, 12)); 1.36 + 1.37 + // Unaligned offset. 1.38 + CHECK(CreateNewObject(11, 12) == nullptr); 1.39 + 1.40 + // Offset + length greater than file size. 1.41 + CHECK(CreateNewObject(8, sizeof(test_data) - 7) == nullptr); 1.42 + 1.43 + // Release the mapped content. 1.44 + CHECK(TestReleaseContents()); 1.45 + 1.46 + // Neuter mapped array buffer. 1.47 + CHECK(TestNeuterObject()); 1.48 + 1.49 + // Clone mapped array buffer. 1.50 + CHECK(TestCloneObject()); 1.51 + 1.52 + // Steal mapped array buffer contents. 1.53 + CHECK(TestStealContents()); 1.54 + 1.55 + // Transfer mapped array buffer contents. 1.56 + CHECK(TestTransferObject()); 1.57 + 1.58 + test_file.remove(); 1.59 + 1.60 + return true; 1.61 +} 1.62 + 1.63 +JSObject *CreateNewObject(const int offset, const int length) 1.64 +{ 1.65 + int fd = open(test_filename, O_RDONLY); 1.66 + void *ptr = JS_CreateMappedArrayBufferContents(fd, offset, length); 1.67 + close(fd); 1.68 + if (!ptr) 1.69 + return nullptr; 1.70 + JSObject *obj = JS_NewMappedArrayBufferWithContents(cx, length, ptr); 1.71 + if (!obj) { 1.72 + JS_ReleaseMappedArrayBufferContents(ptr, length); 1.73 + return nullptr; 1.74 + } 1.75 + return obj; 1.76 +} 1.77 + 1.78 +bool VerifyObject(JS::HandleObject obj, const int offset, const int length, const bool mapped) 1.79 +{ 1.80 + CHECK(obj); 1.81 + CHECK(JS_IsArrayBufferObject(obj)); 1.82 + CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length); 1.83 + if (mapped) 1.84 + CHECK(JS_IsMappedArrayBufferObject(obj)); 1.85 + else 1.86 + CHECK(!JS_IsMappedArrayBufferObject(obj)); 1.87 + const char *data = reinterpret_cast<const char *>(JS_GetArrayBufferData(obj)); 1.88 + CHECK(data); 1.89 + CHECK(memcmp(data, test_data + offset, length) == 0); 1.90 + 1.91 + return true; 1.92 +} 1.93 + 1.94 +bool TestCreateObject(const int offset, const int length) 1.95 +{ 1.96 + JS::RootedObject obj(cx, CreateNewObject(offset, length)); 1.97 + CHECK(VerifyObject(obj, offset, length, true)); 1.98 + 1.99 + return true; 1.100 +} 1.101 + 1.102 +bool TestReleaseContents() 1.103 +{ 1.104 + int fd = open(test_filename, O_RDONLY); 1.105 + void *ptr = JS_CreateMappedArrayBufferContents(fd, 0, 12); 1.106 + close(fd); 1.107 + if (!ptr) 1.108 + return false; 1.109 + JS_ReleaseMappedArrayBufferContents(ptr, 12); 1.110 + 1.111 + return true; 1.112 +} 1.113 + 1.114 +bool TestNeuterObject() 1.115 +{ 1.116 + JS::RootedObject obj(cx, CreateNewObject(8, 12)); 1.117 + CHECK(obj); 1.118 + JS_NeuterArrayBuffer(cx, obj, ChangeData); 1.119 + CHECK(isNeutered(obj)); 1.120 + 1.121 + return true; 1.122 +} 1.123 + 1.124 +bool TestCloneObject() 1.125 +{ 1.126 + JS::RootedObject obj1(cx, CreateNewObject(8, 12)); 1.127 + CHECK(obj1); 1.128 + JSAutoStructuredCloneBuffer cloned_buffer; 1.129 + JS::RootedValue v1(cx, OBJECT_TO_JSVAL(obj1)); 1.130 + const JSStructuredCloneCallbacks *callbacks = js::GetContextStructuredCloneCallbacks(cx); 1.131 + CHECK(cloned_buffer.write(cx, v1, callbacks, nullptr)); 1.132 + JS::RootedValue v2(cx); 1.133 + CHECK(cloned_buffer.read(cx, &v2, callbacks, nullptr)); 1.134 + JS::RootedObject obj2(cx, JSVAL_TO_OBJECT(v2)); 1.135 + CHECK(VerifyObject(obj2, 8, 12, false)); 1.136 + 1.137 + return true; 1.138 +} 1.139 + 1.140 +bool TestStealContents() 1.141 +{ 1.142 + JS::RootedObject obj(cx, CreateNewObject(8, 12)); 1.143 + CHECK(obj); 1.144 + void *contents = JS_StealArrayBufferContents(cx, obj); 1.145 + CHECK(contents); 1.146 + CHECK(memcmp(contents, test_data + 8, 12) == 0); 1.147 + CHECK(isNeutered(obj)); 1.148 + 1.149 + return true; 1.150 +} 1.151 + 1.152 +bool TestTransferObject() 1.153 +{ 1.154 + JS::RootedObject obj1(cx, CreateNewObject(8, 12)); 1.155 + CHECK(obj1); 1.156 + JS::RootedValue v1(cx, OBJECT_TO_JSVAL(obj1)); 1.157 + 1.158 + // Create an Array of transferable values. 1.159 + JS::AutoValueVector argv(cx); 1.160 + argv.append(v1); 1.161 + JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::subarray(argv, 0, 1))); 1.162 + CHECK(obj); 1.163 + JS::RootedValue transferable(cx, OBJECT_TO_JSVAL(obj)); 1.164 + 1.165 + JSAutoStructuredCloneBuffer cloned_buffer; 1.166 + const JSStructuredCloneCallbacks *callbacks = js::GetContextStructuredCloneCallbacks(cx); 1.167 + CHECK(cloned_buffer.write(cx, v1, transferable, callbacks, nullptr)); 1.168 + JS::RootedValue v2(cx); 1.169 + CHECK(cloned_buffer.read(cx, &v2, callbacks, nullptr)); 1.170 + JS::RootedObject obj2(cx, JSVAL_TO_OBJECT(v2)); 1.171 + CHECK(VerifyObject(obj2, 8, 12, true)); 1.172 + CHECK(isNeutered(obj1)); 1.173 + 1.174 + return true; 1.175 +} 1.176 + 1.177 +bool isNeutered(JS::HandleObject obj) 1.178 +{ 1.179 + JS::RootedValue v(cx); 1.180 + return JS_GetProperty(cx, obj, "byteLength", &v) && v.toInt32() == 0; 1.181 +} 1.182 + 1.183 +static void GC(JSContext *cx) 1.184 +{ 1.185 + JS_GC(JS_GetRuntime(cx)); 1.186 + // Trigger another to wait for background finalization to end. 1.187 + JS_GC(JS_GetRuntime(cx)); 1.188 +} 1.189 + 1.190 +END_TEST(testMappedArrayBuffer_bug945152) 1.191 +#endif