Skip to content

Commit

Permalink
Bug 1061288 - Make it harder for ArrayBuffer data pointers to be held…
Browse files Browse the repository at this point in the history
… across invalidations. r=smaug,terrence,jdm,roc,khuey
  • Loading branch information
hotsphink committed Oct 7, 2014
1 parent 20c5190 commit b640335
Show file tree
Hide file tree
Showing 26 changed files with 326 additions and 242 deletions.
3 changes: 2 additions & 1 deletion content/base/src/nsContentUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5983,7 +5983,8 @@ nsContentUtils::CreateArrayBuffer(JSContext *aCx, const nsACString& aData,

if (dataLen > 0) {
NS_ASSERTION(JS_IsArrayBufferObject(*aResult), "What happened?");
memcpy(JS_GetArrayBufferData(*aResult), aData.BeginReading(), dataLen);
JS::AutoCheckCannotGC nogc;
memcpy(JS_GetArrayBufferData(*aResult, nogc), aData.BeginReading(), dataLen);
}

return NS_OK;
Expand Down
42 changes: 25 additions & 17 deletions content/base/src/nsDOMFileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,22 @@ nsDOMFileReader::DoOnLoadEnd(nsresult aStatus,

nsresult rv = NS_OK;
switch (mDataFormat) {
case FILE_AS_ARRAYBUFFER:
break; //Already accumulated mResultArrayBuffer
case FILE_AS_ARRAYBUFFER: {
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mozilla::DOMEventTargetHelper::GetParentObject()))) {
return NS_ERROR_FAILURE;
}

RootResultArrayBuffer();
mResultArrayBuffer = JS_NewArrayBufferWithContents(jsapi.cx(), mTotal, mFileData);
if (!mResultArrayBuffer) {
JS_ClearPendingException(jsapi.cx());
rv = NS_ERROR_OUT_OF_MEMORY;
} else {
mFileData = nullptr; // Transfer ownership
}
break;
}
case FILE_AS_BINARY:
break; //Already accumulated mResult
case FILE_AS_TEXT:
Expand Down Expand Up @@ -342,20 +356,16 @@ nsDOMFileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount)
&bytesRead);
NS_ASSERTION(bytesRead == aCount, "failed to read data");
}
else if (mDataFormat == FILE_AS_ARRAYBUFFER) {
uint32_t bytesRead = 0;
aStream->Read((char*) JS_GetArrayBufferData(mResultArrayBuffer) + mDataLen,
aCount, &bytesRead);
NS_ASSERTION(bytesRead == aCount, "failed to read data");
}
else {
//Update memory buffer to reflect the contents of the file
if (mDataLen + aCount > UINT32_MAX) {
// PR_Realloc doesn't support over 4GB memory size even if 64-bit OS
return NS_ERROR_OUT_OF_MEMORY;
}
mFileData = (char *) moz_realloc(mFileData, mDataLen + aCount);
NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY);
if (mDataFormat != FILE_AS_ARRAYBUFFER) {
mFileData = (char *) moz_realloc(mFileData, mDataLen + aCount);
NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY);
}

uint32_t bytesRead = 0;
aStream->Read(mFileData + mDataLen, aCount, &bytesRead);
Expand All @@ -369,8 +379,7 @@ nsDOMFileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount)
// Helper methods

void
nsDOMFileReader::ReadFileContent(JSContext* aCx,
File& aFile,
nsDOMFileReader::ReadFileContent(File& aFile,
const nsAString &aCharset,
eDataFormat aDataFormat,
ErrorResult& aRv)
Expand Down Expand Up @@ -443,11 +452,10 @@ nsDOMFileReader::ReadFileContent(JSContext* aCx,
DispatchProgressEvent(NS_LITERAL_STRING(LOADSTART_STR));

if (mDataFormat == FILE_AS_ARRAYBUFFER) {
RootResultArrayBuffer();
mResultArrayBuffer = JS_NewArrayBuffer(aCx, mTotal);
if (!mResultArrayBuffer) {
NS_WARNING("Failed to create JS array buffer");
aRv.Throw(NS_ERROR_FAILURE);
mFileData = js_pod_malloc<char>(mTotal);
if (!mFileData) {
NS_WARNING("Preallocation failed for ReadFileData");
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions content/base/src/nsDOMFileReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,17 @@ class nsDOMFileReader : public mozilla::dom::FileIOObject,
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
void ReadAsArrayBuffer(JSContext* aCx, File& aBlob, ErrorResult& aRv)
{
ReadFileContent(aCx, aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
ReadFileContent(aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
}

void ReadAsText(File& aBlob, const nsAString& aLabel, ErrorResult& aRv)
{
ReadFileContent(nullptr, aBlob, aLabel, FILE_AS_TEXT, aRv);
ReadFileContent(aBlob, aLabel, FILE_AS_TEXT, aRv);
}

void ReadAsDataURL(File& aBlob, ErrorResult& aRv)
{
ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
ReadFileContent(aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
}

using FileIOObject::Abort;
Expand All @@ -104,7 +104,7 @@ class nsDOMFileReader : public mozilla::dom::FileIOObject,

void ReadAsBinaryString(File& aBlob, ErrorResult& aRv)
{
ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_BINARY, aRv);
ReadFileContent(aBlob, EmptyString(), FILE_AS_BINARY, aRv);
}


Expand All @@ -124,7 +124,7 @@ class nsDOMFileReader : public mozilla::dom::FileIOObject,
FILE_AS_DATAURL
};

void ReadFileContent(JSContext* aCx, File& aBlob,
void ReadFileContent(File& aBlob,
const nsAString &aCharset, eDataFormat aDataFormat,
ErrorResult& aRv);
nsresult GetAsText(nsIDOMBlob *aFile, const nsACString &aCharset,
Expand Down
12 changes: 8 additions & 4 deletions content/media/webaudio/AudioBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ AudioBuffer::RestoreJSChannelData(JSContext* aJSContext)
if (!array) {
return false;
}
memcpy(JS_GetFloat32ArrayData(array), data, sizeof(float)*mLength);
JS::AutoCheckCannotGC nogc;
mozilla::PodCopy(JS_GetFloat32ArrayData(array, nogc), data, mLength);
mJSChannels[i] = array;
}

Expand Down Expand Up @@ -146,9 +147,10 @@ AudioBuffer::CopyFromChannel(const Float32Array& aDestination, uint32_t aChannel
return;
}

JS::AutoCheckCannotGC nogc;
const float* sourceData = mSharedChannels ?
mSharedChannels->GetData(aChannelNumber) :
JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]);
JS_GetFloat32ArrayData(mJSChannels[aChannelNumber], nogc);
PodMove(aDestination.Data(), sourceData + aStartInChannel, length);
}

Expand Down Expand Up @@ -179,7 +181,8 @@ AudioBuffer::CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
return;
}

PodMove(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]) + aStartInChannel,
JS::AutoCheckCannotGC nogc;
PodMove(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber], nogc) + aStartInChannel,
aSource.Data(), length);
}

Expand All @@ -188,7 +191,8 @@ AudioBuffer::SetRawChannelContents(uint32_t aChannel, float* aContents)
{
MOZ_ASSERT(!GetWrapperPreserveColor() && !mSharedChannels,
"The AudioBuffer object should not have been handed to JS or have C++ callers neuter its typed array");
PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel]), aContents, mLength);
JS::AutoCheckCannotGC nogc;
PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel], nogc), aContents, mLength);
}

void
Expand Down
40 changes: 26 additions & 14 deletions content/media/webspeech/synth/nsSpeechTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,20 @@ nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
return NS_OK;
}

static nsRefPtr<mozilla::SharedBuffer>
makeSamples(int16_t* aData, uint32_t aDataLen)
{
nsRefPtr<mozilla::SharedBuffer> samples =
SharedBuffer::Create(aDataLen * sizeof(int16_t));
int16_t* frames = static_cast<int16_t*>(samples->Data());

for (uint32_t i = 0; i < aDataLen; i++) {
frames[i] = aData[i];
}

return samples;
}

NS_IMETHODIMP
nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLandmarks,
JSContext* aCx)
Expand Down Expand Up @@ -194,8 +208,13 @@ nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLand
return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
}

SendAudioImpl(JS_GetInt16ArrayData(tsrc),
JS_GetTypedArrayLength(tsrc));
uint32_t dataLen = JS_GetTypedArrayLength(tsrc);
nsRefPtr<mozilla::SharedBuffer> samples;
{
JS::AutoCheckCannotGC nogc;
samples = makeSamples(JS_GetInt16ArrayData(tsrc, nogc), dataLen);
}
SendAudioImpl(samples, dataLen);

return NS_OK;
}
Expand All @@ -214,31 +233,24 @@ nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
return NS_ERROR_FAILURE;
}

SendAudioImpl(aData, aDataLen);
nsRefPtr<mozilla::SharedBuffer> samples = makeSamples(aData, aDataLen);
SendAudioImpl(samples, aDataLen);

return NS_OK;
}

void
nsSpeechTask::SendAudioImpl(int16_t* aData, uint32_t aDataLen)
nsSpeechTask::SendAudioImpl(nsRefPtr<mozilla::SharedBuffer>& aSamples, uint32_t aDataLen)
{
if (aDataLen == 0) {
mStream->EndAllTrackAndFinish();
return;
}

nsRefPtr<mozilla::SharedBuffer> samples =
SharedBuffer::Create(aDataLen * sizeof(int16_t));
int16_t* frames = static_cast<int16_t*>(samples->Data());

for (uint32_t i = 0; i < aDataLen; i++) {
frames[i] = aData[i];
}

AudioSegment segment;
nsAutoTArray<const int16_t*, 1> channelData;
channelData.AppendElement(frames);
segment.AppendFrames(samples.forget(), channelData, aDataLen);
channelData.AppendElement(static_cast<int16_t*>(aSamples->Data()));
segment.AppendFrames(aSamples.forget(), channelData, aDataLen);
mStream->AppendToTrack(1, &segment);
mStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
}
Expand Down
2 changes: 1 addition & 1 deletion content/media/webspeech/synth/nsSpeechTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class nsSpeechTask : public nsISpeechTask
private:
void End();

void SendAudioImpl(int16_t* aData, uint32_t aDataLen);
void SendAudioImpl(nsRefPtr<mozilla::SharedBuffer>& aSamples, uint32_t aDataLen);

nsRefPtr<SourceMediaStream> mStream;

Expand Down
5 changes: 3 additions & 2 deletions dom/bindings/TypedArray.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ struct TypedArray_base : public TypedArrayObjectStorage {

template<typename T,
JSObject* UnwrapArray(JSObject*),
T* GetData(JSObject*),
T* GetData(JSObject*, const JS::AutoCheckCannotGC&),
void GetLengthAndData(JSObject*, uint32_t*, T**),
JSObject* CreateNew(JSContext*, uint32_t)>
struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> {
Expand Down Expand Up @@ -181,7 +181,8 @@ struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> {
return nullptr;
}
if (data) {
T* buf = static_cast<T*>(GetData(obj));
JS::AutoCheckCannotGC nogc;
T* buf = static_cast<T*>(GetData(obj, nogc));
memcpy(buf, data, length*sizeof(T));
}
return obj;
Expand Down
14 changes: 10 additions & 4 deletions dom/canvas/CanvasRenderingContext2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4515,18 +4515,24 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
return NS_OK;
}

uint8_t* data = JS_GetUint8ClampedArrayData(darray);

IntRect dstWriteRect = srcReadRect;
dstWriteRect.MoveBy(-aX, -aY);

uint8_t* src = data;
uint32_t srcStride = aWidth * 4;
uint8_t* src;
uint32_t srcStride;

if (readback) {
srcStride = readback->Stride();
src = readback->GetData() + srcReadRect.y * srcStride + srcReadRect.x * 4;
}

JS::AutoCheckCannotGC nogc;
uint8_t* data = JS_GetUint8ClampedArrayData(darray, nogc);
if (!readback) {
src = data;
srcStride = aWidth * 4;
}

// NOTE! dst is the same as src, and this relies on reading
// from src and advancing that ptr before writing to dst.
// NOTE! I'm not sure that it is, I think this comment might have been
Expand Down
3 changes: 2 additions & 1 deletion dom/fmradio/FMRadio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ FMRadio::GetRdsgroup(JSContext* cx, JS::MutableHandle<JSObject*> retval)
}

JSObject *rdsgroup = Uint16Array::Create(cx, this, 4);
uint16_t *data = JS_GetUint16ArrayData(rdsgroup);
JS::AutoCheckCannotGC nogc;
uint16_t *data = JS_GetUint16ArrayData(rdsgroup, nogc);
data[3] = group & 0xFFFF;
group >>= 16;
data[2] = group & 0xFFFF;
Expand Down
33 changes: 20 additions & 13 deletions dom/network/TCPSocketChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <algorithm>
#include "TCPSocketChild.h"
#include "mozilla/unused.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/TabChild.h"
Expand All @@ -27,14 +28,17 @@ DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
mozilla::AutoSafeJSContext cx;
JSAutoCompartment ac(cx, aObj);

JS::Rooted<JSObject*> obj(cx, JS_NewArrayBuffer(cx, aBuffer.Length()));
if (!obj)
return false;
uint8_t* data = JS_GetArrayBufferData(obj);
mozilla::UniquePtr<uint8_t[], JS::FreePolicy> data(js_pod_malloc<uint8_t>(aBuffer.Length()));
if (!data)
return false;
memcpy(data, aBuffer.Elements(), aBuffer.Length());
aVal.set(OBJECT_TO_JSVAL(obj));
return false;
memcpy(data.get(), aBuffer.Elements(), aBuffer.Length());

JSObject* obj = JS_NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
if (!obj)
return false;
data.release();

aVal.setObject(*obj);
return true;
}

Expand Down Expand Up @@ -224,13 +228,16 @@ TCPSocketChild::SendSend(JS::Handle<JS::Value> aData,
uint32_t buflen = JS_GetArrayBufferByteLength(obj);
aByteOffset = std::min(buflen, aByteOffset);
uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
uint8_t* data = JS_GetArrayBufferData(obj);
if (!data) {
return NS_ERROR_OUT_OF_MEMORY;
}
FallibleTArray<uint8_t> fallibleArr;
if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) {
return NS_ERROR_OUT_OF_MEMORY;
{
JS::AutoCheckCannotGC nogc;
uint8_t* data = JS_GetArrayBufferData(obj, nogc);
if (!data) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
InfallibleTArray<uint8_t> arr;
arr.SwapElements(fallibleArr);
Expand Down
Loading

0 comments on commit b640335

Please sign in to comment.