diff --git a/mfbt/BufferList.h b/mfbt/BufferList.h index 51eb966707c0..507aa62511c3 100644 --- a/mfbt/BufferList.h +++ b/mfbt/BufferList.h @@ -658,6 +658,20 @@ BufferList BufferList::Extract(IterImpl& aIter, aIter.mAbsoluteOffset -= removedBytes; mSize -= removedBytes; + // If our iterator is already at the end, we just removed the very last + // segment of our buffer list and need to shift the iterator back to point + // at the end of the previous segment. + if (aIter.Done()) { + MOZ_ASSERT(lastSegmentSize.isNothing()); + if (mSegments.empty()) { + MOZ_ASSERT(aIter.mSegment == 0); + aIter.mData = aIter.mDataEnd = nullptr; + } else { + MOZ_ASSERT(aIter.mSegment == mSegments.length() - 1); + aIter.mData = aIter.mDataEnd = mSegments.back().End(); + } + } + if (lastSegmentSize.isSome()) { // We called reserve() on result.mSegments so infallibleAppend is safe. result.mSegments.infallibleAppend( @@ -673,6 +687,15 @@ BufferList BufferList::Extract(IterImpl& aIter, AssertConsistentSize(); result.AssertConsistentSize(); + // Ensure that the iterator is still valid when Extract returns. +#ifdef DEBUG + if (!mSegments.empty()) { + auto& segment = mSegments[aIter.mSegment]; + MOZ_ASSERT(segment.Start() <= aIter.mData); + MOZ_ASSERT(aIter.mDataEnd == segment.End()); + } +#endif + *aSuccess = true; return result; } diff --git a/mfbt/tests/TestBufferList.cpp b/mfbt/tests/TestBufferList.cpp index e80448dc3ba0..9535c2245fbd 100644 --- a/mfbt/tests/TestBufferList.cpp +++ b/mfbt/tests/TestBufferList.cpp @@ -299,6 +299,8 @@ int main(void) { MOZ_RELEASE_ASSERT(success); MOZ_RELEASE_ASSERT(bl11.Size() == 16); MOZ_RELEASE_ASSERT(iter.Done()); + MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl10, 0)); + MOZ_RELEASE_ASSERT(iter.Done()); iter = bl11.Iter(); MOZ_RELEASE_ASSERT(bl11.ReadBytes(iter, data, 16)); MOZ_RELEASE_ASSERT(memcmp(data, "abcdefgh12345678", 16) == 0);