Fixes behavior in OgHttp2Session::CloseStream when frames have been removed from the pending frames queue.

Protected by does not affect the GFE2 binary; not protected.

PiperOrigin-RevId: 855881714
diff --git a/quiche/http2/adapter/oghttp2_session.cc b/quiche/http2/adapter/oghttp2_session.cc
index f345ec7..09c35a1 100644
--- a/quiche/http2/adapter/oghttp2_session.cc
+++ b/quiche/http2/adapter/oghttp2_session.cc
@@ -1963,7 +1963,8 @@
     queued_frames_.erase(queued_it);
     for (auto it = frames_.begin();
          frames_remaining > 0 && it != frames_.end();) {
-      if (static_cast<Http2StreamId>((*it)->stream_id()) == stream_id) {
+      if (*it != nullptr &&
+          static_cast<Http2StreamId>((*it)->stream_id()) == stream_id) {
         *it = nullptr;
         --frames_remaining;
       }
diff --git a/quiche/http2/adapter/oghttp2_session_test.cc b/quiche/http2/adapter/oghttp2_session_test.cc
index 8e637f0..51858bd 100644
--- a/quiche/http2/adapter/oghttp2_session_test.cc
+++ b/quiche/http2/adapter/oghttp2_session_test.cc
@@ -1420,6 +1420,65 @@
   EXPECT_THAT(serialized, EqualsFrames({SpdyFrameType::SETTINGS}));
 }
 
+// Regression test for pending frame queue behavior in CloseStream().
+TEST(OgHttp2SessionTest, RstStreamCausesCloseStreamCrash) {
+  TestVisitor visitor;
+  OgHttp2Session::Options options;
+  options.perspective = Perspective::kServer;
+  OgHttp2Session session(visitor, options);
+
+  const std::string frames = TestFrameSequence()
+                                 .ClientPreface()
+                                 .Headers(1,
+                                          {{":method", "GET"},
+                                           {":scheme", "https"},
+                                           {":authority", "example.com"},
+                                           {":path", "/"}},
+                                          true)
+                                 .Headers(3,
+                                          {{":method", "GET"},
+                                           {":scheme", "https"},
+                                           {":authority", "example.com"},
+                                           {":path", "/"}},
+                                          true)
+                                 .Serialize();
+  // Process headers to create streams 1 and 3.
+  EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+  EXPECT_CALL(visitor, OnSettingsStart());
+  EXPECT_CALL(visitor, OnSettingsEnd());
+  EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+  EXPECT_CALL(visitor, OnHeaderForStream(1, _, _)).Times(4);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+  EXPECT_CALL(visitor, OnEndStream(1));
+  EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(3));
+  EXPECT_CALL(visitor, OnHeaderForStream(3, _, _)).Times(4);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(3));
+  EXPECT_CALL(visitor, OnEndStream(3));
+  session.ProcessBytes(frames);
+
+  // Enqueue one frame for stream 1 and one for stream 3.
+  session.SubmitResponse(1, ToHeaders({{":status", "200"}}), false);
+  session.SubmitResponse(3, ToHeaders({{":status", "200"}}), false);
+
+  // Receive RST_STREAM for stream 1, followed by RST_STREAM for stream 3.
+  // The call to CloseStream(1) will null out the frame for stream 1 in frames_.
+  // The call to CloseStream(3) will iterate through frames_ and encounter the
+  // nullptr.
+  const std::string rst_frames = TestFrameSequence()
+                                     .RstStream(1, Http2ErrorCode::CANCEL)
+                                     .RstStream(3, Http2ErrorCode::CANCEL)
+                                     .Serialize();
+  EXPECT_CALL(visitor, OnFrameHeader(1, 4, RST_STREAM, 0));
+  EXPECT_CALL(visitor, OnRstStream(1, Http2ErrorCode::CANCEL));
+  EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::CANCEL));
+  EXPECT_CALL(visitor, OnFrameHeader(3, 4, RST_STREAM, 0));
+  EXPECT_CALL(visitor, OnRstStream(3, Http2ErrorCode::CANCEL));
+  EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::CANCEL));
+  session.ProcessBytes(rst_frames);
+}
+
 }  // namespace test
 }  // namespace adapter
 }  // namespace http2