зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1350864 - Fix SetIntegrityLevel to set non-writable length correctly when freezing arrays. r=Waldo
This commit is contained in:
Родитель
3c3ff310ce
Коммит
d7c81386bd
|
@ -0,0 +1,19 @@
|
|||
function maybeFreeze(arr, b) {
|
||||
with(this) {}; // Don't inline this.
|
||||
if (b) {
|
||||
Object.freeze(arr);
|
||||
}
|
||||
}
|
||||
function test() {
|
||||
var arr = [];
|
||||
for (var i = 0; i < 1800; i++) {
|
||||
maybeFreeze(arr, i > 1500);
|
||||
try {
|
||||
arr.push(2);
|
||||
assertEq(i <= 1500, true);
|
||||
} catch(e) {
|
||||
assertEq(e instanceof TypeError, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
test();
|
|
@ -890,25 +890,8 @@ js::ArraySetLength(JSContext* cx, Handle<ArrayObject*> arr, HandleId id,
|
|||
ObjectElements* header = arr->getElementsHeader();
|
||||
header->initializedLength = Min(header->initializedLength, newLen);
|
||||
|
||||
if (attrs & JSPROP_READONLY) {
|
||||
if (header->numShiftedElements() > 0) {
|
||||
arr->unshiftElements();
|
||||
header = arr->getElementsHeader();
|
||||
}
|
||||
|
||||
header->setNonwritableArrayLength();
|
||||
|
||||
// When an array's length becomes non-writable, writes to indexes
|
||||
// greater than or equal to the length don't change the array. We
|
||||
// handle this with a check for non-writable length in most places.
|
||||
// But in JIT code every check counts -- so we piggyback the check on
|
||||
// the already-required range check for |index < capacity| by making
|
||||
// capacity of arrays with non-writable length never exceed the length.
|
||||
if (arr->getDenseCapacity() > newLen) {
|
||||
arr->shrinkElements(cx, newLen);
|
||||
arr->getElementsHeader()->capacity = newLen;
|
||||
}
|
||||
}
|
||||
if (attrs & JSPROP_READONLY)
|
||||
arr->setNonWritableLength(cx);
|
||||
|
||||
if (!succeeded)
|
||||
return result.fail(JSMSG_CANT_TRUNCATE_ARRAY);
|
||||
|
|
|
@ -534,17 +534,10 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level)
|
|||
|
||||
// Ordinarily ArraySetLength handles this, but we're going behind its back
|
||||
// right now, so we must do this manually.
|
||||
//
|
||||
// ArraySetLength also implements the capacity <= length invariant for
|
||||
// arrays with non-writable length. We don't need to do anything special
|
||||
// for that, because capacity was zeroed out by preventExtensions. (See
|
||||
// the assertion about getDenseCapacity above.)
|
||||
if (level == IntegrityLevel::Frozen && obj->is<ArrayObject>()) {
|
||||
if (!obj->as<ArrayObject>().maybeCopyElementsForWrite(cx))
|
||||
return false;
|
||||
if (nobj->getElementsHeader()->numShiftedElements() > 0)
|
||||
nobj->unshiftElements();
|
||||
obj->as<ArrayObject>().getElementsHeader()->setNonwritableArrayLength();
|
||||
obj->as<ArrayObject>().setNonWritableLength(cx);
|
||||
}
|
||||
} else {
|
||||
RootedId id(cx);
|
||||
|
|
|
@ -31,6 +31,26 @@ class ArrayObject : public NativeObject
|
|||
return getElementsHeader()->length;
|
||||
}
|
||||
|
||||
void setNonWritableLength(JSContext* cx) {
|
||||
if (getElementsHeader()->numShiftedElements() > 0)
|
||||
unshiftElements();
|
||||
|
||||
// When an array's length becomes non-writable, writes to indexes
|
||||
// greater than or equal to the length don't change the array. We
|
||||
// handle this with a check for non-writable length in most places.
|
||||
// But in JIT code every check counts -- so we piggyback the check on
|
||||
// the already-required range check for |index < capacity| by making
|
||||
// capacity of arrays with non-writable length never exceed the length.
|
||||
ObjectElements* header = getElementsHeader();
|
||||
uint32_t len = header->initializedLength;
|
||||
if (header->capacity > len) {
|
||||
shrinkElements(cx, len);
|
||||
header = getElementsHeader();
|
||||
header->capacity = len;
|
||||
}
|
||||
header->setNonwritableArrayLength();
|
||||
}
|
||||
|
||||
inline void setLength(JSContext* cx, uint32_t length);
|
||||
|
||||
// Variant of setLength for use on arrays where the length cannot overflow int32_t.
|
||||
|
|
|
@ -259,6 +259,9 @@ class ObjectElements
|
|||
return flags & NONWRITABLE_ARRAY_LENGTH;
|
||||
}
|
||||
void setNonwritableArrayLength() {
|
||||
// See ArrayObject::setNonWritableLength.
|
||||
MOZ_ASSERT(capacity == initializedLength);
|
||||
MOZ_ASSERT(numShiftedElements() == 0);
|
||||
MOZ_ASSERT(!isCopyOnWrite());
|
||||
flags |= NONWRITABLE_ARRAY_LENGTH;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче