[tbb-commits] [tor-browser/esr24] Bug 982974 - Be paranoid about neutering ArrayBuffer objects. r=sfink, a=dveditz
mikeperry at torproject.org
mikeperry at torproject.org
Fri Aug 29 05:26:38 UTC 2014
commit 664b5f505f7fed95256bf5632ed0cd5ba3308fc6
Author: Jeff Walden <jwalden at mit.edu>
Date: Fri Mar 14 17:20:22 2014 -0700
Bug 982974 - Be paranoid about neutering ArrayBuffer objects. r=sfink, a=dveditz
---
js/src/jstypedarray.cpp | 50 ++++++++++++++++++++++++++++--------------
js/src/jstypedarray.h | 27 ++++++++++++++++++++++-
js/src/jstypedarrayinlines.h | 6 -----
js/src/vm/ObjectImpl.h | 9 +++++++-
4 files changed, 67 insertions(+), 25 deletions(-)
diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp
index 1630c5a..9d02d06 100644
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -623,41 +623,57 @@ bool
ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents,
uint8_t **data)
{
+ MOZ_ASSERT(cx);
+
ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
JSObject *views = *GetViewList(&buffer);
- js::ObjectElements *header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
- if (buffer.hasDynamicElements() && !buffer.isAsmJSArrayBuffer()) {
+
+ uint32_t byteLen = buffer.byteLength();
+
+ js::ObjectElements *oldHeader = buffer.getElementsHeader();
+ js::ObjectElements *newHeader;
+
+ // If the ArrayBuffer's elements are transferrable, transfer ownership
+ // directly. Otherwise we have to copy the data into new elements.
+ bool stolen = buffer.hasStealableContents();
+ if (stolen) {
+ newHeader = AllocateArrayBufferContents(cx, byteLen, NULL);
+ if (!newHeader)
+ return false;
+
*GetViewList(&buffer) = NULL;
- *contents = header;
+ *contents = oldHeader;
*data = buffer.dataPointer();
- buffer.setFixedElements();
- header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
+ MOZ_ASSERT(!buffer.isAsmJSArrayBuffer(),
+ "buffer won't be neutered by neuterAsmJSArrayBuffer");
+
+ buffer.elements = newHeader->elements();
} else {
- uint32_t length = buffer.byteLength();
- js::ObjectElements *newheader =
- AllocateArrayBufferContents(cx, length, buffer.dataPointer());
- if (!newheader) {
- js_ReportOutOfMemory(cx);
+ js::ObjectElements *headerCopy =
+ AllocateArrayBufferContents(cx, byteLen, buffer.dataPointer());
+ if (!headerCopy)
return false;
- }
- ArrayBufferObject::setElementsHeader(newheader, length);
- *contents = newheader;
- *data = reinterpret_cast<uint8_t *>(newheader + 1);
+ *contents = headerCopy;
+ *data = reinterpret_cast<uint8_t *>(headerCopy + 1);
if (buffer.isAsmJSArrayBuffer())
ArrayBufferObject::neuterAsmJSArrayBuffer(buffer);
+
+ // Keep using the current elements.
+ newHeader = oldHeader;
}
// Neuter the donor ArrayBuffer and all views of it
- uint32_t flags = header->flags;
- ArrayBufferObject::setElementsHeader(header, 0);
- header->flags = flags;
+ uint32_t flags = newHeader->flags;
+ ArrayBufferObject::setElementsHeader(newHeader, 0);
+ newHeader->flags = flags;
GetViewList(&buffer)->init(views);
for (JSObject *view = views; view; view = NextView(view))
TypedArray::neuter(view);
+ newHeader->setIsNeuteredBuffer();
return true;
}
diff --git a/js/src/jstypedarray.h b/js/src/jstypedarray.h
index f666e52..4751d53 100644
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -137,6 +137,24 @@ class ArrayBufferObject : public JSObject
static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector);
static void restoreArrayBufferLists(ArrayBufferVector &vector);
+ bool hasStealableContents() const {
+ // Inline elements strictly adhere to the corresponding buffer.
+ if (!hasDynamicElements())
+ return false;
+
+ // asm.js buffer contents are transferred by copying, just like inline
+ // elements.
+ if (isAsmJSArrayBuffer())
+ return false;
+
+ // Neutered contents aren't transferrable because we want a neutered
+ // array's contents to be backed by zeroed memory equal in length to
+ // the original buffer contents. Transferring these contents would
+ // allocate new ones based on the current byteLength, which is 0 for a
+ // neutered array -- not the original byteLength.
+ return !isNeutered();
+ }
+
static bool stealContents(JSContext *cx, JSObject *obj, void **contents,
uint8_t **data);
@@ -164,10 +182,17 @@ class ArrayBufferObject : public JSObject
*/
inline bool hasData() const;
- inline bool isAsmJSArrayBuffer() const;
+ bool isAsmJSArrayBuffer() const {
+ return getElementsHeader()->isAsmJSArrayBuffer();
+ }
+
static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
static void neuterAsmJSArrayBuffer(ArrayBufferObject &buffer);
static void releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj);
+
+ bool isNeutered() const {
+ return getElementsHeader()->isNeuteredBuffer();
+ }
};
/*
diff --git a/js/src/jstypedarrayinlines.h b/js/src/jstypedarrayinlines.h
index 5af70f5..f26e9cc 100644
--- a/js/src/jstypedarrayinlines.h
+++ b/js/src/jstypedarrayinlines.h
@@ -56,12 +56,6 @@ ArrayBufferObject::hasData() const
return getClass() == &class_;
}
-inline bool
-ArrayBufferObject::isAsmJSArrayBuffer() const
-{
- return getElementsHeader()->isAsmJSArrayBuffer();
-}
-
static inline int32_t
ClampIntForUint8Array(int32_t x)
{
diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h
index 980f935..8eba5da 100644
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -979,10 +979,11 @@ class ObjectElements
enum Flags {
CONVERT_DOUBLE_ELEMENTS = 0x1,
ASMJS_ARRAY_BUFFER = 0x2,
+ NEUTERED_BUFFER = 0x4,
// Present only if these elements correspond to an array with
// non-writable length; never present for non-arrays.
- NONWRITABLE_ARRAY_LENGTH = 0x4
+ NONWRITABLE_ARRAY_LENGTH = 0x8
};
private:
@@ -1036,6 +1037,12 @@ class ObjectElements
void setIsAsmJSArrayBuffer() {
flags |= ASMJS_ARRAY_BUFFER;
}
+ bool isNeuteredBuffer() const {
+ return flags & NEUTERED_BUFFER;
+ }
+ void setIsNeuteredBuffer() {
+ flags |= NEUTERED_BUFFER;
+ }
bool hasNonwritableArrayLength() const {
return flags & NONWRITABLE_ARRAY_LENGTH;
}
More information about the tbb-commits
mailing list