diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 5866be21746f..75e9f16f29c0 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -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; diff --git a/content/base/src/nsDOMBlobBuilder.cpp b/content/base/src/nsDOMBlobBuilder.cpp index 83175487fd10..b1a4dc7d99ec 100644 --- a/content/base/src/nsDOMBlobBuilder.cpp +++ b/content/base/src/nsDOMBlobBuilder.cpp @@ -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 >& 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)); } diff --git a/content/base/src/nsDOMDataChannel.cpp b/content/base/src/nsDOMDataChannel.cpp index c17b822ac666..83cdec3566da 100644 --- a/content/base/src/nsDOMDataChannel.cpp +++ b/content/base/src/nsDOMDataChannel.cpp @@ -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(JS_GetArrayBufferData(obj)); + (JS_IsArrayBufferObject(obj, aCx))) { + int32_t len = JS_GetArrayBufferByteLength(obj, aCx); + char* data = reinterpret_cast(JS_GetArrayBufferData(obj, aCx)); aStringOut.Assign(data, len); aIsBinary = true; diff --git a/content/base/src/nsDOMFileReader.cpp b/content/base/src/nsDOMFileReader.cpp index d20a3fe31a11..4741abfe7bdf 100644 --- a/content/base/src/nsDOMFileReader.cpp +++ b/content/base/src/nsDOMFileReader.cpp @@ -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"); } diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index b0b097e538b4..d457bd9f883e 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -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); } } diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp index b02799835ffe..88bd1830cc5d 100644 --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -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(), diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index e88ab1d38ce8..fcc1bd0e95c3 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -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, diff --git a/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp b/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp index 408095be72c9..eb0e207cedb4 100644 --- a/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp +++ b/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp @@ -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; diff --git a/content/html/content/src/nsHTMLAudioElement.cpp b/content/html/content/src/nsHTMLAudioElement.cpp index 94ca49d33c33..95047585251b 100644 --- a/content/html/content/src/nsHTMLAudioElement.cpp +++ b/content/html/content/src/nsHTMLAudioElement.cpp @@ -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 diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 6f4cb9de6194..16335daeceed 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -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; diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 5eceb1d32603..a64bff6f73d8 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -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)) { diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 2f1929aee503..79866d87e535 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -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). @@ -1314,11 +1314,6 @@ public: mImpl.construct(); } - template - void Construct(const T1 &t1) { - mImpl.construct(t1); - } - template void Construct(const T1 &t1, const T2 &t2) { mImpl.construct(t1, t2); diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index a6bbc4617f08..522f0c340359 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -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" % diff --git a/dom/bindings/TypedArray.h b/dom/bindings/TypedArray.h index 9e179c8fe8a0..2a6f17bcb96e 100644 --- a/dom/bindings/TypedArray.h +++ b/dom/bindings/TypedArray.h @@ -19,11 +19,11 @@ namespace dom { * or array buffer object. */ template + 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 struct TypedArray : public TypedArray_base { - TypedArray(JSObject* obj) : - TypedArray_base(obj) + TypedArray(JSContext* cx, JSObject* obj) : + TypedArray_base(cx, obj) {} static inline JSObject* @@ -75,7 +75,7 @@ struct TypedArray : public TypedArray_base { return NULL; } if (data) { - T* buf = static_cast(GetData(obj)); + T* buf = static_cast(GetData(obj, cx)); memcpy(buf, data, length*sizeof(T)); } return obj; diff --git a/dom/file/LockedFile.cpp b/dom/file/LockedFile.cpp index f24b4dac3874..944d4a0d3452 100644 --- a/dom/file/LockedFile.cpp +++ b/dom/file/LockedFile.cpp @@ -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(JS_GetArrayBufferData(obj)); - uint32_t length = JS_GetArrayBufferByteLength(obj); + if (JS_IsArrayBufferObject(obj, aCx)) { + char* data = reinterpret_cast(JS_GetArrayBufferData(obj, aCx)); + uint32_t length = JS_GetArrayBufferByteLength(obj, aCx); rv = NS_NewByteInputStream(aInputStream, data, length, NS_ASSIGNMENT_COPY); diff --git a/dom/network/src/TCPSocketChild.cpp b/dom/network/src/TCPSocketChild.cpp index ac3e2b1f0be5..546c49121f8b 100644 --- a/dom/network/src/TCPSocketChild.cpp +++ b/dom/network/src/TCPSocketChild.cpp @@ -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; } diff --git a/dom/network/src/TCPSocketParent.cpp b/dom/network/src/TCPSocketParent.cpp index fb29176ff565..95f4da39711e 100644 --- a/dom/network/src/TCPSocketParent.cpp +++ b/dom/network/src/TCPSocketParent.cpp @@ -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; diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index ad9dee043d2a..5faf672ba711 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -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; diff --git a/dom/system/gonk/SystemWorkerManager.cpp b/dom/system/gonk/SystemWorkerManager.cpp index 5b1b5fd10519..834efe7a1838 100644 --- a/dom/system/gonk/SystemWorkerManager.cpp +++ b/dom/system/gonk/SystemWorkerManager.cpp @@ -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); diff --git a/dom/workers/FileReaderSync.cpp b/dom/workers/FileReaderSync.cpp index 55e155807696..14e13ec07de2 100644 --- a/dom/workers/FileReaderSync.cpp +++ b/dom/workers/FileReaderSync.cpp @@ -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 stream; rv = blob->GetInternalStream(getter_AddRefs(stream)); diff --git a/dom/workers/ImageData.cpp b/dom/workers/ImageData.cpp index 90fd6498a968..0195e0bbd4f5 100644 --- a/dom/workers/ImageData.cpp +++ b/dom/workers/ImageData.cpp @@ -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) { diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index b1e5da167a11..9f99c33b86f2 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -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 { diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index fadd146d6612..1991608b2110 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -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(buffer) = JS_GetArrayBufferData(valObj); + *static_cast(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(buffer) = JS_GetArrayBufferViewData(valObj); + *static_cast(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 diff --git a/js/src/jsapi-tests/testArrayBuffer.cpp b/js/src/jsapi-tests/testArrayBuffer.cpp index c8432e1886b3..2dd591e53593 100644 --- a/js/src/jsapi-tests/testArrayBuffer.cpp +++ b/js/src/jsapi-tests/testArrayBuffer.cpp @@ -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(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(data), MAGIC_VALUE_2); CHECK(JS_GetElement(cx, dstview, 0, &v)); diff --git a/js/src/jsapi-tests/testTypedArrays.cpp b/js/src/jsapi-tests/testTypedArrays.cpp index e4fb7cf81d7f..7a4cb17953db 100644 --- a/js/src/jsapi-tests/testTypedArrays.cpp +++ b/js/src/jsapi-tests/testTypedArrays.cpp @@ -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(cx) && @@ -55,24 +55,24 @@ BEGIN_TEST(testTypedArrays) template + 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 + 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(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); diff --git a/js/src/jsclone.cpp b/js/src/jsclone.cpp index ccfcfe7bbb8c..58d33da2580c 100644 --- a/js/src/jsclone.cpp +++ b/js/src/jsclone.cpp @@ -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; diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 45e03a1b77dc..3a659d2fbf60 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -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 diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 28fa378293f5..254337bc26ef 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -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(); diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 39ddba59e9bc..bb4b4d218466 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -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::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::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::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; diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 9a7c1f605fa5..7b17f9efd203 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -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 SecurityWrapper::SecurityWrapper(unsigned flags) : Base(flags) -{ - Base::setSafeToUnwrap(false); -} +{} template bool diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index b2837c462532..a29bdbce43e2 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -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); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 741a512cf297..922d9b03c10a 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -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; } diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 249c6423b518..38fd1b487cf7 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -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; } diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index 2f573a33f75e..e925b4e29f39 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -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)) { diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 43c9494d7919..1a7b3c6e9179 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -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, diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index fd5fd3998883..d302171674fb 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -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 diff --git a/js/xpconnect/wrappers/AccessCheck.h b/js/xpconnect/wrappers/AccessCheck.h index 0eb7fc01e3e4..e85c3767f2f2 100644 --- a/js/xpconnect/wrappers/AccessCheck.h +++ b/js/xpconnect/wrappers/AccessCheck.h @@ -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; } diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index 13a7eda255df..373a7926e24b 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -133,13 +133,20 @@ FilteringWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, #define SOW FilteringWrapper #define SCSOW FilteringWrapper -#define XOW FilteringWrapper -#define DXOW FilteringWrapper -#define NNXOW FilteringWrapper -#define LW FilteringWrapper -#define XLW FilteringWrapper -#define CW FilteringWrapper -#define XCW FilteringWrapper +#define XOW FilteringWrapper, \ + CrossOriginAccessiblePropertiesOnly> +#define DXOW FilteringWrapper +#define NNXOW FilteringWrapper +#define LW FilteringWrapper, \ + LocationPolicy> +#define XLW FilteringWrapper, \ + LocationPolicy> +#define CW FilteringWrapper +#define XCW FilteringWrapper template<> SOW SOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG | WrapperFactory::SOW_FLAG); template<> SCSOW SCSOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG | diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index d17c1c75ab49..092bea3071e3 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -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 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 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 Xray; if (IsLocationObject(obj)) - wrapper = &FilteringWrapper::singleton; + wrapper = &FilteringWrapper::singleton; else - wrapper = &FilteringWrapper::singleton; + wrapper = &FilteringWrapper::singleton; } else if (mozilla::dom::UseDOMXray(obj)) { - wrapper = &FilteringWrapper::singleton; + wrapper = &FilteringWrapper::singleton; } else if (IsComponentsObject(obj)) { wrapper = &FilteringWrapper::singleton; @@ -431,7 +408,8 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj, wrapper = &FilteringWrapper::singleton; } else if (IsLocationObject(obj)) { - wrapper = &FilteringWrapper::singleton; + typedef XrayWrapper Xray; + wrapper = &FilteringWrapper::singleton; } else if (IsComponentsObject(obj)) { wrapper = &FilteringWrapper::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 Xray; + wrapper = &Xray::singleton; } } else { NS_ASSERTION(!AccessCheck::needsSystemOnlyWrapper(obj), @@ -454,22 +433,22 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj, wrapper = &FilteringWrapper::singleton; } else if (type == XrayForDOMObject) { - wrapper = &FilteringWrapper::singleton; } else { + typedef XrayWrapper Xray; + // Location objects can become same origin after navigation, so we might // have to grant transparent access later on. if (IsLocationObject(obj)) { - wrapper = &FilteringWrapper::singleton; + wrapper = &FilteringWrapper::singleton; } else { - wrapper = &FilteringWrapper::singleton; + wrapper = &FilteringWrapper::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, 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::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::singleton; else if (type == XrayForDOMObject) - wrapper = &SCPermissiveXrayDOM::singleton; + wrapper = &XrayWrapper::singleton; else MOZ_NOT_REACHED("Bad Xray type"); diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 5b0ad99de5db..556046869086 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -1702,26 +1702,37 @@ XrayWrapper::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 +template <> XRAY XRAY::singleton(0); +template class XRAY; +#undef XRAY + +#define XRAY XrayWrapper +template <> XRAY XRAY::singleton(0); +template class XRAY; +#undef XRAY + +#define XRAY XrayWrapper +template <> XRAY XRAY::singleton(0); +template class XRAY; +#undef XRAY + +#define XRAY XrayWrapper +template <> XRAY XRAY::singleton(0); +template class XRAY; +#undef XRAY + +/* Same-compartment non-filtering versions. */ + +#define XRAY XrayWrapper +template <> XRAY XRAY::singleton(0); +template class XRAY; +#undef XRAY + +#define XRAY XrayWrapper +template <> XRAY XRAY::singleton(0); +template class XRAY; +#undef XRAY } diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 30095d057905..bb334f387f80 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -93,13 +93,7 @@ class XrayWrapper : public Base { JS::AutoIdVector &props); }; -typedef XrayWrapper PermissiveXrayXPCWN; -typedef XrayWrapper SecurityXrayXPCWN; -typedef XrayWrapper PermissiveXrayDOM; -typedef XrayWrapper SecurityXrayDOM; -typedef XrayWrapper SCSecurityXrayXPCWN; -typedef XrayWrapper SCPermissiveXrayXPCWN; -typedef XrayWrapper SCPermissiveXrayDOM; +typedef XrayWrapper XrayDOM; class SandboxProxyHandler : public js::Wrapper { public: