Fix QuicStreamSequencerBuffer::PrefetchNextRegion() behavior after Clear().

If some data are prefetched then QuicStreamSequencerBuffer::Clear() is called,
then QuicStreamSequencerBuffer::FirstByteMissing() will take the value of
|total_bytes_read_|, which can be less than |total_bytes_prefetched_|.  In this
case, QuicStreamSequencerBuffer::PrefetchNextRegion() used to return true, but
really ought to return false.  This CL fixes that.

This CL addresses the root cause of the fuzzer-found ASAN crash at
https://crbug.com/969391.  It is complementary to cr/253592180, which addresses
the stream level behavior.  Either CLs would be enough to make that particular
crash go away, but they are both necessary as they fix different bugs.

gfe-relnote: Change in code only mean for QUIC v99, not flag protected.

We believe this change does not need flag protection, because it only affects |total_bytes_prefetched_|, which is only read in QuicStreamSequencerBuffer::PrefetchNextRegion(), which is only called (other than tests) in QuicStreamSequencer::PrefetchNextRegion(), which is only called in three places: QuicSpdyStream::OnDataAvailable() but only when using v99, QuicReceiveControlStream::OnDataAvailable() which is not currently wired up but will be v99-only anyway, and //depot/google3/vr/c9/playability/yperf/message_stream.cc in a galaxy far-far away.  Therefore this change should not affect production GFE.

PiperOrigin-RevId: 253995330
Change-Id: I40b92da16dcf6ec1bdeda9de9ddeeb49ff3542f4
diff --git a/quic/core/quic_stream_sequencer_buffer.cc b/quic/core/quic_stream_sequencer_buffer.cc
index 7f0f2cb..9d239b1 100644
--- a/quic/core/quic_stream_sequencer_buffer.cc
+++ b/quic/core/quic_stream_sequencer_buffer.cc
@@ -53,6 +53,7 @@
   num_bytes_buffered_ = 0;
   bytes_received_.Clear();
   bytes_received_.Add(0, total_bytes_read_);
+  total_bytes_prefetched_ = total_bytes_read_;
 }
 
 bool QuicStreamSequencerBuffer::RetireBlock(size_t idx) {
@@ -336,6 +337,8 @@
 
 bool QuicStreamSequencerBuffer::PrefetchNextRegion(iovec* iov) {
   DCHECK(iov != nullptr);
+  DCHECK_LE(total_bytes_read_, total_bytes_prefetched_);
+  DCHECK_LE(total_bytes_prefetched_, FirstMissingByte());
 
   if (total_bytes_prefetched_ == FirstMissingByte()) {
     return false;
diff --git a/quic/core/quic_stream_sequencer_buffer_test.cc b/quic/core/quic_stream_sequencer_buffer_test.cc
index 335aa2d..67d9b28 100644
--- a/quic/core/quic_stream_sequencer_buffer_test.cc
+++ b/quic/core/quic_stream_sequencer_buffer_test.cc
@@ -1078,6 +1078,31 @@
   EXPECT_LE(bytes_to_buffer_, total_bytes_written_);
 }
 
+// Regression test for https://crbug.com/969391.
+TEST_F(QuicStreamSequencerBufferTest, PrefetchAfterClear) {
+  // Write a few bytes.
+  const std::string kData("foo");
+  size_t written = 0;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->OnStreamData(/* offset = */ 0, kData,
+                                                 &written, &error_details_));
+  EXPECT_EQ(kData.size(), written);
+
+  // Prefetch all buffered data.
+  iovec iov;
+  EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
+  EXPECT_EQ(kData, QuicStringPiece(reinterpret_cast<const char*>(iov.iov_base),
+                                   iov.iov_len));
+
+  // No more data to prefetch.
+  EXPECT_FALSE(buffer_->PrefetchNextRegion(&iov));
+
+  // Clear all buffered data.
+  buffer_->Clear();
+
+  // Still no data to prefetch.
+  EXPECT_FALSE(buffer_->PrefetchNextRegion(&iov));
+}
+
 }  // anonymous namespace
 
 }  // namespace test