Bug 1483603 - Avoid propagating OOM from StartBulkWrite() when shrinking the buffer. r=froydnj

Shrinking the buffer is purely a memory footprint optimization and can be
omitted as far as the string semantics visible to the caller are concerned.
Since shrinking is optional, it doesn't make sense to propagate error when
it fails due to OOM.

MozReview-Commit-ID: BuyBLCBmYzZ

Differential Revision: https://phabricator.services.mozilla.com/D3866

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Henri Sivonen 2018-08-27 07:03:59 +00:00
parent 94698538d1
commit 8711bfbcb6

View File

@ -92,18 +92,24 @@ nsTSubstring<T>::StartBulkWrite(size_type aCapacity,
}
// Note! Capacity() returns 0 when the string is immutable.
size_type curCapacity = Capacity();
const size_type curCapacity = Capacity();
bool shrinking = false;
// We've established that aCapacity > 0.
// |curCapacity == 0| means that the buffer is immutable or 0-sized, so we
// need to allocate a new buffer. We cannot use the existing buffer even
// though it might be large enough.
if (!aAllowShrinking && aCapacity <= curCapacity) {
char_traits::move(this->mData + aNewSuffixStart,
this->mData + aOldSuffixStart,
aSuffixLength);
return curCapacity;
if (aCapacity <= curCapacity) {
if (aAllowShrinking) {
shrinking = true;
} else {
char_traits::move(this->mData + aNewSuffixStart,
this->mData + aOldSuffixStart,
aSuffixLength);
return curCapacity;
}
}
char_type* oldData = this->mData;
@ -167,6 +173,7 @@ nsTSubstring<T>::StartBulkWrite(size_type aCapacity,
MOZ_ASSERT(aAllowShrinking, "How come we didn't return earlier?");
// We're already close enough to the right size.
newData = oldData;
newCapacity = curCapacity;
} else {
size_type storageSize = (newCapacity + 1) * sizeof(char_type);
// Since we allocate only by powers of 2 we always fit into a full mozjemalloc
@ -174,7 +181,18 @@ nsTSubstring<T>::StartBulkWrite(size_type aCapacity,
// copying too much.
nsStringBuffer* newHdr = nsStringBuffer::Alloc(storageSize).take();
if (!newHdr) {
return mozilla::Err(NS_ERROR_OUT_OF_MEMORY); // we are still in a consistent state
// we are still in a consistent state
if (shrinking) {
// Since shrinking is just a memory footprint optimization, we
// don't propagate OOM if we tried to shrink in order to avoid
// OOM crashes from infallible callers. If we're lucky, soon enough
// a fallible caller reaches OOM and is able to deal or we end up
// disposing of this string before reaching OOM again.
newData = oldData;
newCapacity = curCapacity;
} else {
return mozilla::Err(NS_ERROR_OUT_OF_MEMORY);
}
}
newData = (char_type*)newHdr->Data();