summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2017-06-21 17:02:50 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-02-05 19:17:30 +0100
commit9ba0c19352ef61c998aef18a1de9a98c66a7291f (patch)
tree4a3ed801cc9aed806cfe62fdb85f4801327a7d3e
parent6b5575eb99714967b38aa2b2b71e5e72d2f97b81 (diff)
downloaduxp-9ba0c19352ef61c998aef18a1de9a98c66a7291f.tar.gz
Fix off-by-one in Vector::insert.
-rw-r--r--mfbt/Vector.h4
-rw-r--r--mfbt/tests/TestVector.cpp52
2 files changed, 54 insertions, 2 deletions
diff --git a/mfbt/Vector.h b/mfbt/Vector.h
index fc43afcf16..07e3704264 100644
--- a/mfbt/Vector.h
+++ b/mfbt/Vector.h
@@ -1232,10 +1232,10 @@ Vector<T, N, AP>::insert(T* aP, U&& aVal)
}
} else {
T oldBack = Move(back());
- if (!append(Move(oldBack))) { /* Dup the last element. */
+ if (!append(Move(oldBack))) {
return nullptr;
}
- for (size_t i = oldLength; i > pos; --i) {
+ for (size_t i = oldLength - 1; i > pos; --i) {
(*this)[i] = Move((*this)[i - 1]);
}
(*this)[pos] = Forward<U>(aVal);
diff --git a/mfbt/tests/TestVector.cpp b/mfbt/tests/TestVector.cpp
index d969bcbc2c..e28b432d69 100644
--- a/mfbt/tests/TestVector.cpp
+++ b/mfbt/tests/TestVector.cpp
@@ -22,6 +22,7 @@ struct mozilla::detail::VectorTesting
static void testReverse();
static void testExtractRawBuffer();
static void testExtractOrCopyRawBuffer();
+ static void testInsert();
};
void
@@ -141,6 +142,15 @@ struct S
destructCount++;
}
+ S& operator=(S&& rhs) {
+ j = rhs.j;
+ rhs.j = 0;
+ k = Move(rhs.k);
+ rhs.k.reset();
+ moveCount++;
+ return *this;
+ }
+
S(const S&) = delete;
S& operator=(const S&) = delete;
};
@@ -346,6 +356,47 @@ mozilla::detail::VectorTesting::testExtractOrCopyRawBuffer()
free(buf);
}
+void
+mozilla::detail::VectorTesting::testInsert()
+{
+ S::resetCounts();
+
+ Vector<S, 8> vec;
+ MOZ_RELEASE_ASSERT(vec.reserve(8));
+ for (size_t i = 0; i < 7; i++) {
+ vec.infallibleEmplaceBack(i, i * i);
+ }
+
+ MOZ_RELEASE_ASSERT(vec.length() == 7);
+ MOZ_ASSERT(vec.reserved() == 8);
+ MOZ_RELEASE_ASSERT(S::constructCount == 7);
+ MOZ_RELEASE_ASSERT(S::moveCount == 0);
+ MOZ_RELEASE_ASSERT(S::destructCount == 0);
+
+ S s(42, 43);
+ MOZ_RELEASE_ASSERT(vec.insert(vec.begin() + 4, Move(s)));
+
+ for (size_t i = 0; i < vec.length(); i++) {
+ const S& s = vec[i];
+ MOZ_RELEASE_ASSERT(s.k);
+ if (i < 4) {
+ MOZ_RELEASE_ASSERT(s.j == i && *s.k == i * i);
+ } else if (i == 4) {
+ MOZ_RELEASE_ASSERT(s.j == 42 && *s.k == 43);
+ } else {
+ MOZ_RELEASE_ASSERT(s.j == i - 1 && *s.k == (i - 1) * (i - 1));
+ }
+ }
+
+ MOZ_RELEASE_ASSERT(vec.length() == 8);
+ MOZ_ASSERT(vec.reserved() == 8);
+ MOZ_RELEASE_ASSERT(S::constructCount == 8);
+ MOZ_RELEASE_ASSERT(S::moveCount == 1 /* move in insert() call */ +
+ 1 /* move the back() element */ +
+ 3 /* elements to shift */);
+ MOZ_RELEASE_ASSERT(S::destructCount == 1);
+}
+
int
main()
{
@@ -355,4 +406,5 @@ main()
VectorTesting::testReverse();
VectorTesting::testExtractRawBuffer();
VectorTesting::testExtractOrCopyRawBuffer();
+ VectorTesting::testInsert();
}