Backed out 7 changesets (bug 1841314) for causing hazard failures. CLOSED TREE

Backed out changeset 82a53d6ea95a (bug 1841314)
Backed out changeset 524607b471a2 (bug 1841314)
Backed out changeset ce128e10bddb (bug 1841314)
Backed out changeset cdae4fbbdaff (bug 1841314)
Backed out changeset f1035b6c08fe (bug 1841314)
Backed out changeset 5897ad8ef181 (bug 1841314)
Backed out changeset 09618a767080 (bug 1841314)
This commit is contained in:
Sandor Molnar 2023-07-06 16:59:47 +03:00
Родитель 0910cc5ba9
Коммит a6c121377b
31 изменённых файлов: 115 добавлений и 249 удалений

Просмотреть файл

@ -651,7 +651,7 @@ void BodyConsumer::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength,
AssertIsOnTargetThread();
// This makes sure that we free the data correctly.
UniquePtr<uint8_t[], JS::FreePolicy> resultPtr{aResult};
auto autoFree = mozilla::MakeScopeExit([&] { free(aResult); });
if (mBodyConsumed) {
return;
@ -689,7 +689,7 @@ void BodyConsumer::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength,
}
// Finish successfully consuming body according to type.
MOZ_ASSERT(resultPtr);
MOZ_ASSERT(aResult);
AutoJSAPI jsapi;
if (!jsapi.Init(mGlobal)) {
@ -703,14 +703,16 @@ void BodyConsumer::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength,
switch (mConsumeType) {
case CONSUME_ARRAYBUFFER: {
JS::Rooted<JSObject*> arrayBuffer(cx);
BodyUtil::ConsumeArrayBuffer(cx, &arrayBuffer, aResultLength,
std::move(resultPtr), error);
BodyUtil::ConsumeArrayBuffer(cx, &arrayBuffer, aResultLength, aResult,
error);
if (!error.Failed()) {
JS::Rooted<JS::Value> val(cx);
val.setObjectOrNull(arrayBuffer);
localPromise->MaybeResolve(val);
// ArrayBuffer takes over ownership.
aResult = nullptr;
}
break;
}
@ -720,7 +722,8 @@ void BodyConsumer::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength,
}
case CONSUME_FORMDATA: {
nsCString data;
data.Adopt(reinterpret_cast<char*>(resultPtr.release()), aResultLength);
data.Adopt(reinterpret_cast<char*>(aResult), aResultLength);
aResult = nullptr;
RefPtr<dom::FormData> fd = BodyUtil::ConsumeFormData(
mGlobal, mBodyMimeType, mMixedCaseMimeType, data, error);
@ -734,7 +737,7 @@ void BodyConsumer::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength,
case CONSUME_JSON: {
nsString decoded;
if (NS_SUCCEEDED(
BodyUtil::ConsumeText(aResultLength, resultPtr.get(), decoded))) {
BodyUtil::ConsumeText(aResultLength, aResult, decoded))) {
if (mConsumeType == CONSUME_TEXT) {
localPromise->MaybeResolve(decoded);
} else {

Просмотреть файл

@ -353,12 +353,11 @@ class MOZ_STACK_CLASS FormDataParser {
// static
void BodyUtil::ConsumeArrayBuffer(JSContext* aCx,
JS::MutableHandle<JSObject*> aValue,
uint32_t aInputLength,
UniquePtr<uint8_t[], JS::FreePolicy> aInput,
uint32_t aInputLength, uint8_t* aInput,
ErrorResult& aRv) {
JS::Rooted<JSObject*> arrayBuffer(aCx);
arrayBuffer =
JS::NewArrayBufferWithContents(aCx, aInputLength, std::move(aInput));
arrayBuffer = JS::NewArrayBufferWithContents(aCx, aInputLength,
reinterpret_cast<void*>(aInput));
if (!arrayBuffer) {
JS_ClearPendingException(aCx);
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);

Просмотреть файл

@ -13,8 +13,6 @@
#include "mozilla/dom/File.h"
#include "mozilla/dom/FormData.h"
#include "js/Utility.h" // JS::FreePolicy
namespace mozilla {
class ErrorResult;
@ -32,8 +30,7 @@ class BodyUtil final {
*/
static void ConsumeArrayBuffer(JSContext* aCx,
JS::MutableHandle<JSObject*> aValue,
uint32_t aInputLength,
UniquePtr<uint8_t[], JS::FreePolicy> aInput,
uint32_t aInputLength, uint8_t* aInput,
ErrorResult& aRv);
/**

Просмотреть файл

@ -108,7 +108,7 @@ class CompressionStreamAlgorithms : public TransformerAlgorithmsWrapper {
do {
static uint16_t kBufferSize = 16384;
UniquePtr<uint8_t[], JS::FreePolicy> buffer(
UniquePtr<uint8_t> buffer(
static_cast<uint8_t*>(JS_malloc(aCx, kBufferSize)));
if (!buffer) {
aRv.ThrowTypeError("Out of memory");
@ -164,8 +164,8 @@ class CompressionStreamAlgorithms : public TransformerAlgorithmsWrapper {
// into Uint8Arrays.
// (The buffer is 'split' by having a fixed sized buffer above.)
JS::Rooted<JSObject*> view(aCx, nsJSUtils::MoveBufferAsUint8Array(
aCx, written, std::move(buffer)));
JS::Rooted<JSObject*> view(
aCx, nsJSUtils::MoveBufferAsUint8Array(aCx, written, buffer));
if (!view || !array.append(view)) {
JS_ClearPendingException(aCx);
aRv.ThrowTypeError("Out of memory");

Просмотреть файл

@ -107,7 +107,7 @@ class DecompressionStreamAlgorithms : public TransformerAlgorithmsWrapper {
do {
static uint16_t kBufferSize = 16384;
UniquePtr<uint8_t[], JS::FreePolicy> buffer(
UniquePtr<uint8_t> buffer(
static_cast<uint8_t*>(JS_malloc(aCx, kBufferSize)));
if (!buffer) {
aRv.ThrowTypeError("Out of memory");
@ -194,8 +194,8 @@ class DecompressionStreamAlgorithms : public TransformerAlgorithmsWrapper {
// into Uint8Arrays.
// (The buffer is 'split' by having a fixed sized buffer above.)
JS::Rooted<JSObject*> view(aCx, nsJSUtils::MoveBufferAsUint8Array(
aCx, written, std::move(buffer)));
JS::Rooted<JSObject*> view(
aCx, nsJSUtils::MoveBufferAsUint8Array(aCx, written, buffer));
if (!view || !array.append(view)) {
JS_ClearPendingException(aCx);
aRv.ThrowTypeError("Out of memory");

Просмотреть файл

@ -186,15 +186,17 @@ bool nsJSUtils::DumpEnabled() {
#endif
}
JSObject* nsJSUtils::MoveBufferAsUint8Array(
JSContext* aCx, size_t aSize,
UniquePtr<uint8_t[], JS::FreePolicy> aBuffer) {
JSObject* nsJSUtils::MoveBufferAsUint8Array(JSContext* aCx, size_t aSize,
UniquePtr<uint8_t>& aBuffer) {
JS::Rooted<JSObject*> arrayBuffer(
aCx, JS::NewArrayBufferWithContents(aCx, aSize, std::move(aBuffer)));
aCx, JS::NewArrayBufferWithContents(aCx, aSize, aBuffer.get()));
if (!arrayBuffer) {
return nullptr;
}
// Now the ArrayBuffer owns the buffer, so let's release our ownership
(void)aBuffer.release();
return JS_NewUint8ArrayWithBuffer(aCx, arrayBuffer, 0,
static_cast<int64_t>(aSize));
}

Просмотреть файл

@ -21,7 +21,6 @@
#include "js/Conversions.h"
#include "js/SourceText.h"
#include "js/String.h" // JS::{,Lossy}CopyLinearStringChars, JS::CopyStringChars, JS::Get{,Linear}StringLength, JS::MaxStringLength, JS::StringHasLatin1Chars
#include "js/Utility.h" // JS::FreePolicy
#include "nsString.h"
#include "xpcpublic.h"
@ -88,9 +87,8 @@ class nsJSUtils {
// Note that the buffer needs to be created by JS_malloc (or at least can be
// freed by JS_free), as the resulting Uint8Array takes the ownership of the
// buffer.
static JSObject* MoveBufferAsUint8Array(
JSContext* aCx, size_t aSize,
mozilla::UniquePtr<uint8_t[], JS::FreePolicy> aBuffer);
static JSObject* MoveBufferAsUint8Array(JSContext* aCx, size_t aSize,
mozilla::UniquePtr<uint8_t>& aBuffer);
};
inline void AssignFromStringBuffer(nsStringBuffer* buffer, size_t len,

Просмотреть файл

@ -68,7 +68,7 @@ static void EncodeNative(JSContext* aCx, mozilla::Decoder* aDecoder,
return;
}
UniquePtr<uint8_t[], JS::FreePolicy> buffer(
UniquePtr<uint8_t> buffer(
static_cast<uint8_t*>(JS_malloc(aCx, needed.value())));
if (!buffer) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
@ -99,7 +99,7 @@ static void EncodeNative(JSContext* aCx, mozilla::Decoder* aDecoder,
// Step 4.2.2.1. Let chunk be a Uint8Array object wrapping an ArrayBuffer
// containing output.
JS::Rooted<JSObject*> arrayBuffer(
aCx, JS::NewArrayBufferWithContents(aCx, written, std::move(buffer)));
aCx, JS::NewArrayBufferWithContents(aCx, written, buffer.release()));
if (!arrayBuffer.get()) {
JS_ClearPendingException(aCx);
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);

Просмотреть файл

@ -201,11 +201,7 @@ void FileReader::OnLoadEndArrayBuffer() {
JSContext* cx = jsapi.cx();
// |mFileData| will be deallocated in FileReader's destructor when this
// ArrayBuffer allocation failed.
mResultArrayBuffer = JS::NewArrayBufferWithContents(
cx, mDataLen, mFileData,
JS::NewArrayBufferOutOfMemory::CallerMustFreeMemory);
mResultArrayBuffer = JS::NewArrayBufferWithContents(cx, mDataLen, mFileData);
if (mResultArrayBuffer) {
mFileData = nullptr; // Transfer ownership
FreeDataAndDispatchSuccess();

Просмотреть файл

@ -85,11 +85,14 @@ void FileReaderSync::ReadAsArrayBuffer(JSContext* aCx,
}
JSObject* arrayBuffer =
JS::NewArrayBufferWithContents(aCx, blobSize, std::move(bufferData));
JS::NewArrayBufferWithContents(aCx, blobSize, bufferData.get());
if (!arrayBuffer) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
// arrayBuffer takes the ownership when it is not null. Otherwise we
// need to release it explicitly.
(void)bufferData.release();
aRetval.set(arrayBuffer);
}

Просмотреть файл

@ -855,19 +855,12 @@ JSObject* Key::DecodeBinary(const EncodedDataType*& aPos,
DecodeStringy<eBinary, uint8_t>(
aPos, aEnd,
[&rv, aCx](uint8_t** out, uint32_t decodedSize) {
UniquePtr<void, JS::FreePolicy> ptr{JS_malloc(aCx, decodedSize)};
if (NS_WARN_IF(!ptr)) {
*out = nullptr;
*out = static_cast<uint8_t*>(JS_malloc(aCx, decodedSize));
if (NS_WARN_IF(!*out)) {
rv = nullptr;
return false;
}
*out = static_cast<uint8_t*>(ptr.get());
rv = JS::NewArrayBufferWithContents(aCx, decodedSize, std::move(ptr));
if (NS_WARN_IF(!rv)) {
*out = nullptr;
return false;
}
rv = JS::NewArrayBufferWithContents(aCx, decodedSize, *out);
return true;
},
[&rv, aCx] { rv = JS::NewArrayBuffer(aCx, 0); });

Просмотреть файл

@ -238,9 +238,8 @@ INSTANTIATE_TEST_SUITE_P(DOM_IndexedDB_Key, TestWithParam_LiteralString,
static JS::Value CreateArrayBufferValue(JSContext* const aContext,
const size_t aSize, char* const aData) {
mozilla::UniquePtr<void, JS::FreePolicy> ptr{aData};
Rooted<JSObject*> arrayBuffer{aContext, JS::NewArrayBufferWithContents(
aContext, aSize, std::move(ptr))};
Rooted<JSObject*> arrayBuffer{
aContext, JS::NewArrayBufferWithContents(aContext, aSize, aData)};
EXPECT_TRUE(arrayBuffer);
return JS::ObjectValue(*arrayBuffer);
}

Просмотреть файл

@ -2166,10 +2166,9 @@ void PeerConnectionImpl::DumpPacket_m(size_t level, dom::mozPacketDumpType type,
return;
}
UniquePtr<void, JS::FreePolicy> packetPtr{packet.release()};
JS::Rooted<JSObject*> jsobj(
jsapi.cx(),
JS::NewArrayBufferWithContents(jsapi.cx(), size, std::move(packetPtr)));
JS::NewArrayBufferWithContents(jsapi.cx(), size, packet.release()));
RootedSpiderMonkeyInterface<ArrayBuffer> arrayBuffer(jsapi.cx());
if (!arrayBuffer.Init(jsobj)) {

Просмотреть файл

@ -33,8 +33,11 @@ bool DeserializeArrayBuffer(JSContext* cx, const nsTArray<uint8_t>& aBuffer,
memcpy(data.get(), aBuffer.Elements(), aBuffer.Length());
JSObject* obj =
JS::NewArrayBufferWithContents(cx, aBuffer.Length(), std::move(data));
JS::NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
if (!obj) return false;
// If JS::NewArrayBufferWithContents returns non-null, the ownership of
// the data is transfered to obj, so we release the ownership here.
mozilla::Unused << data.release();
aVal.setObject(*obj);
return true;

Просмотреть файл

@ -1093,9 +1093,7 @@ void PushMessageData::ArrayBuffer(JSContext* cx,
ErrorResult& aRv) {
uint8_t* data = GetContentsCopy();
if (data) {
UniquePtr<uint8_t[], JS::FreePolicy> dataPtr(data);
BodyUtil::ConsumeArrayBuffer(cx, aRetval, mBytes.Length(),
std::move(dataPtr), aRv);
BodyUtil::ConsumeArrayBuffer(cx, aRetval, mBytes.Length(), data, aRv);
}
}

Просмотреть файл

@ -26,8 +26,7 @@ JSObject* TransferArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aObject) {
size_t bufferLength = JS::GetArrayBufferByteLength(aObject);
// Step 2 (Reordered)
UniquePtr<void, JS::FreePolicy> bufferData{
JS::StealArrayBufferContents(aCx, aObject)};
void* bufferData = JS::StealArrayBufferContents(aCx, aObject);
// Step 4.
if (!JS::DetachArrayBuffer(aCx, aObject)) {
@ -35,8 +34,7 @@ JSObject* TransferArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aObject) {
}
// Step 5.
return JS::NewArrayBufferWithContents(aCx, bufferLength,
std::move(bufferData));
return JS::NewArrayBufferWithContents(aCx, bufferLength, bufferData);
}
// https://streams.spec.whatwg.org/#can-transfer-array-buffer

Просмотреть файл

@ -429,8 +429,7 @@ void InputToReadableStreamAlgorithms::PullFromInputStream(JSContext* aCx,
else {
// Step 9.1. Set view to the result of creating a Uint8Array from pulled in
// streams relevant Realm.
UniquePtr<uint8_t[], JS::FreePolicy> buffer(
static_cast<uint8_t*>(JS_malloc(aCx, pullSize)));
UniquePtr<uint8_t> buffer(static_cast<uint8_t*>(JS_malloc(aCx, pullSize)));
if (!buffer) {
aRv.ThrowTypeError("Out of memory");
return;
@ -447,8 +446,8 @@ void InputToReadableStreamAlgorithms::PullFromInputStream(JSContext* aCx,
}
MOZ_DIAGNOSTIC_ASSERT(pullSize == bytesWritten);
JS::Rooted<JSObject*> view(aCx, nsJSUtils::MoveBufferAsUint8Array(
aCx, bytesWritten, std::move(buffer)));
JS::Rooted<JSObject*> view(
aCx, nsJSUtils::MoveBufferAsUint8Array(aCx, bytesWritten, buffer));
if (!view) {
JS_ClearPendingException(aCx);
aRv.ThrowTypeError("Out of memory");

Просмотреть файл

@ -2708,15 +2708,20 @@ JSObject* IOUtils::JsBuffer::IntoUint8Array(JSContext* aCx, JsBuffer aBuffer) {
return JS_NewUint8Array(aCx, 0);
}
MOZ_RELEASE_ASSERT(aBuffer.mBuffer);
char* rawBuffer = aBuffer.mBuffer.release();
MOZ_RELEASE_ASSERT(rawBuffer);
JS::Rooted<JSObject*> arrayBuffer(
aCx, JS::NewArrayBufferWithContents(aCx, aBuffer.mLength,
std::move(aBuffer.mBuffer)));
reinterpret_cast<void*>(rawBuffer)));
if (!arrayBuffer) {
// The array buffer does not take ownership of the data pointer unless
// creation succeeds. We are still on the hook to free it.
//
// aBuffer will be destructed at end of scope, but its destructor does not
// take into account |mCapacity| or |mLength|, so it is OK for them to be
// non-zero here with a null |mBuffer|.
js_free(rawBuffer);
return nullptr;
}

Просмотреть файл

@ -247,10 +247,8 @@ void Buffer::GetMappedRange(JSContext* aCx, uint64_t aOffset,
std::shared_ptr<ipc::WritableSharedMemoryMapping>* userData =
new std::shared_ptr<ipc::WritableSharedMemoryMapping>(mShmem);
UniquePtr<void, JS::BufferContentsDeleter> dataPtr{
span.data(), {&ExternalBufferFreeCallback, userData}};
auto* const arrayBuffer =
JS::NewExternalArrayBuffer(aCx, size, std::move(dataPtr));
auto* const arrayBuffer = JS::NewExternalArrayBuffer(
aCx, size, span.data(), &ExternalBufferFreeCallback, userData);
if (!arrayBuffer) {
aRv.NoteJSContextException(aCx);

Просмотреть файл

@ -3927,11 +3927,7 @@ JSObject* ArrayBufferBuilder::TakeArrayBuffer(JSContext* aCx) {
}
}
// |mDataPtr| will be deallocated in ArrayBufferBuilder's destructor when this
// ArrayBuffer allocation failed.
JSObject* obj = JS::NewArrayBufferWithContents(
aCx, mLength, mDataPtr,
JS::NewArrayBufferOutOfMemory::CallerMustFreeMemory);
JSObject* obj = JS::NewArrayBufferWithContents(aCx, mLength, mDataPtr);
if (!obj) {
return nullptr;
}

Просмотреть файл

@ -8,14 +8,11 @@
#ifndef js_ArrayBuffer_h
#define js_ArrayBuffer_h
#include "mozilla/UniquePtr.h"
#include <stddef.h> // size_t
#include <stdint.h> // uint32_t
#include "jstypes.h" // JS_PUBLIC_API
#include "js/TypeDecls.h"
#include "js/Utility.h"
struct JS_PUBLIC_API JSContext;
class JS_PUBLIC_API JSObject;
@ -36,77 +33,18 @@ extern JS_PUBLIC_API JSObject* NewArrayBuffer(JSContext* cx, size_t nbytes);
* if |nbytes == 0|. |contents| must be allocated compatible with deallocation
* by |JS_free|.
*
* Care must be taken that |nbytes| bytes of |contents| remain valid for the
* duration of this call. In particular, passing the length/pointer of existing
* typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
* call to this function, it could move those contents to a different location
* and invalidate the provided pointer.
*/
extern JS_PUBLIC_API JSObject* NewArrayBufferWithContents(
JSContext* cx, size_t nbytes,
mozilla::UniquePtr<void, JS::FreePolicy> contents);
/**
* Create a new ArrayBuffer with the given |contents|, which may be null only
* if |nbytes == 0|. |contents| must be allocated compatible with deallocation
* by |JS_free|.
*
* Care must be taken that |nbytes| bytes of |contents| remain valid for the
* duration of this call. In particular, passing the length/pointer of existing
* typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
* call to this function, it could move those contents to a different location
* and invalidate the provided pointer.
*/
inline JS_PUBLIC_API JSObject* NewArrayBufferWithContents(
JSContext* cx, size_t nbytes,
mozilla::UniquePtr<char[], JS::FreePolicy> contents) {
// As a convenience, provide an overload for UniquePtr<char[]>.
mozilla::UniquePtr<void, JS::FreePolicy> ptr{contents.release()};
return NewArrayBufferWithContents(cx, nbytes, std::move(ptr));
}
/**
* Create a new ArrayBuffer with the given |contents|, which may be null only
* if |nbytes == 0|. |contents| must be allocated compatible with deallocation
* by |JS_free|.
*
* Care must be taken that |nbytes| bytes of |contents| remain valid for the
* duration of this call. In particular, passing the length/pointer of existing
* typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
* call to this function, it could move those contents to a different location
* and invalidate the provided pointer.
*/
inline JS_PUBLIC_API JSObject* NewArrayBufferWithContents(
JSContext* cx, size_t nbytes,
mozilla::UniquePtr<uint8_t[], JS::FreePolicy> contents) {
// As a convenience, provide an overload for UniquePtr<uint8_t[]>.
mozilla::UniquePtr<void, JS::FreePolicy> ptr{contents.release()};
return NewArrayBufferWithContents(cx, nbytes, std::move(ptr));
}
/**
* Marker enum to notify callers that the buffer contents must be freed manually
* when the ArrayBuffer allocation failed.
*/
enum class NewArrayBufferOutOfMemory { CallerMustFreeMemory };
/**
* Create a new ArrayBuffer with the given |contents|, which may be null only
* if |nbytes == 0|. |contents| must be allocated compatible with deallocation
* by |JS_free|.
*
* !!! IMPORTANT !!!
* If and only if an ArrayBuffer is successfully created and returned,
* ownership of |contents| is transferred to the new ArrayBuffer.
*
* Care must be taken that |nbytes| bytes of |contents| remain valid for the
* Care must be taken that |nbytes| bytes of |content| remain valid for the
* duration of this call. In particular, passing the length/pointer of existing
* typed array or ArrayBuffer data is generally unsafe: if a GC occurs during a
* call to this function, it could move those contents to a different location
* and invalidate the provided pointer.
*/
extern JS_PUBLIC_API JSObject* NewArrayBufferWithContents(
JSContext* cx, size_t nbytes, void* contents, NewArrayBufferOutOfMemory);
extern JS_PUBLIC_API JSObject* NewArrayBufferWithContents(JSContext* cx,
size_t nbytes,
void* contents);
/**
* Create a new ArrayBuffer, whose bytes are set to the values of the bytes in
@ -131,24 +69,6 @@ extern JS_PUBLIC_API JSObject* CopyArrayBuffer(
using BufferContentsFreeFunc = void (*)(void* contents, void* userData);
/**
* UniquePtr deleter for external buffer contents.
*/
class JS_PUBLIC_API BufferContentsDeleter {
BufferContentsFreeFunc freeFunc_ = nullptr;
void* userData_ = nullptr;
public:
MOZ_IMPLICIT BufferContentsDeleter(BufferContentsFreeFunc freeFunc,
void* userData = nullptr)
: freeFunc_(freeFunc), userData_(userData) {}
void operator()(void* contents) const { freeFunc_(contents, userData_); }
BufferContentsFreeFunc freeFunc() const { return freeFunc_; }
void* userData() const { return userData_; }
};
/**
* Create a new ArrayBuffer with the given contents. The contents must not be
* modified by any other code, internal or external.
@ -176,8 +96,8 @@ class JS_PUBLIC_API BufferContentsDeleter {
* freed with some function other than free().
*/
extern JS_PUBLIC_API JSObject* NewExternalArrayBuffer(
JSContext* cx, size_t nbytes,
mozilla::UniquePtr<void, BufferContentsDeleter> contents);
JSContext* cx, size_t nbytes, void* contents,
BufferContentsFreeFunc freeFunc, void* freeUserData = nullptr);
/**
* Create a new ArrayBuffer with the given non-null |contents|.

Просмотреть файл

@ -4989,9 +4989,10 @@ class CloneBufferObject : public NativeObject {
return false;
}
JSObject* arrayBuffer =
JS::NewArrayBufferWithContents(cx, size, std::move(buffer));
auto* rawBuffer = buffer.release();
JSObject* arrayBuffer = JS::NewArrayBufferWithContents(cx, size, rawBuffer);
if (!arrayBuffer) {
js_free(rawBuffer);
return false;
}

Просмотреть файл

@ -66,15 +66,14 @@ BEGIN_TEST(testArrayBuffer_bug720949_steal) {
CHECK(v.isInt32(MAGIC_VALUE_2));
// Steal the contents
mozilla::UniquePtr<void, JS::FreePolicy> contents{
JS::StealArrayBufferContents(cx, obj)};
void* contents = JS::StealArrayBufferContents(cx, obj);
CHECK(contents != nullptr);
CHECK(JS::IsDetachedArrayBufferObject(obj));
// Transfer to a new ArrayBuffer
JS::RootedObject dst(
cx, JS::NewArrayBufferWithContents(cx, size, std::move(contents)));
JS::RootedObject dst(cx,
JS::NewArrayBufferWithContents(cx, size, contents));
CHECK(JS::IsArrayBufferObject(dst));
{
JS::AutoCheckCannotGC nogc;
@ -172,11 +171,11 @@ END_TEST(testArrayBuffer_bug720949_viewList)
BEGIN_TEST(testArrayBuffer_customFreeFunc) {
ExternalData data("One two three four");
auto dataPointer = data.pointer();
// The buffer takes ownership of the data.
JS::RootedObject buffer(
cx, JS::NewExternalArrayBuffer(cx, data.len(), std::move(dataPointer)));
cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
&ExternalData::freeCallback, &data));
CHECK(buffer);
CHECK(!data.wasFreed());
@ -200,8 +199,9 @@ END_TEST(testArrayBuffer_customFreeFunc)
BEGIN_TEST(testArrayBuffer_staticContents) {
ExternalData data("One two three four");
JS::RootedObject buffer(cx, JS::NewArrayBufferWithUserOwnedContents(
cx, data.len(), data.contents()));
// When not passing a free function, the buffer doesn't own the data.
JS::RootedObject buffer(
cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(), nullptr));
CHECK(buffer);
CHECK(!data.wasFreed());
@ -226,9 +226,9 @@ END_TEST(testArrayBuffer_staticContents)
BEGIN_TEST(testArrayBuffer_stealDetachExternal) {
static const char dataBytes[] = "One two three four";
ExternalData data(dataBytes);
auto dataPointer = data.pointer();
JS::RootedObject buffer(
cx, JS::NewExternalArrayBuffer(cx, data.len(), std::move(dataPointer)));
cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
&ExternalData::freeCallback, &data));
CHECK(buffer);
CHECK(!data.wasFreed());
@ -260,9 +260,9 @@ BEGIN_TEST(testArrayBuffer_serializeExternal) {
}
ExternalData data("One two three four");
auto dataPointer = data.pointer();
JS::RootedObject externalBuffer(
cx, JS::NewExternalArrayBuffer(cx, data.len(), std::move(dataPointer)));
cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
&ExternalData::freeCallback, &data));
CHECK(externalBuffer);
CHECK(!data.wasFreed());
@ -308,14 +308,14 @@ END_TEST(testArrayBuffer_serializeExternal)
BEGIN_TEST(testArrayBuffer_copyData) {
ExternalData data1("One two three four");
JS::RootedObject buffer1(cx, JS::NewArrayBufferWithUserOwnedContents(
cx, data1.len(), data1.contents()));
JS::RootedObject buffer1(cx, JS::NewExternalArrayBuffer(
cx, data1.len(), data1.contents(), nullptr));
CHECK(buffer1);
ExternalData data2("Six");
JS::RootedObject buffer2(cx, JS::NewArrayBufferWithUserOwnedContents(
cx, data2.len(), data2.contents()));
JS::RootedObject buffer2(cx, JS::NewExternalArrayBuffer(
cx, data2.len(), data2.contents(), nullptr));
CHECK(buffer2);
@ -367,15 +367,15 @@ BEGIN_TEST(testArrayBuffer_copyDataAcrossGlobals) {
JS::RootedObject buffer1(cx);
{
js::AutoRealm realm(cx, otherGlobal);
buffer1 = JS::NewArrayBufferWithUserOwnedContents(cx, data1.len(),
data1.contents());
buffer1 =
JS::NewExternalArrayBuffer(cx, data1.len(), data1.contents(), nullptr);
}
CHECK(buffer1);
CHECK(JS_WrapObject(cx, &buffer1));
ExternalData data2("Six");
JS::RootedObject buffer2(cx, JS::NewArrayBufferWithUserOwnedContents(
cx, data2.len(), data2.contents()));
JS::RootedObject buffer2(cx, JS::NewExternalArrayBuffer(
cx, data2.len(), data2.contents(), nullptr));
CHECK(buffer2);
@ -424,8 +424,8 @@ END_TEST(testArrayBuffer_copyDataAcrossGlobals)
BEGIN_TEST(testArrayBuffer_ArrayBufferClone) {
ExternalData data("One two three four");
JS::RootedObject externalBuffer(cx, JS::NewArrayBufferWithUserOwnedContents(
cx, data.len(), data.contents()));
JS::RootedObject externalBuffer(
cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(), nullptr));
CHECK(externalBuffer);

Просмотреть файл

@ -103,7 +103,6 @@ END_TEST(testStructuredClone_string)
BEGIN_TEST(testStructuredClone_externalArrayBuffer) {
ExternalData data("One two three four");
auto dataPointer = data.pointer();
JS::RootedObject g1(cx, createGlobal());
JS::RootedObject g2(cx, createGlobal());
CHECK(g1);
@ -115,7 +114,8 @@ BEGIN_TEST(testStructuredClone_externalArrayBuffer) {
JSAutoRealm ar(cx, g1);
JS::RootedObject obj(
cx, JS::NewExternalArrayBuffer(cx, data.len(), std::move(dataPointer)));
cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
&ExternalData::freeCallback, &data));
CHECK(!data.wasFreed());
v1 = JS::ObjectOrNullValue(obj);
@ -164,9 +164,9 @@ BEGIN_TEST(testStructuredClone_externalArrayBufferDifferentThreadOrProcess) {
bool testStructuredCloneCopy(JS::StructuredCloneScope scope) {
ExternalData data("One two three four");
auto dataPointer = data.pointer();
JS::RootedObject buffer(
cx, JS::NewExternalArrayBuffer(cx, data.len(), std::move(dataPointer)));
cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
&ExternalData::freeCallback, &data));
CHECK(buffer);
CHECK(!data.wasFreed());

Просмотреть файл

@ -20,7 +20,6 @@
#include "gc/GC.h"
#include "js/AllocPolicy.h"
#include "js/ArrayBuffer.h"
#include "js/CharacterEncoding.h"
#include "js/Conversions.h"
#include "js/Equality.h" // JS::SameValue
@ -543,7 +542,6 @@ class TestJSPrincipals : public JSPrincipals {
class ExternalData {
char* contents_;
size_t len_;
bool uniquePointerCreated_ = false;
public:
explicit ExternalData(const char* str)
@ -560,13 +558,6 @@ class ExternalData {
contents_ = nullptr;
}
mozilla::UniquePtr<void, JS::BufferContentsDeleter> pointer() {
MOZ_ASSERT(!uniquePointerCreated_,
"Not allowed to create multiple unique pointers to contents");
uniquePointerCreated_ = true;
return {contents_, {ExternalData::freeCallback, this}};
}
static void freeCallback(void* contents, void* userData) {
auto self = static_cast<ExternalData*>(userData);
MOZ_ASSERT(self->contents() == contents);

Просмотреть файл

@ -1743,16 +1743,14 @@ static bool CreateExternalArrayBuffer(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
void* buffer = js_calloc(bytes);
void* buffer = js_malloc(bytes);
if (!buffer) {
JS_ReportOutOfMemory(cx);
return false;
}
UniquePtr<void, JS::BufferContentsDeleter> ptr{buffer,
{&freeExternalCallback}};
RootedObject arrayBuffer(
cx, JS::NewExternalArrayBuffer(cx, bytes, std::move(ptr)));
cx, JS::NewExternalArrayBuffer(cx, bytes, buffer, &freeExternalCallback));
if (!arrayBuffer) {
return false;
}

Просмотреть файл

@ -1018,8 +1018,7 @@ void ArrayBufferObject::releaseData(JS::GCContext* gcx) {
gcx->removeCellMemory(this, byteLength(), MemoryUse::ArrayBufferContents);
break;
case EXTERNAL:
MOZ_ASSERT(freeInfo()->freeFunc);
{
if (freeInfo()->freeFunc) {
// The analyzer can't know for sure whether the embedder-supplied
// free function will GC. We give the analyzer a hint here.
// (Doing a GC in the free function is considered a programmer
@ -1357,10 +1356,9 @@ ArrayBufferObject* ArrayBufferObject::createForContents(
} else if (contents.kind() == EXTERNAL) {
// Store the FreeInfo in the inline data slots so that we
// don't use up slots for it in non-refcounted array buffers.
constexpr size_t freeInfoSlots = HowMany(sizeof(FreeInfo), sizeof(Value));
static_assert(
reservedSlots + freeInfoSlots <= NativeObject::MAX_FIXED_SLOTS,
"FreeInfo must fit in inline slots");
size_t freeInfoSlots = HowMany(sizeof(FreeInfo), sizeof(Value));
MOZ_ASSERT(reservedSlots + freeInfoSlots <= NativeObject::MAX_FIXED_SLOTS,
"FreeInfo must fit in inline slots");
nslots += freeInfoSlots;
} else {
// The ABO is taking ownership, so account the bytes against the zone.
@ -1924,22 +1922,9 @@ JS_PUBLIC_API JSObject* JS::NewArrayBuffer(JSContext* cx, size_t nbytes) {
return ArrayBufferObject::createZeroed(cx, nbytes);
}
JS_PUBLIC_API JSObject* JS::NewArrayBufferWithContents(
JSContext* cx, size_t nbytes,
mozilla::UniquePtr<void, JS::FreePolicy> contents) {
auto* result = NewArrayBufferWithContents(
cx, nbytes, contents.get(),
JS::NewArrayBufferOutOfMemory::CallerMustFreeMemory);
if (result) {
// If and only if an ArrayBuffer is successfully created, ownership of
// |contents| is transferred to the new ArrayBuffer.
(void)contents.release();
}
return result;
}
JS_PUBLIC_API JSObject* JS::NewArrayBufferWithContents(
JSContext* cx, size_t nbytes, void* data, NewArrayBufferOutOfMemory) {
JS_PUBLIC_API JSObject* JS::NewArrayBufferWithContents(JSContext* cx,
size_t nbytes,
void* data) {
AssertHeapIsIdle();
CHECK_THREAD(cx);
MOZ_ASSERT_IF(!data, nbytes == 0);
@ -1972,26 +1957,18 @@ JS_PUBLIC_API JSObject* JS::CopyArrayBuffer(JSContext* cx,
}
JS_PUBLIC_API JSObject* JS::NewExternalArrayBuffer(
JSContext* cx, size_t nbytes,
mozilla::UniquePtr<void, JS::BufferContentsDeleter> contents) {
JSContext* cx, size_t nbytes, void* data,
JS::BufferContentsFreeFunc freeFunc, void* freeUserData) {
AssertHeapIsIdle();
CHECK_THREAD(cx);
MOZ_ASSERT(contents);
MOZ_ASSERT(data);
using BufferContents = ArrayBufferObject::BufferContents;
BufferContents bufferContents = BufferContents::createExternal(
contents.get(), contents.get_deleter().freeFunc(),
contents.get_deleter().userData());
auto* result =
ArrayBufferObject::createForContents(cx, nbytes, bufferContents);
if (result) {
// If and only if an ArrayBuffer is successfully created, ownership of
// |contents| is transferred to the new ArrayBuffer.
(void)contents.release();
}
return result;
BufferContents contents =
BufferContents::createExternal(data, freeFunc, freeUserData);
return ArrayBufferObject::createForContents(cx, nbytes, contents);
}
JS_PUBLIC_API JSObject* JS::NewArrayBufferWithUserOwnedContents(JSContext* cx,

Просмотреть файл

@ -308,7 +308,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared {
static BufferContents createExternal(void* data,
JS::BufferContentsFreeFunc freeFunc,
void* freeUserData = nullptr) {
MOZ_ASSERT(freeFunc);
return BufferContents(static_cast<uint8_t*>(data), EXTERNAL, freeFunc,
freeUserData);
}

Просмотреть файл

@ -3261,11 +3261,7 @@ bool JSStructuredCloneReader::readTransferMap() {
MOZ_ASSERT(data == JS::SCTAG_TMO_ALLOC_DATA ||
data == JS::SCTAG_TMO_MAPPED_DATA);
if (data == JS::SCTAG_TMO_ALLOC_DATA) {
// When the ArrayBuffer can't be allocated, |content| will be free'ed
// in `JSStructuredCloneData::discardTransferables()`.
obj = JS::NewArrayBufferWithContents(
cx, nbytes, content,
JS::NewArrayBufferOutOfMemory::CallerMustFreeMemory);
obj = JS::NewArrayBufferWithContents(cx, nbytes, content);
} else if (data == JS::SCTAG_TMO_MAPPED_DATA) {
obj = JS::NewMappedArrayBufferWithContents(cx, nbytes, content);
}

Просмотреть файл

@ -490,9 +490,8 @@ class Span {
/**
* Constructor for mozilla::UniquePtr holding an array and length.
*/
template <class ArrayElementType = std::add_pointer<element_type>,
class DeleterType>
constexpr Span(const mozilla::UniquePtr<ArrayElementType, DeleterType>& aPtr,
template <class ArrayElementType = std::add_pointer<element_type>>
constexpr Span(const mozilla::UniquePtr<ArrayElementType>& aPtr,
index_type aLength)
: storage_(aPtr.get(), aLength) {}

Просмотреть файл

@ -82,9 +82,8 @@ JSObject* OwnedRustBuffer::IntoArrayBuffer(JSContext* cx) {
int32_t len = mBuf.len;
void* data = mBuf.data;
auto userData = MakeUnique<OwnedRustBuffer>(std::move(*this));
UniquePtr<void, JS::BufferContentsDeleter> dataPtr{
data, {&ArrayBufferFreeFunc, userData.release()}};
return JS::NewExternalArrayBuffer(cx, len, std::move(dataPtr));
return JS::NewExternalArrayBuffer(cx, len, data, &ArrayBufferFreeFunc,
userData.release());
}
void OwnedRustBuffer::ArrayBufferFreeFunc(void* contents, void* userData) {