Fix an undefined behavior in QuicChaosProtector::AddPingFrames when remaining_padding_bytes_ is zero after split.

The newly added test fails without the fix, see http://sponge2/644a2be0-0db6-4f83-a1b9-19a5ef431826.

PiperOrigin-RevId: 404606531
diff --git a/quic/core/quic_chaos_protector.cc b/quic/core/quic_chaos_protector.cc
index 4eb353b..e21d26c 100644
--- a/quic/core/quic_chaos_protector.cc
+++ b/quic/core/quic_chaos_protector.cc
@@ -175,6 +175,9 @@
 }
 
 void QuicChaosProtector::AddPingFrames() {
+  if (remaining_padding_bytes_ == 0) {
+    return;
+  }
   constexpr uint64_t kMaxAddedPingFrames = 10;
   const uint64_t num_ping_frames =
       random_->InsecureRandUint64() %
diff --git a/quic/core/quic_chaos_protector_test.cc b/quic/core/quic_chaos_protector_test.cc
index 1ec985b..675e00f 100644
--- a/quic/core/quic_chaos_protector_test.cc
+++ b/quic/core/quic_chaos_protector_test.cc
@@ -30,9 +30,7 @@
  public:
   QuicChaosProtectorTest()
       : version_(GetParam()),
-        framer_({version_},
-                QuicTime::Zero(),
-                Perspective::IS_CLIENT,
+        framer_({version_}, QuicTime::Zero(), Perspective::IS_CLIENT,
                 kQuicDefaultConnectionIdLength),
         validation_framer_({version_}),
         random_(/*base=*/3),
@@ -42,12 +40,15 @@
         crypto_frame_(level_, crypto_offset_, crypto_data_length_),
         num_padding_bytes_(50),
         packet_size_(1000),
-        packet_buffer_(std::make_unique<char[]>(packet_size_)),
-        chaos_protector_(crypto_frame_,
-                         num_padding_bytes_,
-                         packet_size_,
-                         SetupHeaderAndFramers(),
-                         &random_) {}
+        packet_buffer_(std::make_unique<char[]>(packet_size_)) {
+    ReCreateChaosProtector();
+  }
+
+  void ReCreateChaosProtector() {
+    chaos_protector_ = std::make_unique<QuicChaosProtector>(
+        crypto_frame_, num_padding_bytes_, packet_size_,
+        SetupHeaderAndFramers(), &random_);
+  }
 
   // From QuicStreamFrameDataProducer.
   WriteStreamDataResult WriteStreamData(QuicStreamId /*id*/,
@@ -100,7 +101,7 @@
 
   void BuildEncryptAndParse() {
     absl::optional<size_t> length =
-        chaos_protector_.BuildDataPacket(header_, packet_buffer_.get());
+        chaos_protector_->BuildDataPacket(header_, packet_buffer_.get());
     ASSERT_TRUE(length.has_value());
     ASSERT_GT(length.value(), 0u);
     size_t encrypted_length = framer_.EncryptInPlace(
@@ -115,7 +116,13 @@
   void ResetOffset(QuicStreamOffset offset) {
     crypto_offset_ = offset;
     crypto_frame_.offset = offset;
-    chaos_protector_.crypto_buffer_offset_ = offset;
+    ReCreateChaosProtector();
+  }
+
+  void ResetLength(QuicByteCount length) {
+    crypto_data_length_ = length;
+    crypto_frame_.data_length = length;
+    ReCreateChaosProtector();
   }
 
   ParsedQuicVersion version_;
@@ -130,7 +137,7 @@
   int num_padding_bytes_;
   size_t packet_size_;
   std::unique_ptr<char[]> packet_buffer_;
-  QuicChaosProtector chaos_protector_;
+  std::unique_ptr<QuicChaosProtector> chaos_protector_;
 };
 
 namespace {
@@ -202,6 +209,22 @@
   ASSERT_EQ(validation_framer_.padding_frames().size(), 1u);
 }
 
+TEST_P(QuicChaosProtectorTest, ZeroRemainingBytesAfterSplit) {
+  QuicPacketLength new_length = 63;
+  num_padding_bytes_ = QuicFramer::GetMinCryptoFrameSize(
+      crypto_frame_.offset + new_length, new_length);
+  ResetLength(new_length);
+  BuildEncryptAndParse();
+
+  ASSERT_EQ(validation_framer_.crypto_frames().size(), 2u);
+  EXPECT_EQ(validation_framer_.crypto_frames()[0]->offset, crypto_offset_);
+  EXPECT_EQ(validation_framer_.crypto_frames()[0]->data_length, 4);
+  EXPECT_EQ(validation_framer_.crypto_frames()[1]->offset, crypto_offset_ + 4);
+  EXPECT_EQ(validation_framer_.crypto_frames()[1]->data_length,
+            crypto_data_length_ - 4);
+  ASSERT_EQ(validation_framer_.ping_frames().size(), 0u);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic