Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 */
5 #ifdef XP_UNIX
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
13 #include "jsfriendapi.h"
14 #include "js/StructuredClone.h"
15 #include "jsapi-tests/tests.h"
16 #include "vm/ArrayBufferObject.h"
18 const char test_data[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
19 const char test_filename[] = "temp-bug945152_MappedArrayBuffer";
21 BEGIN_TEST(testMappedArrayBuffer_bug945152)
22 {
23 TempFile test_file;
24 FILE *test_stream = test_file.open(test_filename);
25 CHECK(fputs(test_data, test_stream) != EOF);
26 test_file.close();
28 // Offset 0.
29 CHECK(TestCreateObject(0, 12));
31 // Aligned offset.
32 CHECK(TestCreateObject(8, 12));
34 // Unaligned offset.
35 CHECK(CreateNewObject(11, 12) == nullptr);
37 // Offset + length greater than file size.
38 CHECK(CreateNewObject(8, sizeof(test_data) - 7) == nullptr);
40 // Release the mapped content.
41 CHECK(TestReleaseContents());
43 // Neuter mapped array buffer.
44 CHECK(TestNeuterObject());
46 // Clone mapped array buffer.
47 CHECK(TestCloneObject());
49 // Steal mapped array buffer contents.
50 CHECK(TestStealContents());
52 // Transfer mapped array buffer contents.
53 CHECK(TestTransferObject());
55 test_file.remove();
57 return true;
58 }
60 JSObject *CreateNewObject(const int offset, const int length)
61 {
62 int fd = open(test_filename, O_RDONLY);
63 void *ptr = JS_CreateMappedArrayBufferContents(fd, offset, length);
64 close(fd);
65 if (!ptr)
66 return nullptr;
67 JSObject *obj = JS_NewMappedArrayBufferWithContents(cx, length, ptr);
68 if (!obj) {
69 JS_ReleaseMappedArrayBufferContents(ptr, length);
70 return nullptr;
71 }
72 return obj;
73 }
75 bool VerifyObject(JS::HandleObject obj, const int offset, const int length, const bool mapped)
76 {
77 CHECK(obj);
78 CHECK(JS_IsArrayBufferObject(obj));
79 CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length);
80 if (mapped)
81 CHECK(JS_IsMappedArrayBufferObject(obj));
82 else
83 CHECK(!JS_IsMappedArrayBufferObject(obj));
84 const char *data = reinterpret_cast<const char *>(JS_GetArrayBufferData(obj));
85 CHECK(data);
86 CHECK(memcmp(data, test_data + offset, length) == 0);
88 return true;
89 }
91 bool TestCreateObject(const int offset, const int length)
92 {
93 JS::RootedObject obj(cx, CreateNewObject(offset, length));
94 CHECK(VerifyObject(obj, offset, length, true));
96 return true;
97 }
99 bool TestReleaseContents()
100 {
101 int fd = open(test_filename, O_RDONLY);
102 void *ptr = JS_CreateMappedArrayBufferContents(fd, 0, 12);
103 close(fd);
104 if (!ptr)
105 return false;
106 JS_ReleaseMappedArrayBufferContents(ptr, 12);
108 return true;
109 }
111 bool TestNeuterObject()
112 {
113 JS::RootedObject obj(cx, CreateNewObject(8, 12));
114 CHECK(obj);
115 JS_NeuterArrayBuffer(cx, obj, ChangeData);
116 CHECK(isNeutered(obj));
118 return true;
119 }
121 bool TestCloneObject()
122 {
123 JS::RootedObject obj1(cx, CreateNewObject(8, 12));
124 CHECK(obj1);
125 JSAutoStructuredCloneBuffer cloned_buffer;
126 JS::RootedValue v1(cx, OBJECT_TO_JSVAL(obj1));
127 const JSStructuredCloneCallbacks *callbacks = js::GetContextStructuredCloneCallbacks(cx);
128 CHECK(cloned_buffer.write(cx, v1, callbacks, nullptr));
129 JS::RootedValue v2(cx);
130 CHECK(cloned_buffer.read(cx, &v2, callbacks, nullptr));
131 JS::RootedObject obj2(cx, JSVAL_TO_OBJECT(v2));
132 CHECK(VerifyObject(obj2, 8, 12, false));
134 return true;
135 }
137 bool TestStealContents()
138 {
139 JS::RootedObject obj(cx, CreateNewObject(8, 12));
140 CHECK(obj);
141 void *contents = JS_StealArrayBufferContents(cx, obj);
142 CHECK(contents);
143 CHECK(memcmp(contents, test_data + 8, 12) == 0);
144 CHECK(isNeutered(obj));
146 return true;
147 }
149 bool TestTransferObject()
150 {
151 JS::RootedObject obj1(cx, CreateNewObject(8, 12));
152 CHECK(obj1);
153 JS::RootedValue v1(cx, OBJECT_TO_JSVAL(obj1));
155 // Create an Array of transferable values.
156 JS::AutoValueVector argv(cx);
157 argv.append(v1);
158 JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::subarray(argv, 0, 1)));
159 CHECK(obj);
160 JS::RootedValue transferable(cx, OBJECT_TO_JSVAL(obj));
162 JSAutoStructuredCloneBuffer cloned_buffer;
163 const JSStructuredCloneCallbacks *callbacks = js::GetContextStructuredCloneCallbacks(cx);
164 CHECK(cloned_buffer.write(cx, v1, transferable, callbacks, nullptr));
165 JS::RootedValue v2(cx);
166 CHECK(cloned_buffer.read(cx, &v2, callbacks, nullptr));
167 JS::RootedObject obj2(cx, JSVAL_TO_OBJECT(v2));
168 CHECK(VerifyObject(obj2, 8, 12, true));
169 CHECK(isNeutered(obj1));
171 return true;
172 }
174 bool isNeutered(JS::HandleObject obj)
175 {
176 JS::RootedValue v(cx);
177 return JS_GetProperty(cx, obj, "byteLength", &v) && v.toInt32() == 0;
178 }
180 static void GC(JSContext *cx)
181 {
182 JS_GC(JS_GetRuntime(cx));
183 // Trigger another to wait for background finalization to end.
184 JS_GC(JS_GetRuntime(cx));
185 }
187 END_TEST(testMappedArrayBuffer_bug945152)
188 #endif