mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-27 02:29:35 +00:00
191 lines
4.9 KiB
C++
191 lines
4.9 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
*/
|
|
|
|
#ifdef XP_UNIX
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "jsfriendapi.h"
|
|
#include "js/StructuredClone.h"
|
|
#include "jsapi-tests/tests.h"
|
|
#include "vm/ArrayBufferObject.h"
|
|
|
|
const char test_data[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
const char test_filename[] = "temp-bug945152_MappedArrayBuffer";
|
|
|
|
BEGIN_TEST(testMappedArrayBuffer_bug945152)
|
|
{
|
|
TempFile test_file;
|
|
FILE* test_stream = test_file.open(test_filename);
|
|
CHECK(fputs(test_data, test_stream) != EOF);
|
|
test_file.close();
|
|
|
|
// Offset 0.
|
|
CHECK(TestCreateObject(0, 12));
|
|
|
|
// Aligned offset.
|
|
CHECK(TestCreateObject(8, 12));
|
|
|
|
// Unaligned offset.
|
|
CHECK(CreateNewObject(11, 12) == nullptr);
|
|
|
|
// Offset + length greater than file size.
|
|
CHECK(CreateNewObject(8, sizeof(test_data) - 7) == nullptr);
|
|
|
|
// Release the mapped content.
|
|
CHECK(TestReleaseContents());
|
|
|
|
// Neuter mapped array buffer.
|
|
CHECK(TestNeuterObject());
|
|
|
|
// Clone mapped array buffer.
|
|
CHECK(TestCloneObject());
|
|
|
|
// Steal mapped array buffer contents.
|
|
CHECK(TestStealContents());
|
|
|
|
// Transfer mapped array buffer contents.
|
|
CHECK(TestTransferObject());
|
|
|
|
test_file.remove();
|
|
|
|
return true;
|
|
}
|
|
|
|
JSObject* CreateNewObject(const int offset, const int length)
|
|
{
|
|
int fd = open(test_filename, O_RDONLY);
|
|
void* ptr = JS_CreateMappedArrayBufferContents(fd, offset, length);
|
|
close(fd);
|
|
if (!ptr)
|
|
return nullptr;
|
|
JSObject* obj = JS_NewMappedArrayBufferWithContents(cx, length, ptr);
|
|
if (!obj) {
|
|
JS_ReleaseMappedArrayBufferContents(ptr, length);
|
|
return nullptr;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
bool VerifyObject(JS::HandleObject obj, uint32_t offset, uint32_t length, const bool mapped)
|
|
{
|
|
JS::AutoCheckCannotGC nogc;
|
|
|
|
CHECK(obj);
|
|
CHECK(JS_IsArrayBufferObject(obj));
|
|
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length);
|
|
if (mapped)
|
|
CHECK(JS_IsMappedArrayBufferObject(obj));
|
|
else
|
|
CHECK(!JS_IsMappedArrayBufferObject(obj));
|
|
bool sharedDummy;
|
|
const char* data =
|
|
reinterpret_cast<const char*>(JS_GetArrayBufferData(obj, &sharedDummy, nogc));
|
|
CHECK(data);
|
|
CHECK(memcmp(data, test_data + offset, length) == 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TestCreateObject(uint32_t offset, uint32_t length)
|
|
{
|
|
JS::RootedObject obj(cx, CreateNewObject(offset, length));
|
|
CHECK(VerifyObject(obj, offset, length, true));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TestReleaseContents()
|
|
{
|
|
int fd = open(test_filename, O_RDONLY);
|
|
void* ptr = JS_CreateMappedArrayBufferContents(fd, 0, 12);
|
|
close(fd);
|
|
if (!ptr)
|
|
return false;
|
|
JS_ReleaseMappedArrayBufferContents(ptr, 12);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TestNeuterObject()
|
|
{
|
|
JS::RootedObject obj(cx, CreateNewObject(8, 12));
|
|
CHECK(obj);
|
|
JS_NeuterArrayBuffer(cx, obj, ChangeData);
|
|
CHECK(isNeutered(obj));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TestCloneObject()
|
|
{
|
|
JS::RootedObject obj1(cx, CreateNewObject(8, 12));
|
|
CHECK(obj1);
|
|
JSAutoStructuredCloneBuffer cloned_buffer;
|
|
JS::RootedValue v1(cx, JS::ObjectValue(*obj1));
|
|
CHECK(cloned_buffer.write(cx, v1, nullptr, nullptr));
|
|
JS::RootedValue v2(cx);
|
|
CHECK(cloned_buffer.read(cx, &v2, nullptr, nullptr));
|
|
JS::RootedObject obj2(cx, v2.toObjectOrNull());
|
|
CHECK(VerifyObject(obj2, 8, 12, false));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TestStealContents()
|
|
{
|
|
JS::RootedObject obj(cx, CreateNewObject(8, 12));
|
|
CHECK(obj);
|
|
void* contents = JS_StealArrayBufferContents(cx, obj);
|
|
CHECK(contents);
|
|
CHECK(memcmp(contents, test_data + 8, 12) == 0);
|
|
CHECK(isNeutered(obj));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TestTransferObject()
|
|
{
|
|
JS::RootedObject obj1(cx, CreateNewObject(8, 12));
|
|
CHECK(obj1);
|
|
JS::RootedValue v1(cx, JS::ObjectValue(*obj1));
|
|
|
|
// Create an Array of transferable values.
|
|
JS::AutoValueVector argv(cx);
|
|
argv.append(v1);
|
|
JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::subarray(argv, 0, 1)));
|
|
CHECK(obj);
|
|
JS::RootedValue transferable(cx, JS::ObjectValue(*obj));
|
|
|
|
JSAutoStructuredCloneBuffer cloned_buffer;
|
|
CHECK(cloned_buffer.write(cx, v1, transferable, nullptr, nullptr));
|
|
JS::RootedValue v2(cx);
|
|
CHECK(cloned_buffer.read(cx, &v2, nullptr, nullptr));
|
|
JS::RootedObject obj2(cx, v2.toObjectOrNull());
|
|
CHECK(VerifyObject(obj2, 8, 12, true));
|
|
CHECK(isNeutered(obj1));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool isNeutered(JS::HandleObject obj)
|
|
{
|
|
JS::RootedValue v(cx);
|
|
return JS_GetProperty(cx, obj, "byteLength", &v) && v.toInt32() == 0;
|
|
}
|
|
|
|
static void GC(JSContext* cx)
|
|
{
|
|
JS_GC(JS_GetRuntime(cx));
|
|
// Trigger another to wait for background finalization to end.
|
|
JS_GC(JS_GetRuntime(cx));
|
|
}
|
|
|
|
END_TEST(testMappedArrayBuffer_bug945152)
|
|
#endif
|