Backed out de9fff3a523, c567df2244f5, 8e3d976d5dc5, and c7499faaec23 (bug 800915) for bustage.

--HG--
extra : rebase_source : c823063bfa31d59d32b3402bd4b458b84b703cd5
This commit is contained in:
Ryan VanderMeulen 2012-11-12 21:43:39 -05:00
parent be230eda17
commit 5f0fd7aeda
41 changed files with 508 additions and 412 deletions

View File

@ -6187,8 +6187,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);
NS_ASSERTION(JS_IsArrayBufferObject(*aResult, aCx), "What happened?");
memcpy(JS_GetArrayBufferData(*aResult, aCx), aData.BeginReading(), dataLen);
}
return NS_OK;

View File

@ -234,12 +234,12 @@ nsDOMMultipartFile::InitInternal(JSContext* aCx,
}
continue;
}
if (JS_IsArrayBufferViewObject(&obj)) {
blobSet.AppendVoidPtr(JS_GetArrayBufferViewData(&obj),
JS_GetArrayBufferViewByteLength(&obj));
if (JS_IsArrayBufferViewObject(&obj, aCx)) {
blobSet.AppendVoidPtr(JS_GetArrayBufferViewData(&obj, aCx),
JS_GetArrayBufferViewByteLength(&obj, aCx));
continue;
}
if (JS_IsArrayBufferObject(&obj)) {
if (JS_IsArrayBufferObject(&obj, aCx)) {
blobSet.AppendArrayBuffer(&obj, aCx);
continue;
}
@ -321,6 +321,6 @@ BlobSet::AppendBlobs(const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlob)
nsresult
BlobSet::AppendArrayBuffer(JSObject* aBuffer, JSContext *aCx)
{
return AppendVoidPtr(JS_GetArrayBufferData(aBuffer),
JS_GetArrayBufferByteLength(aBuffer));
return AppendVoidPtr(JS_GetArrayBufferData(aBuffer, aCx),
JS_GetArrayBufferByteLength(aBuffer, aCx));
}

View File

@ -317,9 +317,9 @@ nsDOMDataChannel::GetSendParams(nsIVariant* aData, nsCString& aStringOut,
nsresult rv = aData->GetAsJSVal(&realVal);
if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal) &&
(obj = JSVAL_TO_OBJECT(realVal)) &&
(JS_IsArrayBufferObject(obj))) {
int32_t len = JS_GetArrayBufferByteLength(obj);
char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(obj));
(JS_IsArrayBufferObject(obj, aCx))) {
int32_t len = JS_GetArrayBufferByteLength(obj, aCx);
char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(obj, aCx));
aStringOut.Assign(data, len);
aIsBinary = true;

View File

@ -309,7 +309,7 @@ nsDOMFileReader::DoOnDataAvailable(nsIRequest *aRequest,
}
else if (mDataFormat == FILE_AS_ARRAYBUFFER) {
uint32_t bytesRead = 0;
aInputStream->Read((char*)JS_GetArrayBufferData(mResultArrayBuffer) + aOffset,
aInputStream->Read((char*)JS_GetArrayBufferData(mResultArrayBuffer, NULL) + aOffset,
aCount, &bytesRead);
NS_ASSERTION(bytesRead == aCount, "failed to read data");
}

View File

@ -2669,8 +2669,8 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult, uint64_t* aContentLe
if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal)) {
JSObject *obj = JSVAL_TO_OBJECT(realVal);
ac.construct(cx, obj);
if (JS_IsArrayBufferObject(obj)) {
ArrayBuffer buf(obj);
if (JS_IsArrayBufferObject(obj, cx)) {
ArrayBuffer buf(cx, obj);
return GetRequestBody(&buf, aResult, aContentLength, aContentType, aCharset);
}
}

View File

@ -4321,7 +4321,7 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
return NS_OK;
}
uint8_t* data = JS_GetUint8ClampedArrayData(darray);
uint8_t* data = JS_GetUint8ClampedArrayData(darray, aCx);
IntRect srcRect(0, 0, mWidth, mHeight);
IntRect destRect(aX, aY, aWidth, aHeight);
@ -4433,7 +4433,7 @@ CanvasRenderingContext2D::PutImageData(JSContext* cx,
return;
}
dom::Uint8ClampedArray arr(imageData.GetDataObject());
dom::Uint8ClampedArray arr(cx, imageData.GetDataObject());
error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
imageData.Width(), imageData.Height(),
@ -4453,7 +4453,7 @@ CanvasRenderingContext2D::PutImageData(JSContext* cx,
return;
}
dom::Uint8ClampedArray arr(imageData.GetDataObject());
dom::Uint8ClampedArray arr(cx, imageData.GetDataObject());
error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
imageData.Width(), imageData.Height(),

View File

@ -3157,8 +3157,8 @@ WebGLContext::ReadPixels(WebGLint x, WebGLint y, WebGLsizei width,
WebGLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
void* data = pixels->Data();
uint32_t dataByteLen = JS_GetTypedArrayByteLength(pixels->Obj());
int dataType = JS_GetTypedArrayType(pixels->Obj());
uint32_t dataByteLen = JS_GetTypedArrayByteLength(pixels->Obj(), NULL);
int dataType = JS_GetTypedArrayType(pixels->Obj(), NULL);
uint32_t channels = 0;
@ -4873,7 +4873,7 @@ WebGLContext::TexImage2D(JSContext* cx, WebGLenum target, WebGLint level,
return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
pixels ? pixels->Data() : 0,
pixels ? pixels->Length() : 0,
pixels ? (int)JS_GetTypedArrayType(pixels->Obj()) : -1,
pixels ? (int)JS_GetTypedArrayType(pixels->Obj(), cx) : -1,
WebGLTexelConversions::Auto, false);
}
@ -4890,7 +4890,7 @@ WebGLContext::TexImage2D(JSContext* cx, WebGLenum target, WebGLint level,
return ErrorInvalidValue("texImage2D: null ImageData");
}
Uint8ClampedArray arr(pixels->GetDataObject());
Uint8ClampedArray arr(cx, pixels->GetDataObject());
return TexImage2D_base(target, level, internalformat, pixels->Width(),
pixels->Height(), 4*pixels->Width(), 0,
format, type, arr.Data(), arr.Length(), -1,
@ -5027,7 +5027,7 @@ WebGLContext::TexSubImage2D(JSContext* cx, WebGLenum target, WebGLint level,
return TexSubImage2D_base(target, level, xoffset, yoffset,
width, height, 0, format, type,
pixels->Data(), pixels->Length(),
JS_GetTypedArrayType(pixels->Obj()),
JS_GetTypedArrayType(pixels->Obj(), cx),
WebGLTexelConversions::Auto, false);
}
@ -5043,7 +5043,7 @@ WebGLContext::TexSubImage2D(JSContext* cx, WebGLenum target, WebGLint level,
if (!pixels)
return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
Uint8ClampedArray arr(pixels->GetDataObject());
Uint8ClampedArray arr(cx, pixels->GetDataObject());
return TexSubImage2D_base(target, level, xoffset, yoffset,
pixels->Width(), pixels->Height(),
4*pixels->Width(), format, type,

View File

@ -86,7 +86,7 @@ nsDOMNotifyAudioAvailableEvent::GetFrameBuffer(JSContext* aCx, jsval* aResult)
NS_DROP_JS_OBJECTS(this, nsDOMNotifyAudioAvailableEvent);
return NS_ERROR_FAILURE;
}
memcpy(JS_GetFloat32ArrayData(mCachedArray), mFrameBuffer.get(), mFrameBufferLength * sizeof(float));
memcpy(JS_GetFloat32ArrayData(mCachedArray, aCx), mFrameBuffer.get(), mFrameBufferLength * sizeof(float));
*aResult = OBJECT_TO_JSVAL(mCachedArray);
return NS_OK;

View File

@ -156,7 +156,7 @@ nsHTMLAudioElement::MozWriteAudio(const JS::Value& aData, JSContext* aCx, uint32
JSObject* tsrc = NULL;
// Allow either Float32Array or plain JS Array
if (JS_IsFloat32Array(darray)) {
if (JS_IsFloat32Array(darray, aCx)) {
tsrc = darray;
} else if (JS_IsArrayObject(aCx, darray)) {
JSObject* nobj = JS_NewFloat32ArrayFromArray(aCx, darray);
@ -169,7 +169,7 @@ nsHTMLAudioElement::MozWriteAudio(const JS::Value& aData, JSContext* aCx, uint32
}
tvr.setObject(tsrc);
uint32_t dataLength = JS_GetTypedArrayLength(tsrc);
uint32_t dataLength = JS_GetTypedArrayLength(tsrc, aCx);
// Make sure that we are going to write the correct amount of data based
// on number of channels.
@ -180,7 +180,7 @@ nsHTMLAudioElement::MozWriteAudio(const JS::Value& aData, JSContext* aCx, uint32
// Don't write more than can be written without blocking.
uint32_t writeLen = NS_MIN(mAudioStream->Available(), dataLength / mChannels);
float* frames = JS_GetFloat32ArrayData(tsrc);
float* frames = JS_GetFloat32ArrayData(tsrc, aCx);
// Convert the samples back to integers as we are using fixed point audio in
// the nsAudioStream.
// This could be optimized to avoid allocation and memcpy when

View File

@ -519,7 +519,7 @@ nsPIDOMWindow::~nsPIDOMWindow() {}
class nsOuterWindowProxy : public js::Wrapper
{
public:
nsOuterWindowProxy() : js::Wrapper(0) { setSafeToUnwrap(false); }
nsOuterWindowProxy() : js::Wrapper(0) {}
virtual bool isOuterWindow() {
return true;

View File

@ -522,11 +522,9 @@ QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
// Get the object. It might be a security wrapper, in which case we do a checked
// unwrap.
JSObject* origObj = JSVAL_TO_OBJECT(thisv);
JSObject* obj = js::UnwrapObjectChecked(origObj);
if (!obj) {
JS_ReportError(cx, "Permission denied to access object");
JSObject* obj = js::UnwrapObjectChecked(cx, origObj);
if (!obj)
return false;
}
nsISupports* native;
if (!UnwrapDOMObjectToISupports(obj, native)) {

View File

@ -245,7 +245,7 @@ IsArrayLike(JSContext* cx, JSObject* obj)
// XXXbz need to detect platform objects (including listbinding
// ones) with indexGetters here!
return JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj);
return JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj, cx);
}
inline bool
@ -272,7 +272,7 @@ IsPlatformObject(JSContext* cx, JSObject* obj)
clasp = js::GetObjectJSClass(obj);
}
return IS_WRAPPER_CLASS(js::Valueify(clasp)) || IsDOMClass(clasp) ||
JS_IsArrayBufferObject(obj);
JS_IsArrayBufferObject(obj, cx);
}
// U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
@ -1314,11 +1314,6 @@ public:
mImpl.construct();
}
template <class T1>
void Construct(const T1 &t1) {
mImpl.construct(t1);
}
template <class T1, class T2>
void Construct(const T1 &t1, const T2 &t2) {
mImpl.construct(t1, t2);

View File

@ -2590,7 +2590,7 @@ for (uint32_t i = 0; i < length; ++i) {
else:
declType = "NonNull<" + name + ">"
template = (
"%s.%s(&${val}.toObject());\n"
"%s.%s(cx, &${val}.toObject());\n"
"if (!%s.%s().inited()) {\n"
"%s" # No newline here because onFailureBadType() handles that
"}\n" %

View File

@ -19,11 +19,11 @@ namespace dom {
* or array buffer object.
*/
template<typename T,
JSObject* UnboxArray(JSObject*, uint32_t*, T**)>
JSObject* UnboxArray(JSContext*, JSObject*, uint32_t*, T**)>
struct TypedArray_base {
TypedArray_base(JSObject* obj)
TypedArray_base(JSContext* cx, JSObject* obj)
{
mObj = UnboxArray(obj, &mLength, &mData);
mObj = UnboxArray(cx, obj, &mLength, &mData);
}
private:
@ -54,12 +54,12 @@ public:
template<typename T,
T* GetData(JSObject*),
JSObject* UnboxArray(JSObject*, uint32_t*, T**),
T* GetData(JSObject*, JSContext*),
JSObject* UnboxArray(JSContext*, JSObject*, uint32_t*, T**),
JSObject* CreateNew(JSContext*, uint32_t)>
struct TypedArray : public TypedArray_base<T,UnboxArray> {
TypedArray(JSObject* obj) :
TypedArray_base<T,UnboxArray>(obj)
TypedArray(JSContext* cx, JSObject* obj) :
TypedArray_base<T,UnboxArray>(cx, obj)
{}
static inline JSObject*
@ -75,7 +75,7 @@ struct TypedArray : public TypedArray_base<T,UnboxArray> {
return NULL;
}
if (data) {
T* buf = static_cast<T*>(GetData(obj));
T* buf = static_cast<T*>(GetData(obj, cx));
memcpy(buf, data, length*sizeof(T));
}
return obj;

View File

@ -218,9 +218,9 @@ GetInputStreamForJSVal(const jsval& aValue, JSContext* aCx,
if (!JSVAL_IS_PRIMITIVE(aValue)) {
JSObject* obj = JSVAL_TO_OBJECT(aValue);
if (JS_IsArrayBufferObject(obj)) {
char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(obj));
uint32_t length = JS_GetArrayBufferByteLength(obj);
if (JS_IsArrayBufferObject(obj, aCx)) {
char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(obj, aCx));
uint32_t length = JS_GetArrayBufferByteLength(obj, aCx);
rv = NS_NewByteInputStream(aInputStream, data, length,
NS_ASSIGNMENT_COPY);

View File

@ -28,7 +28,7 @@ DeserializeUint8Array(JSRawObject aObj,
JSObject* obj = JS_NewArrayBuffer(cx, aBuffer.Length());
if (!obj)
return false;
uint8_t* data = JS_GetArrayBufferData(obj);
uint8_t* data = JS_GetArrayBufferData(obj, cx);
if (!data)
return false;
memcpy(data, aBuffer.Elements(), aBuffer.Length());
@ -187,10 +187,10 @@ TCPSocketChild::Send(const JS::Value& aData, JSContext* aCx)
} else {
NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
JSObject* obj = &aData.toObject();
NS_ENSURE_TRUE(JS_IsTypedArrayObject(obj), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(JS_IsUint8Array(obj), NS_ERROR_FAILURE);
uint32_t nbytes = JS_GetTypedArrayByteLength(obj);
uint8_t* data = JS_GetUint8ArrayData(obj);
NS_ENSURE_TRUE(JS_IsTypedArrayObject(obj, aCx), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(JS_IsUint8Array(obj, aCx), NS_ERROR_FAILURE);
uint32_t nbytes = JS_GetTypedArrayByteLength(obj, aCx);
uint8_t* data = JS_GetUint8ArrayData(obj, aCx);
if (!data) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@ -156,10 +156,10 @@ TCPSocketParent::SendCallback(const nsAString& aType, const JS::Value& aDataVal,
} else if (aDataVal.isObject()) {
JSObject* obj = &aDataVal.toObject();
if (JS_IsTypedArrayObject(obj)) {
NS_ENSURE_TRUE(JS_IsUint8Array(obj), NS_ERROR_FAILURE);
uint32_t nbytes = JS_GetTypedArrayByteLength(obj);
uint8_t* buffer = JS_GetUint8ArrayData(obj);
if (JS_IsTypedArrayObject(obj, aCx)) {
NS_ENSURE_TRUE(JS_IsUint8Array(obj, aCx), NS_ERROR_FAILURE);
uint32_t nbytes = JS_GetTypedArrayByteLength(obj, aCx);
uint8_t* buffer = JS_GetUint8ArrayData(obj, aCx);
if (!buffer) {
FireInteralError(this, __LINE__);
return NS_ERROR_OUT_OF_MEMORY;

View File

@ -460,12 +460,20 @@ JSValToNPVariant(NPP npp, JSContext *cx, jsval val, NPVariant *variant)
// element has since been adopted into a new document. We don't bother
// transplanting the plugin objects, and just do a unwrap with security
// checks if we encounter one of them as an argument. If the unwrap fails,
// we run with the original wrapped object, since sometimes there are
// legitimate cases where a security wrapper ends up here (for example,
// Location objects, which are _always_ behind security wrappers).
// we clear the pending exception and just run with the original wrapped object,
// since sometimes there are legitimate cases where a security wrapper ends
// up here (for example, Location objects, which are _always_ behind security
// wrappers).
//
// NB: In addition to clearing the pending exception, we also have to temporarily
// disable the error reporter, because SpiderMonkey calls it directly if there's
// no JS code on the stack, which might be the case here.
JSObject *obj = JSVAL_TO_OBJECT(val);
obj = js::UnwrapObjectChecked(obj);
JSErrorReporter reporter = JS_SetErrorReporter(cx, NULL);
obj = js::UnwrapObjectChecked(cx, obj);
JS_SetErrorReporter(cx, reporter);
if (!obj) {
JS_ClearPendingException(cx);
obj = JSVAL_TO_OBJECT(val);
}
@ -1126,7 +1134,7 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JSObject *obj)
static JSObject *
GetNPObjectWrapper(JSContext *cx, JSObject *obj, bool wrapResult = true)
{
while (obj && (obj = js::UnwrapObjectChecked(obj))) {
while (obj && (obj = js::UnwrapObjectChecked(cx, obj))) {
if (JS_GetClass(obj) == &sNPObjectJSWrapperClass) {
if (wrapResult && !JS_WrapObject(cx, &obj)) {
return NULL;

View File

@ -89,12 +89,12 @@ PostToRIL(JSContext *cx, unsigned argc, jsval *vp)
data = abs.ptr();
} else if (!JSVAL_IS_PRIMITIVE(v)) {
JSObject *obj = JSVAL_TO_OBJECT(v);
if (!JS_IsTypedArrayObject(obj)) {
if (!JS_IsTypedArrayObject(obj, cx)) {
JS_ReportError(cx, "Object passed in wasn't a typed array");
return false;
}
uint32_t type = JS_GetTypedArrayType(obj);
uint32_t type = JS_GetTypedArrayType(obj, cx);
if (type != js::ArrayBufferView::TYPE_INT8 &&
type != js::ArrayBufferView::TYPE_UINT8 &&
type != js::ArrayBufferView::TYPE_UINT8_CLAMPED) {
@ -102,8 +102,8 @@ PostToRIL(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
size = JS_GetTypedArrayByteLength(obj);
data = JS_GetArrayBufferViewData(obj);
size = JS_GetTypedArrayByteLength(obj, cx);
data = JS_GetArrayBufferViewData(obj, cx);
} else {
JS_ReportError(cx,
"Incorrect argument. Expecting a string or a typed array");
@ -175,7 +175,7 @@ RILReceiver::DispatchRILEvent::RunTask(JSContext *aCx)
return false;
}
memcpy(JS_GetArrayBufferViewData(array), mMessage->mData, mMessage->mSize);
memcpy(JS_GetArrayBufferViewData(array, aCx), mMessage->mData, mMessage->mSize);
jsval argv[] = { OBJECT_TO_JSVAL(array) };
return JS_CallFunctionName(aCx, obj, "onRILMessage", NS_ARRAY_LENGTH(argv),
argv, argv);
@ -217,12 +217,12 @@ DoNetdCommand(JSContext *cx, unsigned argc, jsval *vp)
}
} else if (!JSVAL_IS_PRIMITIVE(v)) {
JSObject *obj = JSVAL_TO_OBJECT(v);
if (!JS_IsTypedArrayObject(obj)) {
if (!JS_IsTypedArrayObject(obj, cx)) {
JS_ReportError(cx, "Object passed in wasn't a typed array");
return false;
}
uint32_t type = JS_GetTypedArrayType(obj);
uint32_t type = JS_GetTypedArrayType(obj, cx);
if (type != js::ArrayBufferView::TYPE_INT8 &&
type != js::ArrayBufferView::TYPE_UINT8 &&
type != js::ArrayBufferView::TYPE_UINT8_CLAMPED) {
@ -230,13 +230,13 @@ DoNetdCommand(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
size = JS_GetTypedArrayByteLength(obj);
size = JS_GetTypedArrayByteLength(obj, cx);
if (!size) {
JS_ReportError(cx, "Typed array byte length is zero");
return false;
}
data = JS_GetArrayBufferViewData(obj);
data = JS_GetArrayBufferViewData(obj, cx);
if (!data) {
JS_ReportError(cx, "Array buffer view data is NULL");
return false;
@ -322,7 +322,7 @@ NetdReceiver::DispatchNetdEvent::RunTask(JSContext *aCx)
return false;
}
memcpy(JS_GetUint8ArrayData(array), mMessage->mData, mMessage->mSize);
memcpy(JS_GetUint8ArrayData(array, aCx), mMessage->mData, mMessage->mSize);
jsval argv[] = { OBJECT_TO_JSVAL(array) };
return JS_CallFunctionName(aCx, obj, "onNetdMessage", NS_ARRAY_LENGTH(argv),
argv, argv);

View File

@ -95,8 +95,8 @@ FileReaderSync::ReadAsArrayBuffer(JSContext* aCx, JSObject* aBlob,
return nullptr;
}
uint32_t bufferLength = JS_GetArrayBufferByteLength(jsArrayBuffer);
uint8_t* arrayBuffer = JS_GetArrayBufferData(jsArrayBuffer);
uint32_t bufferLength = JS_GetArrayBufferByteLength(jsArrayBuffer, aCx);
uint8_t* arrayBuffer = JS_GetArrayBufferData(jsArrayBuffer, aCx);
nsCOMPtr<nsIInputStream> stream;
rv = blob->GetInternalStream(getter_AddRefs(stream));

View File

@ -40,8 +40,8 @@ public:
Create(JSContext* aCx, uint32_t aWidth, uint32_t aHeight, JSObject *aData)
{
MOZ_ASSERT(aData);
MOZ_ASSERT(JS_IsTypedArrayObject(aData));
MOZ_ASSERT(JS_IsUint8ClampedArray(aData));
MOZ_ASSERT(JS_IsTypedArrayObject(aData, aCx));
MOZ_ASSERT(JS_IsUint8ClampedArray(aData, aCx));
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (!obj) {

View File

@ -2008,7 +2008,7 @@ XMLHttpRequest::Send(JSObject* aBody, ErrorResult& aRv)
JSContext* cx = GetJSContext();
jsval valToClone;
if (JS_IsArrayBufferObject(aBody) || file::GetDOMBlobFromJSObject(aBody)) {
if (JS_IsArrayBufferObject(aBody, cx) || file::GetDOMBlobFromJSObject(aBody)) {
valToClone = OBJECT_TO_JSVAL(aBody);
}
else {

View File

@ -2116,7 +2116,7 @@ bool CanConvertTypedArrayItemTo(JSObject *baseType, JSObject *valObj, JSContext
return true;
}
TypeCode elementTypeCode;
switch (JS_GetTypedArrayType(valObj)) {
switch (JS_GetTypedArrayType(valObj, cx)) {
case TypedArray::TYPE_INT8:
elementTypeCode = TYPE_int8_t;
break;
@ -2341,13 +2341,13 @@ ImplicitConvert(JSContext* cx,
return TypeError(cx, "string pointer", val);
}
break;
} else if (!JSVAL_IS_PRIMITIVE(val) && JS_IsArrayBufferObject(valObj)) {
} else if (!JSVAL_IS_PRIMITIVE(val) && JS_IsArrayBufferObject(valObj, cx)) {
// Convert ArrayBuffer to pointer without any copy.
// Just as with C arrays, we make no effort to
// keep the ArrayBuffer alive.
*static_cast<void**>(buffer) = JS_GetArrayBufferData(valObj);
*static_cast<void**>(buffer) = JS_GetArrayBufferData(valObj, cx);
break;
} if (!JSVAL_IS_PRIMITIVE(val) && JS_IsTypedArrayObject(valObj)) {
} if (!JSVAL_IS_PRIMITIVE(val) && JS_IsTypedArrayObject(valObj, cx)) {
if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
return TypeError(cx, "typed array with the appropriate type", val);
}
@ -2355,7 +2355,7 @@ ImplicitConvert(JSContext* cx,
// Convert TypedArray to pointer without any copy.
// Just as with C arrays, we make no effort to
// keep the TypedArray alive.
*static_cast<void**>(buffer) = JS_GetArrayBufferViewData(valObj);
*static_cast<void**>(buffer) = JS_GetArrayBufferViewData(valObj, cx);
break;
}
return TypeError(cx, "pointer", val);
@ -2444,34 +2444,34 @@ ImplicitConvert(JSContext* cx,
memcpy(buffer, intermediate.get(), arraySize);
} else if (!JSVAL_IS_PRIMITIVE(val) &&
JS_IsArrayBufferObject(valObj)) {
JS_IsArrayBufferObject(valObj, cx)) {
// Check that array is consistent with type, then
// copy the array.
uint32_t sourceLength = JS_GetArrayBufferByteLength(valObj);
uint32_t sourceLength = JS_GetArrayBufferByteLength(valObj, cx);
size_t elementSize = CType::GetSize(baseType);
size_t arraySize = elementSize * targetLength;
if (arraySize != size_t(sourceLength)) {
JS_ReportError(cx, "ArrayType length does not match source ArrayBuffer length");
return false;
}
memcpy(buffer, JS_GetArrayBufferData(valObj), sourceLength);
memcpy(buffer, JS_GetArrayBufferData(valObj, cx), sourceLength);
break;
} else if (!JSVAL_IS_PRIMITIVE(val) &&
JS_IsTypedArrayObject(valObj)) {
JS_IsTypedArrayObject(valObj, cx)) {
// Check that array is consistent with type, then
// copy the array.
if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
return TypeError(cx, "typed array with the appropriate type", val);
}
uint32_t sourceLength = JS_GetTypedArrayByteLength(valObj);
uint32_t sourceLength = JS_GetTypedArrayByteLength(valObj, cx);
size_t elementSize = CType::GetSize(baseType);
size_t arraySize = elementSize * targetLength;
if (arraySize != size_t(sourceLength)) {
JS_ReportError(cx, "typed array length does not match source TypedArray length");
return false;
}
memcpy(buffer, JS_GetArrayBufferViewData(valObj), sourceLength);
memcpy(buffer, JS_GetArrayBufferViewData(valObj, cx), sourceLength);
break;
} else {
// Don't implicitly convert to string. Users can implicitly convert

View File

@ -36,15 +36,15 @@ BEGIN_TEST(testArrayBuffer_bug720949_steal)
jsval v;
// Byte lengths should all agree
CHECK(JS_IsArrayBufferObject(obj));
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), size);
CHECK(JS_IsArrayBufferObject(obj, cx));
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), size);
JS_GetProperty(cx, obj, "byteLength", &v);
CHECK_SAME(v, INT_TO_JSVAL(size));
JS_GetProperty(cx, view, "byteLength", &v);
CHECK_SAME(v, INT_TO_JSVAL(size));
// Modifying the underlying data should update the value returned through the view
uint8_t *data = JS_GetArrayBufferData(obj);
uint8_t *data = JS_GetArrayBufferData(obj, cx);
CHECK(data != NULL);
*reinterpret_cast<uint32_t*>(data) = MAGIC_VALUE_2;
CHECK(JS_GetElement(cx, view, 0, &v));
@ -57,7 +57,7 @@ BEGIN_TEST(testArrayBuffer_bug720949_steal)
CHECK(data != NULL);
// Check that the original ArrayBuffer is neutered
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0);
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), 0);
CHECK(JS_GetProperty(cx, obj, "byteLength", &v));
CHECK_SAME(v, INT_TO_JSVAL(0));
CHECK(JS_GetProperty(cx, view, "byteLength", &v));
@ -66,21 +66,21 @@ BEGIN_TEST(testArrayBuffer_bug720949_steal)
CHECK_SAME(v, INT_TO_JSVAL(0));
CHECK(JS_GetProperty(cx, view, "length", &v));
CHECK_SAME(v, INT_TO_JSVAL(0));
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0);
CHECK_EQUAL(JS_GetArrayBufferByteLength(obj, cx), 0);
v = JSVAL_VOID;
JS_GetElement(cx, obj, 0, &v);
CHECK_SAME(v, JSVAL_VOID);
// Transfer to a new ArrayBuffer
js::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, contents));
CHECK(JS_IsArrayBufferObject(dst));
data = JS_GetArrayBufferData(obj);
CHECK(JS_IsArrayBufferObject(dst, cx));
data = JS_GetArrayBufferData(obj, cx);
js::RootedObject dstview(cx, JS_NewInt32ArrayWithBuffer(cx, dst, 0, -1));
CHECK(dstview != NULL);
CHECK_EQUAL(JS_GetArrayBufferByteLength(dst), size);
data = JS_GetArrayBufferData(dst);
CHECK_EQUAL(JS_GetArrayBufferByteLength(dst, cx), size);
data = JS_GetArrayBufferData(dst, cx);
CHECK(data != NULL);
CHECK_EQUAL(*reinterpret_cast<uint32_t*>(data), MAGIC_VALUE_2);
CHECK(JS_GetElement(cx, dstview, 0, &v));

View File

@ -28,16 +28,16 @@ BEGIN_TEST(testTypedArrays)
size_t nbytes = sizeof(double) * 8;
RootedObject buffer(cx, JS_NewArrayBuffer(cx, nbytes));
CHECK(JS_IsArrayBufferObject(buffer));
CHECK(JS_IsArrayBufferObject(buffer, cx));
RootedObject proto(cx);
JS_GetPrototype(cx, buffer, proto.address());
CHECK(!JS_IsArrayBufferObject(proto));
CHECK(!JS_IsArrayBufferObject(proto, cx));
RootedObject dummy(cx, JS_GetParent(proto));
CHECK(!JS_IsArrayBufferObject(dummy));
CHECK(!JS_IsArrayBufferObject(dummy, cx));
CHECK_EQUAL(JS_GetArrayBufferByteLength(buffer), nbytes);
memset(JS_GetArrayBufferData(buffer), 1, nbytes);
CHECK_EQUAL(JS_GetArrayBufferByteLength(buffer, cx), nbytes);
memset(JS_GetArrayBufferData(buffer, cx), 1, nbytes);
ok = ok &&
TestArrayFromBuffer<JS_NewInt8ArrayWithBuffer, JS_NewInt8ArrayFromArray, int8_t, JS_GetInt8ArrayData>(cx) &&
@ -55,24 +55,24 @@ BEGIN_TEST(testTypedArrays)
template<JSObject *Create(JSContext *, uint32_t),
typename Element,
Element *GetData(JSObject *)>
Element *GetData(JSObject *, JSContext *)>
bool
TestPlainTypedArray(JSContext *cx)
{
RootedObject array(cx, Create(cx, 7));
CHECK(JS_IsTypedArrayObject(array));
CHECK(JS_IsTypedArrayObject(array, cx));
RootedObject proto(cx);
JS_GetPrototype(cx, array, proto.address());
CHECK(!JS_IsTypedArrayObject(proto));
CHECK(!JS_IsTypedArrayObject(proto, cx));
RootedObject dummy(cx, JS_GetParent(proto));
CHECK(!JS_IsTypedArrayObject(dummy));
CHECK(!JS_IsTypedArrayObject(dummy, cx));
CHECK_EQUAL(JS_GetTypedArrayLength(array), 7);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0);
CHECK_EQUAL(JS_GetTypedArrayByteLength(array), sizeof(Element) * 7);
CHECK_EQUAL(JS_GetTypedArrayLength(array, cx), 7);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(array, cx), 0);
CHECK_EQUAL(JS_GetTypedArrayByteLength(array, cx), sizeof(Element) * 7);
Element *data;
CHECK(data = GetData(array));
CHECK(data = GetData(array, cx));
*data = 13;
jsval v;
CHECK(JS_GetElement(cx, array, 0, &v));
@ -84,7 +84,7 @@ TestPlainTypedArray(JSContext *cx)
template<JSObject *CreateWithBuffer(JSContext *, JSObject *, uint32_t, int32_t),
JSObject *CreateFromArray(JSContext *, JSObject *),
typename Element,
Element *GetData(JSObject *)>
Element *GetData(JSObject *, JSContext *)>
bool
TestArrayFromBuffer(JSContext *cx)
{
@ -92,32 +92,32 @@ TestArrayFromBuffer(JSContext *cx)
size_t nbytes = elts * sizeof(Element);
RootedObject buffer(cx, JS_NewArrayBuffer(cx, nbytes));
uint8_t *bufdata;
CHECK(bufdata = JS_GetArrayBufferData(buffer));
CHECK(bufdata = JS_GetArrayBufferData(buffer, cx));
memset(bufdata, 1, nbytes);
RootedObject array(cx, CreateWithBuffer(cx, buffer, 0, -1));
CHECK_EQUAL(JS_GetTypedArrayLength(array), elts);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0);
CHECK_EQUAL(JS_GetTypedArrayByteLength(array), nbytes);
CHECK_EQUAL(JS_GetArrayBufferViewBuffer(array), (JSObject*) buffer);
CHECK_EQUAL(JS_GetTypedArrayLength(array, cx), elts);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(array, cx), 0);
CHECK_EQUAL(JS_GetTypedArrayByteLength(array, cx), nbytes);
CHECK_EQUAL(JS_GetArrayBufferViewBuffer(array, cx), (JSObject*) buffer);
Element *data;
CHECK(data = GetData(array));
CHECK(bufdata = JS_GetArrayBufferData(buffer));
CHECK(data = GetData(array, cx));
CHECK(bufdata = JS_GetArrayBufferData(buffer, cx));
CHECK_EQUAL((void*) data, (void*) bufdata);
CHECK_EQUAL(*bufdata, 1);
CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1);
RootedObject shortArray(cx, CreateWithBuffer(cx, buffer, 0, elts / 2));
CHECK_EQUAL(JS_GetTypedArrayLength(shortArray), elts / 2);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(shortArray), 0);
CHECK_EQUAL(JS_GetTypedArrayByteLength(shortArray), nbytes / 2);
CHECK_EQUAL(JS_GetTypedArrayLength(shortArray, cx), elts / 2);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(shortArray, cx), 0);
CHECK_EQUAL(JS_GetTypedArrayByteLength(shortArray, cx), nbytes / 2);
RootedObject ofsArray(cx, CreateWithBuffer(cx, buffer, nbytes / 2, -1));
CHECK_EQUAL(JS_GetTypedArrayLength(ofsArray), elts / 2);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(ofsArray), nbytes / 2);
CHECK_EQUAL(JS_GetTypedArrayByteLength(ofsArray), nbytes / 2);
CHECK_EQUAL(JS_GetTypedArrayLength(ofsArray, cx), elts / 2);
CHECK_EQUAL(JS_GetTypedArrayByteOffset(ofsArray, cx), nbytes / 2);
CHECK_EQUAL(JS_GetTypedArrayByteLength(ofsArray, cx), nbytes / 2);
// Make sure all 3 views reflect the same buffer at the expected locations
jsval v = INT_TO_JSVAL(39);

View File

@ -567,13 +567,13 @@ JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v)
JS_ASSERT(v.isObject());
RootedObject obj(w->context(), &v.toObject());
// If the object is a security wrapper, see if we're allowed to unwrap it.
// If we aren't, throw.
if (obj->isWrapper())
obj = UnwrapObjectChecked(obj);
if (!obj) {
JS_ReportError(w->context(), "Permission denied to access object");
return false;
// If the object is a security wrapper, try puncturing it. This may throw
// if the access is not allowed.
if (obj->isWrapper()) {
JSObject *unwrapped = UnwrapObjectChecked(w->context(), obj);
if (!unwrapped)
return false;
obj = unwrapped;
}
return w->writeTypedArray(obj);
}
@ -674,11 +674,9 @@ JSStructuredCloneWriter::startWrite(const Value &v)
// The object might be a security wrapper. See if we can clone what's
// behind it. If we can, unwrap the object.
obj = UnwrapObjectChecked(obj);
if (!obj) {
JS_ReportError(context(), "Permission denied to access object");
obj = UnwrapObjectChecked(context(), obj);
if (!obj)
return false;
}
AutoCompartment ac(context(), obj);
@ -899,23 +897,23 @@ JSStructuredCloneReader::readTypedArray(uint32_t tag, uint32_t nelems, Value *vp
JS_ASSERT(TypedArray::length(obj) == nelems);
switch (tag) {
case SCTAG_TYPED_ARRAY_INT8:
return in.readArray((uint8_t*) JS_GetInt8ArrayData(obj), nelems);
return in.readArray((uint8_t*) JS_GetInt8ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_UINT8:
return in.readArray(JS_GetUint8ArrayData(obj), nelems);
return in.readArray(JS_GetUint8ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_INT16:
return in.readArray((uint16_t*) JS_GetInt16ArrayData(obj), nelems);
return in.readArray((uint16_t*) JS_GetInt16ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_UINT16:
return in.readArray(JS_GetUint16ArrayData(obj), nelems);
return in.readArray(JS_GetUint16ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_INT32:
return in.readArray((uint32_t*) JS_GetInt32ArrayData(obj), nelems);
return in.readArray((uint32_t*) JS_GetInt32ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_UINT32:
return in.readArray(JS_GetUint32ArrayData(obj), nelems);
return in.readArray(JS_GetUint32ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_FLOAT32:
return in.readArray((uint32_t*) JS_GetFloat32ArrayData(obj), nelems);
return in.readArray((uint32_t*) JS_GetFloat32ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_FLOAT64:
return in.readArray((uint64_t*) JS_GetFloat64ArrayData(obj), nelems);
return in.readArray((uint64_t*) JS_GetFloat64ArrayData(obj, context()), nelems);
case SCTAG_TYPED_ARRAY_UINT8_CLAMPED:
return in.readArray(JS_GetUint8ClampedArrayData(obj), nelems);
return in.readArray(JS_GetUint8ClampedArrayData(obj, context()), nelems);
default:
JS_NOT_REACHED("unknown TypedArray type");
return false;

View File

@ -1183,40 +1183,41 @@ JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes);
* the various accessor JSAPI calls defined below.
*/
extern JS_FRIEND_API(JSBool)
JS_IsTypedArrayObject(JSObject *obj);
JS_IsTypedArrayObject(JSObject *obj, JSContext *cx);
/*
* Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may
* return false if a security wrapper is encountered that denies the
* unwrapping. If this test or one of the more specific tests succeeds, then it
* is safe to call the various ArrayBufferView accessor JSAPI calls defined
* below.
* below. cx MUST be non-NULL and valid.
*/
extern JS_FRIEND_API(JSBool)
JS_IsArrayBufferViewObject(JSObject *obj);
JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx);
/*
* Test for specific typed array types (ArrayBufferView subtypes)
*/
extern JS_FRIEND_API(JSBool)
JS_IsInt8Array(JSObject *obj);
JS_IsInt8Array(JSObject *obj, JSContext *cx);
extern JS_FRIEND_API(JSBool)
JS_IsUint8Array(JSObject *obj);
JS_IsUint8Array(JSObject *obj, JSContext *cx);
extern JS_FRIEND_API(JSBool)
JS_IsUint8ClampedArray(JSObject *obj);
JS_IsUint8ClampedArray(JSObject *obj, JSContext *cx);
extern JS_FRIEND_API(JSBool)
JS_IsInt16Array(JSObject *obj);
JS_IsInt16Array(JSObject *obj, JSContext *cx);
extern JS_FRIEND_API(JSBool)
JS_IsUint16Array(JSObject *obj);
JS_IsUint16Array(JSObject *obj, JSContext *cx);
extern JS_FRIEND_API(JSBool)
JS_IsInt32Array(JSObject *obj);
JS_IsInt32Array(JSObject *obj, JSContext *cx);
extern JS_FRIEND_API(JSBool)
JS_IsUint32Array(JSObject *obj);
JS_IsUint32Array(JSObject *obj, JSContext *cx);
extern JS_FRIEND_API(JSBool)
JS_IsFloat32Array(JSObject *obj);
JS_IsFloat32Array(JSObject *obj, JSContext *cx);
extern JS_FRIEND_API(JSBool)
JS_IsFloat64Array(JSObject *obj);
JS_IsFloat64Array(JSObject *obj, JSContext *cx);
/*
* Unwrap Typed arrays all at once. Return NULL without throwing if the object
@ -1224,37 +1225,38 @@ JS_IsFloat64Array(JSObject *obj);
* success, filling both outparameters.
*/
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsInt8Array(JSObject *obj, uint32_t *length, int8_t **data);
JS_GetObjectAsInt8Array(JSContext *cx, JSObject *obj, uint32_t *length, int8_t **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsUint8Array(JSObject *obj, uint32_t *length, uint8_t **data);
JS_GetObjectAsUint8Array(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsUint8ClampedArray(JSObject *obj, uint32_t *length, uint8_t **data);
JS_GetObjectAsUint8ClampedArray(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsInt16Array(JSObject *obj, uint32_t *length, int16_t **data);
JS_GetObjectAsInt16Array(JSContext *cx, JSObject *obj, uint32_t *length, int16_t **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsUint16Array(JSObject *obj, uint32_t *length, uint16_t **data);
JS_GetObjectAsUint16Array(JSContext *cx, JSObject *obj, uint32_t *length, uint16_t **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsInt32Array(JSObject *obj, uint32_t *length, int32_t **data);
JS_GetObjectAsInt32Array(JSContext *cx, JSObject *obj, uint32_t *length, int32_t **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsUint32Array(JSObject *obj, uint32_t *length, uint32_t **data);
JS_GetObjectAsUint32Array(JSContext *cx, JSObject *obj, uint32_t *length, uint32_t **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsFloat32Array(JSObject *obj, uint32_t *length, float **data);
JS_GetObjectAsFloat32Array(JSContext *cx, JSObject *obj, uint32_t *length, float **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsFloat64Array(JSObject *obj, uint32_t *length, double **data);
JS_GetObjectAsFloat64Array(JSContext *cx, JSObject *obj, uint32_t *length, double **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data);
JS_GetObjectAsArrayBufferView(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
extern JS_FRIEND_API(JSObject *)
JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data);
JS_GetObjectAsArrayBuffer(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
/*
* Get the type of elements in a typed array.
*
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
* be known that it would pass such a test: it is a typed array or a wrapper of
* a typed array, and the unwrapping will succeed.
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
* builds may be unable to assert when unwrapping should be disallowed.
*/
extern JS_FRIEND_API(JSArrayBufferViewType)
JS_GetTypedArrayType(JSObject *obj);
JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx);
/*
* Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may
@ -1263,17 +1265,18 @@ JS_GetTypedArrayType(JSObject *obj);
* accessor JSAPI calls defined below.
*/
extern JS_FRIEND_API(JSBool)
JS_IsArrayBufferObject(JSObject *obj);
JS_IsArrayBufferObject(JSObject *obj, JSContext *maybecx);
/*
* Return the available byte length of an array buffer.
*
* |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
* that it would pass such a test: it is an ArrayBuffer or a wrapper of an
* ArrayBuffer, and the unwrapping will succeed.
* ArrayBuffer, and the unwrapping will succeed. If cx is NULL, then DEBUG
* builds may be unable to assert when unwrapping should be disallowed.
*/
extern JS_FRIEND_API(uint32_t)
JS_GetArrayBufferByteLength(JSObject *obj);
JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx);
/*
* Return a pointer to an array buffer's data. The buffer is still owned by the
@ -1282,20 +1285,22 @@ JS_GetArrayBufferByteLength(JSObject *obj);
*
* |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
* that it would pass such a test: it is an ArrayBuffer or a wrapper of an
* ArrayBuffer, and the unwrapping will succeed.
* ArrayBuffer, and the unwrapping will succeed. If cx is NULL, then DEBUG
* builds may be unable to assert when unwrapping should be disallowed.
*/
extern JS_FRIEND_API(uint8_t *)
JS_GetArrayBufferData(JSObject *obj);
JS_GetArrayBufferData(JSObject *obj, JSContext *maybecx);
/*
* Return the number of elements in a typed array.
*
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
* be known that it would pass such a test: it is a typed array or a wrapper of
* a typed array, and the unwrapping will succeed.
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
* builds may be unable to assert when unwrapping should be disallowed.
*/
extern JS_FRIEND_API(uint32_t)
JS_GetTypedArrayLength(JSObject *obj);
JS_GetTypedArrayLength(JSObject *obj, JSContext *cx);
/*
* Return the byte offset from the start of an array buffer to the start of a
@ -1303,20 +1308,22 @@ JS_GetTypedArrayLength(JSObject *obj);
*
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
* be known that it would pass such a test: it is a typed array or a wrapper of
* a typed array, and the unwrapping will succeed.
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
* builds may be unable to assert when unwrapping should be disallowed.
*/
extern JS_FRIEND_API(uint32_t)
JS_GetTypedArrayByteOffset(JSObject *obj);
JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *cx);
/*
* Return the byte length of a typed array.
*
* |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
* be known that it would pass such a test: it is a typed array or a wrapper of
* a typed array, and the unwrapping will succeed.
* a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
* builds may be unable to assert when unwrapping should be disallowed.
*/
extern JS_FRIEND_API(uint32_t)
JS_GetTypedArrayByteLength(JSObject *obj);
JS_GetTypedArrayByteLength(JSObject *obj, JSContext *cx);
/*
* Check whether obj supports JS_ArrayBufferView* APIs. Note that this may
@ -1324,13 +1331,13 @@ JS_GetTypedArrayByteLength(JSObject *obj);
* unwrapping.
*/
extern JS_FRIEND_API(JSBool)
JS_IsArrayBufferViewObject(JSObject *obj);
JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx);
/*
* More generic name for JS_GetTypedArrayByteLength to cover DataViews as well
*/
extern JS_FRIEND_API(uint32_t)
JS_GetArrayBufferViewByteLength(JSObject *obj);
JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx);
/*
* Return a pointer to the start of the data referenced by a typed array. The
@ -1339,34 +1346,35 @@ JS_GetArrayBufferViewByteLength(JSObject *obj);
*
* |obj| must have passed a JS_Is*Array test, or somehow be known that it would
* pass such a test: it is a typed array or a wrapper of a typed array, and the
* unwrapping will succeed.
* unwrapping will succeed. If cx is NULL, then DEBUG builds may be unable to
* assert when unwrapping should be disallowed.
*/
extern JS_FRIEND_API(int8_t *)
JS_GetInt8ArrayData(JSObject *obj);
JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx);
extern JS_FRIEND_API(uint8_t *)
JS_GetUint8ArrayData(JSObject *obj);
JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx);
extern JS_FRIEND_API(uint8_t *)
JS_GetUint8ClampedArrayData(JSObject *obj);
JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx);
extern JS_FRIEND_API(int16_t *)
JS_GetInt16ArrayData(JSObject *obj);
JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx);
extern JS_FRIEND_API(uint16_t *)
JS_GetUint16ArrayData(JSObject *obj);
JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx);
extern JS_FRIEND_API(int32_t *)
JS_GetInt32ArrayData(JSObject *obj);
JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx);
extern JS_FRIEND_API(uint32_t *)
JS_GetUint32ArrayData(JSObject *obj);
JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx);
extern JS_FRIEND_API(float *)
JS_GetFloat32ArrayData(JSObject *obj);
JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx);
extern JS_FRIEND_API(double *)
JS_GetFloat64ArrayData(JSObject *obj);
JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx);
/*
* Same as above, but for any kind of ArrayBufferView. Prefer the type-specific
* versions when possible.
*/
extern JS_FRIEND_API(void *)
JS_GetArrayBufferViewData(JSObject *obj);
JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx);
/*
* Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been
@ -1374,13 +1382,15 @@ JS_GetArrayBufferViewData(JSObject *obj);
* object that would return true for JS_IsArrayBufferViewObject().
*/
extern JS_FRIEND_API(JSObject *)
JS_GetArrayBufferViewBuffer(JSObject *obj);
JS_GetArrayBufferViewBuffer(JSObject *obj, JSContext *maybecx);
/*
* Check whether obj supports JS_GetDataView* APIs.
* Check whether obj supports JS_GetDataView* APIs. Note that this may fail and
* throw an exception if a security wrapper is encountered that denies the
* operation.
*/
JS_FRIEND_API(JSBool)
JS_IsDataViewObject(JSObject *obj);
JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView);
/*
* Return the byte offset of a data view into its array buffer. |obj| must be a
@ -1388,10 +1398,11 @@ JS_IsDataViewObject(JSObject *obj);
*
* |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
* it would pass such a test: it is a data view or a wrapper of a data view,
* and the unwrapping will succeed.
* and the unwrapping will succeed. If cx is NULL, then DEBUG builds may be
* unable to assert when unwrapping should be disallowed.
*/
JS_FRIEND_API(uint32_t)
JS_GetDataViewByteOffset(JSObject *obj);
JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx);
/*
* Return the byte length of a data view.
@ -1402,7 +1413,7 @@ JS_GetDataViewByteOffset(JSObject *obj);
* unable to assert when unwrapping should be disallowed.
*/
JS_FRIEND_API(uint32_t)
JS_GetDataViewByteLength(JSObject *obj);
JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx);
/*
* Return a pointer to the beginning of the data referenced by a DataView.
@ -1413,7 +1424,7 @@ JS_GetDataViewByteLength(JSObject *obj);
* unable to assert when unwrapping should be disallowed.
*/
JS_FRIEND_API(void *)
JS_GetDataViewData(JSObject *obj);
JS_GetDataViewData(JSObject *obj, JSContext *maybecx);
/*
* This struct contains metadata passed from the DOM to the JS Engine for JIT

View File

@ -174,10 +174,16 @@ fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValu
return false;
/*
* Censor the caller if we don't have full access to it.
* Censor the caller if we can't PUNCTURE it.
*
* NB - This will get much much nicer with bug 800915
*/
JSObject &caller = vp.toObject();
if (caller.isWrapper() && !Wrapper::wrapperHandler(&caller)->isSafeToUnwrap()) {
JSErrorReporter reporter = JS_SetErrorReporter(cx, NULL);
bool punctureThrew = !UnwrapObjectChecked(cx, &caller);
JS_SetErrorReporter(cx, reporter);
if (punctureThrew) {
JS_ClearPendingException(cx);
vp.setNull();
} else if (caller.isFunction()) {
JSFunction *callerFun = caller.toFunction();

View File

@ -1873,11 +1873,9 @@ class TypedArrayTemplate
* compartment for a view in the target compartment referencing the
* ArrayBuffer in that same compartment.
*/
JSObject *wrapped = UnwrapObjectChecked(bufobj);
if (!wrapped) {
JS_ReportError(cx, "Permission denied to access object");
JSObject *wrapped = UnwrapObjectChecked(cx, bufobj);
if (!wrapped)
return NULL;
}
if (wrapped->isArrayBuffer()) {
/*
* And for even more fun, the new view's prototype should be
@ -3143,10 +3141,13 @@ JSFunctionSpec _typedArray::jsfuncs[] = { \
return TypedArrayTemplate<NativeType>::fromBuffer(cx, arrayBuffer, byteoffset, length, \
proto); \
} \
JS_FRIEND_API(JSBool) JS_Is ## Name ## Array(JSObject *obj) \
JS_FRIEND_API(JSBool) JS_Is ## Name ## Array(JSObject *obj, JSContext *cx) \
{ \
if (!(obj = UnwrapObjectChecked(obj))) \
MOZ_ASSERT(!cx->isExceptionPending()); \
if (!(obj = UnwrapObjectChecked(cx, obj))) { \
cx->clearPendingException(); \
return false; \
} \
Class *clasp = obj->getClass(); \
return (clasp == &TypedArray::classes[TypedArrayTemplate<NativeType>::ArrayTypeID()]); \
}
@ -3162,12 +3163,18 @@ IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float32, float)
IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double)
#define IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Name, ExternalType, InternalType) \
JS_FRIEND_API(JSObject *) JS_GetObjectAs ## Name ## Array(JSObject *obj, \
JS_FRIEND_API(JSObject *) JS_GetObjectAs ## Name ## Array(JSContext *cx, \
JSObject *obj, \
uint32_t *length, \
ExternalType **data) \
{ \
if (!(obj = UnwrapObjectChecked(obj))) \
return NULL; \
if (obj->isWrapper()) { \
MOZ_ASSERT(!cx->isExceptionPending()); \
if (!(obj = UnwrapObjectChecked(cx, obj))) { \
cx->clearPendingException(); \
return NULL; \
} \
} \
\
Class *clasp = obj->getClass(); \
if (clasp != &TypedArray::classes[TypedArrayTemplate<InternalType>::ArrayTypeID()]) \
@ -3564,42 +3571,76 @@ js_InitTypedArrayClasses(JSContext *cx, HandleObject obj)
/* JS Friend API */
JS_FRIEND_API(JSBool)
JS_IsArrayBufferObject(JSObject *obj)
// The typed array friend API defines a number of accessor functions that want
// to unwrap an argument, but in certain rare cases may not have a cx available
// and so pass in NULL instead. Use UnwrapObjectChecked when possible.
static JSObject *
CheckedUnwrap(JSContext *cx, JSObject *obj)
{
obj = UnwrapObjectChecked(obj);
return obj ? obj->isArrayBuffer() : false;
if (!cx)
return UnwrapObject(obj);
MOZ_ASSERT(!cx->isExceptionPending());
obj = UnwrapObjectChecked(cx, obj);
MOZ_ASSERT(obj);
return obj;
}
JS_FRIEND_API(JSBool)
JS_IsTypedArrayObject(JSObject *obj)
JS_IsArrayBufferObject(JSObject *objArg, JSContext *cx)
{
obj = UnwrapObjectChecked(obj);
return obj ? obj->isTypedArray() : false;
RootedObject obj_(cx, objArg);
MOZ_ASSERT(!cx->isExceptionPending());
JSObject *obj = UnwrapObjectChecked(cx, obj_);
if (!obj) {
cx->clearPendingException();
return false;
}
return obj->isArrayBuffer();
}
JS_FRIEND_API(JSBool)
JS_IsArrayBufferViewObject(JSObject *obj)
JS_IsTypedArrayObject(JSObject *objArg, JSContext *cx)
{
obj = UnwrapObjectChecked(obj);
return obj ? (obj->isTypedArray() || obj->isDataView()) : false;
RootedObject obj_(cx, objArg);
MOZ_ASSERT(!cx->isExceptionPending());
JSObject *obj = UnwrapObjectChecked(cx, obj_);
if (!obj) {
cx->clearPendingException();
return false;
}
return obj->isTypedArray();
}
JS_FRIEND_API(JSBool)
JS_IsArrayBufferViewObject(JSObject *objArg, JSContext *cx)
{
RootedObject obj_(cx, objArg);
MOZ_ASSERT(!cx->isExceptionPending());
JSObject *obj = UnwrapObjectChecked(cx, obj_);
if (!obj) {
cx->clearPendingException();
return false;
}
return obj->isTypedArray() || obj->isDataView();
}
JS_FRIEND_API(uint32_t)
JS_GetArrayBufferByteLength(JSObject *obj)
JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
return obj ? obj->asArrayBuffer().byteLength() : 0;
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return 0;
return obj->asArrayBuffer().byteLength();
}
JS_FRIEND_API(uint8_t *)
JS_GetArrayBufferData(JSObject *obj)
JS_GetArrayBufferData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
ArrayBufferObject &buffer = obj->asArrayBuffer();
if (!buffer.uninlineData(NULL))
if (!buffer.uninlineData(maybecx))
return NULL;
return buffer.dataPointer();
}
@ -3639,7 +3680,7 @@ JS_PUBLIC_API(JSBool)
JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents,
uint8_t **data)
{
if (!(obj = UnwrapObjectChecked(obj)))
if (!(obj = UnwrapObjectChecked(cx, obj)))
return false;
if (!obj->isArrayBuffer()) {
@ -3654,9 +3695,9 @@ JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents,
}
JS_FRIEND_API(uint32_t)
JS_GetTypedArrayLength(JSObject *obj)
JS_GetTypedArrayLength(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return 0;
JS_ASSERT(obj->isTypedArray());
@ -3664,9 +3705,9 @@ JS_GetTypedArrayLength(JSObject *obj)
}
JS_FRIEND_API(uint32_t)
JS_GetTypedArrayByteOffset(JSObject *obj)
JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return 0;
JS_ASSERT(obj->isTypedArray());
@ -3674,9 +3715,9 @@ JS_GetTypedArrayByteOffset(JSObject *obj)
}
JS_FRIEND_API(uint32_t)
JS_GetTypedArrayByteLength(JSObject *obj)
JS_GetTypedArrayByteLength(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return 0;
JS_ASSERT(obj->isTypedArray());
@ -3684,9 +3725,9 @@ JS_GetTypedArrayByteLength(JSObject *obj)
}
JS_FRIEND_API(JSArrayBufferViewType)
JS_GetTypedArrayType(JSObject *obj)
JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return ArrayBufferView::TYPE_MAX;
JS_ASSERT(obj->isTypedArray());
@ -3694,9 +3735,9 @@ JS_GetTypedArrayType(JSObject *obj)
}
JS_FRIEND_API(int8_t *)
JS_GetInt8ArrayData(JSObject *obj)
JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray());
@ -3705,9 +3746,9 @@ JS_GetInt8ArrayData(JSObject *obj)
}
JS_FRIEND_API(uint8_t *)
JS_GetUint8ArrayData(JSObject *obj)
JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray());
@ -3716,9 +3757,9 @@ JS_GetUint8ArrayData(JSObject *obj)
}
JS_FRIEND_API(uint8_t *)
JS_GetUint8ClampedArrayData(JSObject *obj)
JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray());
@ -3727,9 +3768,9 @@ JS_GetUint8ClampedArrayData(JSObject *obj)
}
JS_FRIEND_API(int16_t *)
JS_GetInt16ArrayData(JSObject *obj)
JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray());
@ -3738,9 +3779,9 @@ JS_GetInt16ArrayData(JSObject *obj)
}
JS_FRIEND_API(uint16_t *)
JS_GetUint16ArrayData(JSObject *obj)
JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray());
@ -3749,9 +3790,9 @@ JS_GetUint16ArrayData(JSObject *obj)
}
JS_FRIEND_API(int32_t *)
JS_GetInt32ArrayData(JSObject *obj)
JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray());
@ -3760,9 +3801,9 @@ JS_GetInt32ArrayData(JSObject *obj)
}
JS_FRIEND_API(uint32_t *)
JS_GetUint32ArrayData(JSObject *obj)
JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray());
@ -3771,9 +3812,9 @@ JS_GetUint32ArrayData(JSObject *obj)
}
JS_FRIEND_API(float *)
JS_GetFloat32ArrayData(JSObject *obj)
JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray());
@ -3782,9 +3823,9 @@ JS_GetFloat32ArrayData(JSObject *obj)
}
JS_FRIEND_API(double *)
JS_GetFloat64ArrayData(JSObject *obj)
JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray());
@ -3793,25 +3834,29 @@ JS_GetFloat64ArrayData(JSObject *obj)
}
JS_FRIEND_API(JSBool)
JS_IsDataViewObject(JSObject *obj)
JS_IsDataViewObject(JSContext *cx, JSObject *objArg, JSBool *isDataView)
{
obj = UnwrapObjectChecked(obj);
return obj ? obj->isDataView() : false;
RootedObject obj_(cx, objArg);
JSObject *obj = CheckedUnwrap(cx, obj_);
if (!obj)
return false;
*isDataView = obj->isDataView();
return true;
}
JS_FRIEND_API(uint32_t)
JS_GetDataViewByteOffset(JSObject *obj)
JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return 0;
return obj->asDataView().byteOffset();
}
JS_FRIEND_API(void *)
JS_GetDataViewData(JSObject *obj)
JS_GetDataViewData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isDataView());
@ -3819,9 +3864,9 @@ JS_GetDataViewData(JSObject *obj)
}
JS_FRIEND_API(uint32_t)
JS_GetDataViewByteLength(JSObject *obj)
JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return 0;
JS_ASSERT(obj->isDataView());
@ -3829,9 +3874,9 @@ JS_GetDataViewByteLength(JSObject *obj)
}
JS_FRIEND_API(void *)
JS_GetArrayBufferViewData(JSObject *obj)
JS_GetArrayBufferViewData(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
@ -3839,9 +3884,9 @@ JS_GetArrayBufferViewData(JSObject *obj)
}
JS_FRIEND_API(JSObject *)
JS_GetArrayBufferViewBuffer(JSObject *obj)
JS_GetArrayBufferViewBuffer(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return NULL;
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
@ -3849,9 +3894,9 @@ JS_GetArrayBufferViewBuffer(JSObject *obj)
}
JS_FRIEND_API(uint32_t)
JS_GetArrayBufferViewByteLength(JSObject *obj)
JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *maybecx)
{
obj = UnwrapObjectChecked(obj);
obj = CheckedUnwrap(maybecx, obj);
if (!obj)
return 0;
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
@ -3861,10 +3906,15 @@ JS_GetArrayBufferViewByteLength(JSObject *obj)
}
JS_FRIEND_API(JSObject *)
JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data)
JS_GetObjectAsArrayBufferView(JSContext *cx, JSObject *obj,
uint32_t *length, uint8_t **data)
{
if (!(obj = UnwrapObjectChecked(obj)))
return NULL;
if (obj->isWrapper()) {
if (!(obj = UnwrapObjectChecked(cx, obj))) {
cx->clearPendingException();
return NULL;
}
}
if (!(obj->isTypedArray() || obj->isDataView()))
return NULL;
@ -3877,10 +3927,14 @@ JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data)
}
JS_FRIEND_API(JSObject *)
JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
JS_GetObjectAsArrayBuffer(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data)
{
if (!(obj = UnwrapObjectChecked(obj)))
return NULL;
if (obj->isWrapper()) {
if (!(obj = UnwrapObjectChecked(cx, obj))) {
cx->clearPendingException();
return NULL;
}
}
if (!obj->isArrayBuffer())
return NULL;

View File

@ -109,18 +109,19 @@ js::UnwrapObject(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp)
}
JS_FRIEND_API(JSObject *)
js::UnwrapObjectChecked(RawObject obj)
js::UnwrapObjectChecked(JSContext *cx, RawObject objArg)
{
RootedObject obj(cx, objArg);
while (true) {
JSObject *wrapper = obj;
obj = UnwrapOneChecked(obj);
obj = UnwrapOneChecked(cx, obj);
if (!obj || obj == wrapper)
return obj;
}
}
JS_FRIEND_API(JSObject *)
js::UnwrapOneChecked(RawObject obj)
js::UnwrapOneChecked(JSContext *cx, HandleObject obj)
{
// Checked unwraps should never unwrap outer windows.
if (!obj->isWrapper() ||
@ -130,7 +131,13 @@ js::UnwrapOneChecked(RawObject obj)
}
Wrapper *handler = Wrapper::wrapperHandler(obj);
return handler->isSafeToUnwrap() ? Wrapper::wrappedObject(obj) : NULL;
bool rvOnFailure;
if (!handler->enter(cx, obj, JSID_VOID, Wrapper::PUNCTURE, &rvOnFailure))
return rvOnFailure ? (JSObject*) obj : NULL;
JSObject *ret = Wrapper::wrappedObject(obj);
JS_ASSERT(ret);
return ret;
}
bool
@ -153,7 +160,6 @@ js::IsCrossCompartmentWrapper(RawObject wrapper)
Wrapper::Wrapper(unsigned flags, bool hasPrototype) : DirectProxyHandler(&sWrapperFamily)
, mFlags(flags)
, mSafeToUnwrap(true)
{
setHasPrototype(hasPrototype);
}
@ -215,22 +221,25 @@ Wrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
}
/*
* Ordinarily, the convert trap would require unwrapping. However, the default
* Ordinarily, the convert trap would require a PUNCTURE. However, the default
* implementation of convert, JS_ConvertStub, obtains a default value by calling
* the toString/valueOf method on the wrapper, if any. Throwing if we can't unwrap
* in this case would be overly conservative. To make matters worse, XPConnect sometimes
* the toString/valueOf method on the wrapper, if any. Doing a PUNCTURE in this
* case would be overly conservative. To make matters worse, XPConnect sometimes
* installs a custom convert trap that obtains a default value by calling the
* toString method on the wrapper. Doing a puncture in this case would be overly
* conservative as well. We deal with these anomalies by falling back to the DefaultValue
* algorithm whenever unwrapping is forbidden.
* conservative as well. We deal with these anomalies by clearing the pending
* exception and falling back to the DefaultValue algorithm whenever the
* PUNCTURE fails.
*/
bool
Wrapper::defaultValue(JSContext *cx, JSObject *wrapper_, JSType hint, Value *vp)
{
RootedObject wrapper(cx, wrapper_);
if (!wrapperHandler(wrapper)->isSafeToUnwrap()) {
bool status;
if (!enter(cx, wrapper_, JSID_VOID, PUNCTURE, &status)) {
RootedValue v(cx);
JS_ClearPendingException(cx);
if (!DefaultValue(cx, wrapper, hint, &v))
return false;
*vp = v;
@ -787,9 +796,7 @@ CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
template <class Base>
SecurityWrapper<Base>::SecurityWrapper(unsigned flags)
: Base(flags)
{
Base::setSafeToUnwrap(false);
}
{}
template <class Base>
bool

View File

@ -29,13 +29,13 @@ class DummyFrameGuard;
class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
{
unsigned mFlags;
bool mSafeToUnwrap;
public:
enum Action {
GET,
SET,
CALL
CALL,
PUNCTURE
};
enum Flags {
@ -43,15 +43,6 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
LAST_USED_FLAG = CROSS_COMPARTMENT
};
/*
* Wrappers can explicitly specify that they are unsafe to unwrap from a
* security perspective (as is the case for SecurityWrappers). If a wrapper
* is not safe to unwrap, operations requiring full access to the underlying
* object (via UnwrapObjectChecked) will throw. Otherwise, they will succeed.
*/
void setSafeToUnwrap(bool safe) { mSafeToUnwrap = safe; };
bool isSafeToUnwrap() { return mSafeToUnwrap; };
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto,
JSObject *parent, Wrapper *handler);
@ -71,7 +62,24 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
* on the underlying object's |id| property. In the case when |act| is CALL,
* |id| is generally JSID_VOID.
*
* The |act| parameter to enter() specifies the action being performed.
* The |act| parameter to enter() specifies the action being performed. GET,
* SET, and CALL are self-explanatory, but PUNCTURE requires more
* explanation:
*
* GET and SET allow for a very fine-grained security membrane, through
* which access can be granted or denied on a per-property, per-object, and
* per-action basis. Sometimes though, we just want to asks if we can access
* _everything_ behind the wrapper barrier. For example, when the structured
* clone algorithm runs up against a cross-compartment wrapper, it needs to
* know whether it can enter the compartment and keep cloning, or whether it
* should throw. This is the role of PUNCTURE.
*
* PUNCTURE allows the policy to specify whether the wrapper barrier may
* be lifted - that is to say, whether the caller is allowed to access
* anything that the wrapped object could access. This is a very powerful
* permission, and thus should generally be denied for security wrappers
* except under very special circumstances. When |act| is PUNCTURE, |id|
* should be JSID_VOID.
*/
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act,
bool *bp);
@ -255,12 +263,12 @@ UnwrapObject(JSObject *obj, bool stopAtOuter = true, unsigned *flagsp = NULL);
// code should never be unwrapping outer window wrappers, we always stop at
// outer windows.
JS_FRIEND_API(JSObject *)
UnwrapObjectChecked(RawObject obj);
UnwrapObjectChecked(JSContext *cx, RawObject obj);
// Unwrap only the outermost security wrapper, with the same semantics as
// above. This is the checked version of Wrapper::wrappedObject.
JS_FRIEND_API(JSObject *)
UnwrapOneChecked(RawObject obj);
UnwrapOneChecked(JSContext *cx, HandleObject obj);
JS_FRIEND_API(bool)
IsCrossCompartmentWrapper(RawObject obj);

View File

@ -1819,11 +1819,9 @@ Debugger::unwrapDebuggeeArgument(JSContext *cx, const Value &v)
}
/* If we have a cross-compartment wrapper, dereference as far as is secure. */
obj = UnwrapObjectChecked(obj);
if (!obj) {
JS_ReportError(cx, "Permission denied to access object");
obj = UnwrapObjectChecked(cx, obj);
if (!obj)
return NULL;
}
/* If that produced an outer window, innerize it. */
obj = GetInnerObject(cx, obj);
@ -4467,8 +4465,18 @@ static JSBool
DebuggerObject_unwrap(JSContext *cx, unsigned argc, Value *vp)
{
THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "unwrap", args, dbg, referent);
JSObject *unwrapped = UnwrapOneChecked(referent);
JSObject *unwrapped = UnwrapOneChecked(cx, referent);
if (!unwrapped) {
// If we were terminated, then pass that along.
if (!cx->isExceptionPending())
return false;
// If the unwrap operation threw an exception, assume it's a
// security exception, and return null. It seems like the wrappers
// in use in Firefox just call JS_ReportError, so we have no way to
// distinguish genuine should-not-unwrap errors from other kinds of
// errors.
cx->clearPendingException();
vp->setNull();
return true;
}

View File

@ -2711,7 +2711,7 @@ nsXPCComponents_Utils::LookupMethod(const JS::Value& object,
// we don't have full access to the other compartment, in which case we throw.
// Otherwise, enter the compartment.
if (js::IsCrossCompartmentWrapper(obj)) {
obj = js::UnwrapOneChecked(obj);
obj = js::UnwrapOneChecked(cx, obj);
if (!obj)
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
@ -3863,7 +3863,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
{
JS_AbortIfWrongThread(JS_GetRuntime(cx));
sandbox = js::UnwrapObjectChecked(sandbox);
sandbox = js::UnwrapObjectChecked(cx, sandbox);
if (!sandbox || js::GetObjectJSClass(sandbox) != &SandboxClass) {
return NS_ERROR_INVALID_ARG;
}

View File

@ -1483,7 +1483,8 @@ failure:
// of the output does not exceed UINT32_MAX bytes. Allocate
// the memory and copy the elements by memcpy.
static JSBool
CheckTargetAndPopulate(const nsXPTType& type,
CheckTargetAndPopulate(JSContext *cx,
const nsXPTType& type,
uint8_t requiredType,
size_t typeSize,
uint32_t count,
@ -1514,7 +1515,7 @@ CheckTargetAndPopulate(const nsXPTType& type,
return false;
}
memcpy(*output, JS_GetArrayBufferViewData(tArr), byteSize);
memcpy(*output, JS_GetArrayBufferViewData(tArr, cx), byteSize);
return true;
}
@ -1528,7 +1529,8 @@ CheckTargetAndPopulate(const nsXPTType& type,
// static
JSBool
XPCConvert::JSTypedArray2Native(void** d,
XPCConvert::JSTypedArray2Native(JSContext* cx,
void** d,
JSObject* jsArray,
uint32_t count,
const nsXPTType& type,
@ -1536,11 +1538,11 @@ XPCConvert::JSTypedArray2Native(void** d,
{
NS_ABORT_IF_FALSE(jsArray, "bad param");
NS_ABORT_IF_FALSE(d, "bad param");
NS_ABORT_IF_FALSE(JS_IsTypedArrayObject(jsArray), "not a typed array");
NS_ABORT_IF_FALSE(JS_IsTypedArrayObject(jsArray, cx), "not a typed array");
// Check the actual length of the input array against the
// given size_is.
uint32_t len = JS_GetTypedArrayLength(jsArray);
uint32_t len = JS_GetTypedArrayLength(jsArray, cx);
if (len < count) {
if (pErr)
*pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
@ -1550,9 +1552,9 @@ XPCConvert::JSTypedArray2Native(void** d,
void* output = nullptr;
switch (JS_GetTypedArrayType(jsArray)) {
switch (JS_GetTypedArrayType(jsArray, cx)) {
case js::ArrayBufferView::TYPE_INT8:
if (!CheckTargetAndPopulate(nsXPTType::T_I8, type,
if (!CheckTargetAndPopulate(cx, nsXPTType::T_I8, type,
sizeof(int8_t), count,
jsArray, &output, pErr)) {
return false;
@ -1561,7 +1563,7 @@ XPCConvert::JSTypedArray2Native(void** d,
case js::ArrayBufferView::TYPE_UINT8:
case js::ArrayBufferView::TYPE_UINT8_CLAMPED:
if (!CheckTargetAndPopulate(nsXPTType::T_U8, type,
if (!CheckTargetAndPopulate(cx, nsXPTType::T_U8, type,
sizeof(uint8_t), count,
jsArray, &output, pErr)) {
return false;
@ -1569,7 +1571,7 @@ XPCConvert::JSTypedArray2Native(void** d,
break;
case js::ArrayBufferView::TYPE_INT16:
if (!CheckTargetAndPopulate(nsXPTType::T_I16, type,
if (!CheckTargetAndPopulate(cx, nsXPTType::T_I16, type,
sizeof(int16_t), count,
jsArray, &output, pErr)) {
return false;
@ -1577,7 +1579,7 @@ XPCConvert::JSTypedArray2Native(void** d,
break;
case js::ArrayBufferView::TYPE_UINT16:
if (!CheckTargetAndPopulate(nsXPTType::T_U16, type,
if (!CheckTargetAndPopulate(cx, nsXPTType::T_U16, type,
sizeof(uint16_t), count,
jsArray, &output, pErr)) {
return false;
@ -1585,7 +1587,7 @@ XPCConvert::JSTypedArray2Native(void** d,
break;
case js::ArrayBufferView::TYPE_INT32:
if (!CheckTargetAndPopulate(nsXPTType::T_I32, type,
if (!CheckTargetAndPopulate(cx, nsXPTType::T_I32, type,
sizeof(int32_t), count,
jsArray, &output, pErr)) {
return false;
@ -1593,7 +1595,7 @@ XPCConvert::JSTypedArray2Native(void** d,
break;
case js::ArrayBufferView::TYPE_UINT32:
if (!CheckTargetAndPopulate(nsXPTType::T_U32, type,
if (!CheckTargetAndPopulate(cx, nsXPTType::T_U32, type,
sizeof(uint32_t), count,
jsArray, &output, pErr)) {
return false;
@ -1601,7 +1603,7 @@ XPCConvert::JSTypedArray2Native(void** d,
break;
case js::ArrayBufferView::TYPE_FLOAT32:
if (!CheckTargetAndPopulate(nsXPTType::T_FLOAT, type,
if (!CheckTargetAndPopulate(cx, nsXPTType::T_FLOAT, type,
sizeof(float), count,
jsArray, &output, pErr)) {
return false;
@ -1609,7 +1611,7 @@ XPCConvert::JSTypedArray2Native(void** d,
break;
case js::ArrayBufferView::TYPE_FLOAT64:
if (!CheckTargetAndPopulate(nsXPTType::T_DOUBLE, type,
if (!CheckTargetAndPopulate(cx, nsXPTType::T_DOUBLE, type,
sizeof(double), count,
jsArray, &output, pErr)) {
return false;
@ -1663,8 +1665,8 @@ XPCConvert::JSArray2Native(JSContext* cx, void** d, JS::Value s,
JSObject* jsarray = &s.toObject();
// If this is a typed array, then try a fast conversion with memcpy.
if (JS_IsTypedArrayObject(jsarray)) {
return JSTypedArray2Native(d, jsarray, count, type, pErr);
if (JS_IsTypedArrayObject(jsarray, cx)) {
return JSTypedArray2Native(cx, d, jsarray, count, type, pErr);
}
if (!JS_IsArrayObject(cx, jsarray)) {

View File

@ -3368,7 +3368,8 @@ public:
uint32_t count, const nsXPTType& type,
const nsID* iid, nsresult* pErr);
static JSBool JSTypedArray2Native(void** d,
static JSBool JSTypedArray2Native(JSContext* cx,
void** d,
JSObject* jsarray,
uint32_t count,
const nsXPTType& type,

View File

@ -231,6 +231,11 @@ AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapper, jsid
JSObject *obj = Wrapper::wrappedObject(wrapper);
// PUNCTURE Is always denied for cross-origin access.
if (act == Wrapper::PUNCTURE) {
return false;
}
const char *name;
js::Class *clasp = js::GetObjectClass(obj);
NS_ASSERTION(Jsvalify(clasp) != &XrayUtils::HolderClass, "shouldn't have a holder here");
@ -340,6 +345,9 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
if (act == Wrapper::CALL)
return true;
if (act == Wrapper::PUNCTURE)
return false;
jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS);
// We need to enter the wrappee's compartment to look at __exposedProps__,
@ -354,7 +362,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
// Always permit access to "length" and indexed properties of arrays.
if ((JS_IsArrayObject(cx, wrappedObject) ||
JS_IsTypedArrayObject(wrappedObject)) &&
JS_IsTypedArrayObject(wrappedObject, cx)) &&
((JSID_IS_INT(id) && JSID_TO_INT(id) >= 0) ||
(JSID_IS_STRING(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "length")))) {
return true; // Allow

View File

@ -96,7 +96,9 @@ struct LocationPolicy : public Policy {
// We should only be dealing with Location objects here.
MOZ_ASSERT(WrapperFactory::IsLocationObject(js::UnwrapObject(wrapper)));
if ((AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act) ||
// Location object security is complicated enough. Don't allow punctures.
if (act != js::Wrapper::PUNCTURE &&
(AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act) ||
AccessCheck::isLocationObjectSameOrigin(cx, wrapper))) {
return true;
}

View File

@ -133,13 +133,20 @@ FilteringWrapper<Base, Policy>::enter(JSContext *cx, JSObject *wrapper, jsid id,
#define SOW FilteringWrapper<CrossCompartmentSecurityWrapper, OnlyIfSubjectIsSystem>
#define SCSOW FilteringWrapper<SameCompartmentSecurityWrapper, OnlyIfSubjectIsSystem>
#define XOW FilteringWrapper<SecurityXrayXPCWN, CrossOriginAccessiblePropertiesOnly>
#define DXOW FilteringWrapper<SecurityXrayDOM, CrossOriginAccessiblePropertiesOnly>
#define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, CrossOriginAccessiblePropertiesOnly>
#define LW FilteringWrapper<SCSecurityXrayXPCWN, LocationPolicy>
#define XLW FilteringWrapper<SecurityXrayXPCWN, LocationPolicy>
#define CW FilteringWrapper<SameCompartmentSecurityWrapper, ComponentsObjectPolicy>
#define XCW FilteringWrapper<CrossCompartmentSecurityWrapper, ComponentsObjectPolicy>
#define XOW FilteringWrapper<XrayWrapper<CrossCompartmentSecurityWrapper>, \
CrossOriginAccessiblePropertiesOnly>
#define DXOW FilteringWrapper<XrayDOM, \
CrossOriginAccessiblePropertiesOnly>
#define NNXOW FilteringWrapper<CrossCompartmentSecurityWrapper, \
CrossOriginAccessiblePropertiesOnly>
#define LW FilteringWrapper<XrayWrapper<SameCompartmentSecurityWrapper>, \
LocationPolicy>
#define XLW FilteringWrapper<XrayWrapper<CrossCompartmentSecurityWrapper>, \
LocationPolicy>
#define CW FilteringWrapper<SameCompartmentSecurityWrapper, \
ComponentsObjectPolicy>
#define XCW FilteringWrapper<CrossCompartmentSecurityWrapper, \
ComponentsObjectPolicy>
template<> SOW SOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
WrapperFactory::SOW_FLAG);
template<> SCSOW SCSOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |

View File

@ -291,31 +291,6 @@ GetWrappedNative(JSContext *cx, JSObject *obj)
: nullptr;
}
#ifdef DEBUG
static void
DEBUG_CheckUnwrapSafety(JSObject *obj, js::Wrapper *handler,
JSCompartment *origin, JSCompartment *target)
{
typedef FilteringWrapper<CrossCompartmentSecurityWrapper, OnlyIfSubjectIsSystem> XSOW;
if (AccessCheck::isChrome(target) || xpc::IsUniversalXPConnectEnabled(target)) {
// If the caller is chrome (or effectively so), unwrap should always be allowed.
MOZ_ASSERT(handler->isSafeToUnwrap());
} else if (WrapperFactory::IsLocationObject(obj) ||
WrapperFactory::IsComponentsObject(obj) ||
handler == &XSOW::singleton)
{
// This is an object that is restricted regardless of origin.
MOZ_ASSERT(!handler->isSafeToUnwrap());
} else {
// Otherwise, it should depend on whether the target subsumes the origin.
MOZ_ASSERT(handler->isSafeToUnwrap() == AccessCheck::subsumes(target, origin));
}
}
#else
#define DEBUG_CheckUnwrapSafety(obj, handler, origin, target) {}
#endif
JSObject *
WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj,
JSObject *wrappedProto, JSObject *parent,
@ -348,9 +323,10 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj,
// Native objects must be wrapped into an X-ray wrapper.
XrayType type = GetXrayType(obj);
if (type == XrayForDOMObject) {
wrapper = &PermissiveXrayDOM::singleton;
wrapper = &XrayDOM::singleton;
} else if (type == XrayForWrappedNative) {
wrapper = &PermissiveXrayXPCWN::singleton;
typedef XrayWrapper<CrossCompartmentWrapper> Xray;
wrapper = &Xray::singleton;
} else {
wrapper = &CrossCompartmentWrapper::singleton;
}
@ -371,12 +347,13 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj,
if (targetdata &&
(wn = GetWrappedNative(cx, obj)) &&
wn->HasProto() && wn->GetProto()->ClassIsDOMObject()) {
typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray;
if (IsLocationObject(obj))
wrapper = &FilteringWrapper<SecurityXrayXPCWN, LocationPolicy>::singleton;
wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton;
else
wrapper = &FilteringWrapper<SecurityXrayXPCWN, CrossOriginAccessiblePropertiesOnly>::singleton;
wrapper = &FilteringWrapper<Xray, CrossOriginAccessiblePropertiesOnly>::singleton;
} else if (mozilla::dom::UseDOMXray(obj)) {
wrapper = &FilteringWrapper<SecurityXrayDOM, CrossOriginAccessiblePropertiesOnly>::singleton;
wrapper = &FilteringWrapper<XrayDOM, CrossOriginAccessiblePropertiesOnly>::singleton;
} else if (IsComponentsObject(obj)) {
wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
ComponentsObjectPolicy>::singleton;
@ -431,7 +408,8 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj,
wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
OnlyIfSubjectIsSystem>::singleton;
} else if (IsLocationObject(obj)) {
wrapper = &FilteringWrapper<SecurityXrayXPCWN, LocationPolicy>::singleton;
typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray;
wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton;
} else if (IsComponentsObject(obj)) {
wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
ComponentsObjectPolicy>::singleton;
@ -439,9 +417,10 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj,
(type = GetXrayType(obj)) == NotXray) {
wrapper = &CrossCompartmentWrapper::singleton;
} else if (type == XrayForDOMObject) {
wrapper = &PermissiveXrayDOM::singleton;
wrapper = &XrayDOM::singleton;
} else {
wrapper = &PermissiveXrayXPCWN::singleton;
typedef XrayWrapper<CrossCompartmentWrapper> Xray;
wrapper = &Xray::singleton;
}
} else {
NS_ASSERTION(!AccessCheck::needsSystemOnlyWrapper(obj),
@ -454,22 +433,22 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj,
wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
CrossOriginAccessiblePropertiesOnly>::singleton;
} else if (type == XrayForDOMObject) {
wrapper = &FilteringWrapper<SecurityXrayDOM,
wrapper = &FilteringWrapper<XrayDOM,
CrossOriginAccessiblePropertiesOnly>::singleton;
} else {
typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray;
// Location objects can become same origin after navigation, so we might
// have to grant transparent access later on.
if (IsLocationObject(obj)) {
wrapper = &FilteringWrapper<SecurityXrayXPCWN, LocationPolicy>::singleton;
wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton;
} else {
wrapper = &FilteringWrapper<SecurityXrayXPCWN,
CrossOriginAccessiblePropertiesOnly>::singleton;
wrapper = &FilteringWrapper<Xray,
CrossOriginAccessiblePropertiesOnly>::singleton;
}
}
}
DEBUG_CheckUnwrapSafety(obj, wrapper, origin, target);
if (existing && proxyProto == wrappedProto)
return Wrapper::Renew(cx, existing, obj, wrapper);
@ -492,11 +471,11 @@ WrapperFactory::WrapForSameCompartment(JSContext *cx, JSObject *obj)
MOZ_ASSERT(wn, "Trying to wrap a dead WN!");
// The WN knows what to do.
JSObject *wrapper = wn->GetSameCompartmentSecurityWrapper(cx);
MOZ_ASSERT_IF(wrapper != obj, !Wrapper::wrapperHandler(wrapper)->isSafeToUnwrap());
return wrapper;
return wn->GetSameCompartmentSecurityWrapper(cx);
}
typedef FilteringWrapper<XrayWrapper<SameCompartmentSecurityWrapper>, LocationPolicy> LW;
bool
WrapperFactory::IsLocationObject(JSObject *obj)
{
@ -510,8 +489,7 @@ WrapperFactory::WrapLocationObject(JSContext *cx, JSObject *obj)
JSObject *proto;
if (!js::GetObjectProto(cx, obj, &proto))
return nullptr;
return Wrapper::New(cx, obj, proto, js::GetObjectParent(obj),
&FilteringWrapper<SCSecurityXrayXPCWN, LocationPolicy>::singleton);
return Wrapper::New(cx, obj, proto, js::GetObjectParent(obj), &LW::singleton);
}
// Call WaiveXrayAndWrap when you have a JS object that you don't want to be
@ -586,9 +564,9 @@ WrapperFactory::WrapForSameCompartmentXray(JSContext *cx, JSObject *obj)
// Select the appropriate proxy handler.
Wrapper *wrapper = NULL;
if (type == XrayForWrappedNative)
wrapper = &SCPermissiveXrayXPCWN::singleton;
wrapper = &XrayWrapper<Wrapper>::singleton;
else if (type == XrayForDOMObject)
wrapper = &SCPermissiveXrayDOM::singleton;
wrapper = &XrayWrapper<Wrapper, DOMXrayTraits>::singleton;
else
MOZ_NOT_REACHED("Bad Xray type");

View File

@ -1702,26 +1702,37 @@ XrayWrapper<Base, Traits>::construct(JSContext *cx, JSObject *wrapper, unsigned
return Traits::construct(cx, wrapper, argc, argv, rval);
}
/*
* The Permissive / Security variants should be used depending on whether the
* compartment of the wrapper is guranteed to subsume the compartment of the
* wrapped object (i.e. - whether it is safe from a security perspective to
* unwrap the wrapper).
*/
template<>
PermissiveXrayXPCWN PermissiveXrayXPCWN::singleton(0);
template<>
SecurityXrayXPCWN SecurityXrayXPCWN::singleton(0);
template<>
PermissiveXrayDOM PermissiveXrayDOM::singleton(0);
template<>
SecurityXrayDOM SecurityXrayDOM::singleton(0);
template<>
SCPermissiveXrayXPCWN SCPermissiveXrayXPCWN::singleton(0);
template<>
SCSecurityXrayXPCWN SCSecurityXrayXPCWN::singleton(0);
template<>
SCPermissiveXrayDOM SCPermissiveXrayDOM::singleton(0);
#define XRAY XrayWrapper<CrossCompartmentSecurityWrapper, XPCWrappedNativeXrayTraits >
template <> XRAY XRAY::singleton(0);
template class XRAY;
#undef XRAY
#define XRAY XrayWrapper<SameCompartmentSecurityWrapper, XPCWrappedNativeXrayTraits >
template <> XRAY XRAY::singleton(0);
template class XRAY;
#undef XRAY
#define XRAY XrayWrapper<CrossCompartmentWrapper, XPCWrappedNativeXrayTraits >
template <> XRAY XRAY::singleton(0);
template class XRAY;
#undef XRAY
#define XRAY XrayWrapper<CrossCompartmentWrapper, DOMXrayTraits >
template <> XRAY XRAY::singleton(0);
template class XRAY;
#undef XRAY
/* Same-compartment non-filtering versions. */
#define XRAY XrayWrapper<Wrapper, XPCWrappedNativeXrayTraits >
template <> XRAY XRAY::singleton(0);
template class XRAY;
#undef XRAY
#define XRAY XrayWrapper<Wrapper, DOMXrayTraits >
template <> XRAY XRAY::singleton(0);
template class XRAY;
#undef XRAY
}

View File

@ -93,13 +93,7 @@ class XrayWrapper : public Base {
JS::AutoIdVector &props);
};
typedef XrayWrapper<js::CrossCompartmentWrapper, XPCWrappedNativeXrayTraits > PermissiveXrayXPCWN;
typedef XrayWrapper<js::CrossCompartmentSecurityWrapper, XPCWrappedNativeXrayTraits > SecurityXrayXPCWN;
typedef XrayWrapper<js::CrossCompartmentWrapper, DOMXrayTraits > PermissiveXrayDOM;
typedef XrayWrapper<js::CrossCompartmentSecurityWrapper, DOMXrayTraits > SecurityXrayDOM;
typedef XrayWrapper<js::SameCompartmentSecurityWrapper, XPCWrappedNativeXrayTraits > SCSecurityXrayXPCWN;
typedef XrayWrapper<js::Wrapper, XPCWrappedNativeXrayTraits > SCPermissiveXrayXPCWN;
typedef XrayWrapper<js::Wrapper, DOMXrayTraits > SCPermissiveXrayDOM;
typedef XrayWrapper<js::CrossCompartmentWrapper, DOMXrayTraits > XrayDOM;
class SandboxProxyHandler : public js::Wrapper {
public: