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

Backed out changeset becc2fa2c186 (bug 1841314)
Backed out changeset e5b723317177 (bug 1841314)
Backed out changeset 61ae850b25e5 (bug 1841314)
Backed out changeset 9ff320c779b8 (bug 1841314)
Backed out changeset debf1172f794 (bug 1841314)
Backed out changeset 8ac4fa317006 (bug 1841314)
Backed out changeset eccacbb3b620 (bug 1841314)
This commit is contained in:
Cristina Horotan 2023-07-06 15:11:47 +03:00
parent 2336558a6d
commit f77c6f3e48
31 changed files with 116 additions and 249 deletions

View File

@ -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 {

View File

@ -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);

View File

@ -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);
/**

View File

@ -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");

View File

@ -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");

View File

@ -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));
}

View File

@ -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,

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -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); });

View File

@ -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);
}

View File

@ -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)) {

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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");

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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|.

View File

@ -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;
}

View File

@ -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);

View File

@ -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());

View File

@ -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);

View File

@ -1743,15 +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}};
auto* arrayBuffer = JS::NewExternalArrayBuffer(cx, bytes, std::move(ptr));
RootedObject arrayBuffer(
cx, JS::NewExternalArrayBuffer(cx, bytes, buffer, &freeExternalCallback));
if (!arrayBuffer) {
return false;
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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) {}

View File

@ -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) {