summaryrefslogtreecommitdiff
path: root/xpcom
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-11-02 14:59:25 +0100
committerwolfbeast <mcwerewolf@gmail.com>2018-11-02 16:05:57 +0100
commitcc234ff4304d3a60dc2163f77a4214ecdbd88d5c (patch)
tree048283d97090e8aec70ac675cbfd66363b55fe39 /xpcom
parent90a73cfe2a7509b3108c2a9ad884b42594638b4d (diff)
downloaduxp-cc234ff4304d3a60dc2163f77a4214ecdbd88d5c.tar.gz
Add overflow checks for extending nsTArrays.
Surprisingly, this was previously not done. Also, some of this code seems to be incorrect or, at the very least, wasn't clear what it was trying to do.
Diffstat (limited to 'xpcom')
-rw-r--r--xpcom/glue/nsTArray-inl.h32
-rw-r--r--xpcom/glue/nsTArray.h42
2 files changed, 50 insertions, 24 deletions
diff --git a/xpcom/glue/nsTArray-inl.h b/xpcom/glue/nsTArray-inl.h
index af57c9866f..7e667a3276 100644
--- a/xpcom/glue/nsTArray-inl.h
+++ b/xpcom/glue/nsTArray-inl.h
@@ -111,6 +111,23 @@ bool IsTwiceTheRequiredBytesRepresentableAsUint32(size_t aCapacity,
template<class Alloc, class Copy>
template<typename ActualAlloc>
typename ActualAlloc::ResultTypeProxy
+nsTArray_base<Alloc, Copy>::ExtendCapacity(size_type aLength,
+ size_type aCount,
+ size_type aElemSize)
+{
+ mozilla::CheckedInt<size_type> newLength = aLength;
+ newLength += aCount;
+
+ if (!newLength.isValid()) {
+ return ActualAlloc::FailureResult();
+ }
+
+ return this->EnsureCapacity<ActualAlloc>(newLength.value(), aElemSize);
+}
+
+template<class Alloc, class Copy>
+template<typename ActualAlloc>
+typename ActualAlloc::ResultTypeProxy
nsTArray_base<Alloc, Copy>::EnsureCapacity(size_type aCapacity,
size_type aElemSize)
{
@@ -275,26 +292,21 @@ nsTArray_base<Alloc, Copy>::ShiftData(index_type aStart,
template<class Alloc, class Copy>
template<typename ActualAlloc>
-bool
+typename ActualAlloc::ResultTypeProxy
nsTArray_base<Alloc, Copy>::InsertSlotsAt(index_type aIndex, size_type aCount,
size_type aElemSize,
size_t aElemAlign)
{
MOZ_ASSERT(aIndex <= Length(), "Bogus insertion index");
- size_type newLen = Length() + aCount;
-
- EnsureCapacity<ActualAlloc>(newLen, aElemSize);
-
- // Check for out of memory conditions
- if (Capacity() < newLen) {
- return false;
+ if (!ActualAlloc::Successful(this->ExtendCapacity<ActualAlloc>(Length(), aCount, aElemSize))) {
+ return ActualAlloc::FailureResult();
}
-
+
// Move the existing elements as needed. Note that this will
// change our mLength, so no need to call IncrementLength.
ShiftData<ActualAlloc>(aIndex, 0, aCount, aElemSize, aElemAlign);
- return true;
+ return ActualAlloc::SuccessResult();
}
// nsTArray_base::IsAutoArrayRestorer is an RAII class which takes
diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h
index c86772a8e9..82586a79a7 100644
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -12,6 +12,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/BinarySearch.h"
+#include "mozilla/CheckedInt.h"
#include "mozilla/fallible.h"
#include "mozilla/Function.h"
#include "mozilla/MathAlgorithms.h"
@@ -421,6 +422,17 @@ protected:
typename ActualAlloc::ResultTypeProxy EnsureCapacity(size_type aCapacity,
size_type aElemSize);
+ // Extend the storage to accommodate aCount extra elements.
+ // @param aLength The current size of the array.
+ // @param aCount The number of elements to add.
+ // @param aElemSize The size of an array element.
+ // @return False if insufficient memory is available or the new length
+ // would overflow; true otherwise.
+ template<typename ActualAlloc>
+ typename ActualAlloc::ResultTypeProxy ExtendCapacity(size_type aLength,
+ size_type aCount,
+ size_type aElemSize);
+
// Tries to resize the storage to the minimum required amount. If this fails,
// the array is left as-is.
// @param aElemSize The size of an array element.
@@ -462,8 +474,9 @@ protected:
// @param aElementSize the size of an array element.
// @param aElemAlign the alignment in bytes of an array element.
template<typename ActualAlloc>
- bool InsertSlotsAt(index_type aIndex, size_type aCount,
- size_type aElementSize, size_t aElemAlign);
+ typename ActualAlloc::ResultTypeProxy
+ InsertSlotsAt(index_type aIndex, size_type aCount,
+ size_type aElementSize, size_t aElemAlign);
template<typename ActualAlloc, class Allocator>
typename ActualAlloc::ResultTypeProxy
@@ -1655,8 +1668,8 @@ public:
protected:
template<typename ActualAlloc = Alloc>
elem_type* AppendElements(size_type aCount) {
- if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
- Length() + aCount, sizeof(elem_type)))) {
+ if (!ActualAlloc::Successful(this->template ExtendCapacity<ActualAlloc>(
+ Length(), aCount, sizeof(elem_type)))) {
return nullptr;
}
elem_type* elems = Elements() + Length();
@@ -1872,9 +1885,8 @@ protected:
template<typename ActualAlloc = Alloc>
elem_type* InsertElementsAt(index_type aIndex, size_type aCount)
{
- if (!base_type::template InsertSlotsAt<ActualAlloc>(aIndex, aCount,
- sizeof(elem_type),
- MOZ_ALIGNOF(elem_type))) {
+ if (!ActualAlloc::Successful(this->template InsertSlotsAt<ActualAlloc>(
+ aIndex, aCount, sizeof(elem_type), MOZ_ALIGNOF(elem_type)))) {
return nullptr;
}
@@ -2047,9 +2059,8 @@ auto
nsTArray_Impl<E, Alloc>::InsertElementsAt(index_type aIndex, size_type aCount,
const Item& aItem) -> elem_type*
{
- if (!base_type::template InsertSlotsAt<ActualAlloc>(aIndex, aCount,
- sizeof(elem_type),
- MOZ_ALIGNOF(elem_type))) {
+ if (!ActualAlloc::Successful(this->template InsertSlotsAt<ActualAlloc>(
+ aIndex, aCount, sizeof(elem_type), MOZ_ALIGNOF(elem_type)))) {
return nullptr;
}
@@ -2068,6 +2079,7 @@ template<typename ActualAlloc>
auto
nsTArray_Impl<E, Alloc>::InsertElementAt(index_type aIndex) -> elem_type*
{
+ // Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK.
if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
Length() + 1, sizeof(elem_type)))) {
return nullptr;
@@ -2084,6 +2096,7 @@ template<class Item, typename ActualAlloc>
auto
nsTArray_Impl<E, Alloc>::InsertElementAt(index_type aIndex, Item&& aItem) -> elem_type*
{
+ // Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK.
if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
Length() + 1, sizeof(elem_type)))) {
return nullptr;
@@ -2100,8 +2113,8 @@ template<class Item, typename ActualAlloc>
auto
nsTArray_Impl<E, Alloc>::AppendElements(const Item* aArray, size_type aArrayLen) -> elem_type*
{
- if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
- Length() + aArrayLen, sizeof(elem_type)))) {
+ if (!ActualAlloc::Successful(this->template ExtendCapacity<ActualAlloc>(
+ Length(), aArrayLen, sizeof(elem_type)))) {
return nullptr;
}
index_type len = Length();
@@ -2123,8 +2136,8 @@ nsTArray_Impl<E, Alloc>::AppendElements(nsTArray_Impl<Item, Allocator>&& aArray)
index_type len = Length();
index_type otherLen = aArray.Length();
- if (!Alloc::Successful(this->template EnsureCapacity<Alloc>(
- len + otherLen, sizeof(elem_type)))) {
+ if (!Alloc::Successful(this->template ExtendCapacity<Alloc>(
+ len, otherLen, sizeof(elem_type)))) {
return nullptr;
}
copy_type::MoveNonOverlappingRegion(Elements() + len, aArray.Elements(), otherLen,
@@ -2140,6 +2153,7 @@ template<class Item, typename ActualAlloc>
auto
nsTArray_Impl<E, Alloc>::AppendElement(Item&& aItem) -> elem_type*
{
+ // Length() + 1 is guaranteed to not overflow, so EnsureCapacity is OK.
if (!ActualAlloc::Successful(this->template EnsureCapacity<ActualAlloc>(
Length() + 1, sizeof(elem_type)))) {
return nullptr;