Make it a `QUIC_BUG` to access the `QuicSession`'s `QuicConfig` after
the handshake completes, in preparation for dropping the config
completely to safe memory.

This CL moves the `QuicConfig` object into a new `SavedConfig` class
which the session stores instead. This new class provides accessors
to the underlying config which trigger the `QUIC_BUG` once the config
has been "deleted". (The actual deletion will happen in a follow up CL).

It also provide a new accessor for access to the config after deletion,
which callers will need to use to avoid the `QUIC_BUG`. In a follow-up
(flag-protected) CL, the `SavedConfig` will cache values from the
`QuicConfig` when it is deleted, and return those instead.

Project import generated by Copybara.

PiperOrigin-RevId: 836879510
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc
index dc7b6cd..841c020 100644
--- a/quiche/quic/core/quic_session.cc
+++ b/quiche/quic/core/quic_session.cc
@@ -156,13 +156,13 @@
                              config.GetMaxBidirectionalStreamsToSend(),
                              config.GetMaxUnidirectionalStreamsToSend() +
                                  num_expected_unidirectional_static_streams),
-      config_(config) {
+      saved_config_(config) {
   closed_streams_clean_up_alarm_ =
       absl::WrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm(
           new ClosedStreamsCleanUpDelegate(this)));
   if (VersionIsIetfQuic(transport_version())) {
-    config_.SetMaxUnidirectionalStreamsToSend(
-        config_.GetMaxUnidirectionalStreamsToSend() +
+    this->config()->SetMaxUnidirectionalStreamsToSend(
+        this->config()->GetMaxUnidirectionalStreamsToSend() +
         num_expected_unidirectional_static_streams);
   }
 }
@@ -173,23 +173,23 @@
   connection_->SetDataProducer(this);
   connection_->SetUnackedMapInitialCapacity();
   if (perspective_ == Perspective::IS_CLIENT) {
-    if (config_.HasClientSentConnectionOption(kCHP1, perspective_)) {
-      config_.SetDiscardLengthToSend(kDefaultMaxPacketSize);
-    } else if (config_.HasClientSentConnectionOption(kCHP2, perspective_)) {
-      config_.SetDiscardLengthToSend(kDefaultMaxPacketSize * 2);
+    if (config()->HasClientSentConnectionOption(kCHP1, perspective_)) {
+      config()->SetDiscardLengthToSend(kDefaultMaxPacketSize);
+    } else if (config()->HasClientSentConnectionOption(kCHP2, perspective_)) {
+      config()->SetDiscardLengthToSend(kDefaultMaxPacketSize * 2);
     }
-    if (config_.HasClientRequestedIndependentOption(kAFIA, perspective_) &&
+    if (config()->HasClientRequestedIndependentOption(kAFIA, perspective_) &&
         connection_->version().IsIetfQuic()) {
-      config_.SetMinAckDelayDraft10Ms(kDefaultMinAckDelayTimeMs);
+      config()->SetMinAckDelayDraft10Ms(kDefaultMinAckDelayTimeMs);
     }
   } else if (GetQuicReloadableFlag(quic_receive_ack_frequency) &&
              connection_->version().IsIetfQuic()) {
-    config_.SetMinAckDelayDraft10Ms(kDefaultMinAckDelayTimeMs);
+    config()->SetMinAckDelayDraft10Ms(kDefaultMinAckDelayTimeMs);
   }
-  connection_->SetFromConfig(config_);
+  connection_->SetFromConfig(*config());
   if (perspective() == Perspective::IS_SERVER &&
       connection_->version().IsIetfQuic()) {
-    config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
+    config()->SetStatelessResetTokenToSend(GetStatelessResetToken());
   }
 
   connection_->CreateConnectionIdManager();
@@ -1336,12 +1336,12 @@
   }
 
   QUIC_DVLOG(1) << ENDPOINT << "OnConfigNegotiated";
-  connection_->SetFromConfig(config_);
+  connection_->SetFromConfig(*config());
 
   if (VersionIsIetfQuic(transport_version())) {
     uint32_t max_streams = 0;
-    if (config_.HasReceivedMaxBidirectionalStreams()) {
-      max_streams = config_.ReceivedMaxBidirectionalStreams();
+    if (config()->HasReceivedMaxBidirectionalStreams()) {
+      max_streams = config()->ReceivedMaxBidirectionalStreams();
     }
     if (was_zero_rtt_rejected_ &&
         max_streams <
@@ -1381,8 +1381,8 @@
     }
 
     max_streams = 0;
-    if (config_.HasReceivedMaxUnidirectionalStreams()) {
-      max_streams = config_.ReceivedMaxUnidirectionalStreams();
+    if (config()->HasReceivedMaxUnidirectionalStreams()) {
+      max_streams = config()->ReceivedMaxUnidirectionalStreams();
     }
 
     if (was_zero_rtt_rejected_ &&
@@ -1423,8 +1423,8 @@
     }
   } else {
     uint32_t max_streams = 0;
-    if (config_.HasReceivedMaxBidirectionalStreams()) {
-      max_streams = config_.ReceivedMaxBidirectionalStreams();
+    if (config()->HasReceivedMaxBidirectionalStreams()) {
+      max_streams = config()->ReceivedMaxBidirectionalStreams();
     }
     QUIC_DVLOG(1) << ENDPOINT << "Setting max_open_outgoing_streams_ to "
                   << max_streams;
@@ -1443,34 +1443,34 @@
   }
 
   if (perspective() == Perspective::IS_SERVER) {
-    if (config_.HasReceivedConnectionOptions()) {
+    if (config()->HasReceivedConnectionOptions()) {
       // The following variations change the initial receive flow control
       // window sizes.
-      if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW6)) {
+      if (ContainsQuicTag(config()->ReceivedConnectionOptions(), kIFW6)) {
         AdjustInitialFlowControlWindows(64 * 1024);
       }
-      if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW7)) {
+      if (ContainsQuicTag(config()->ReceivedConnectionOptions(), kIFW7)) {
         AdjustInitialFlowControlWindows(128 * 1024);
       }
-      if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW8)) {
+      if (ContainsQuicTag(config()->ReceivedConnectionOptions(), kIFW8)) {
         AdjustInitialFlowControlWindows(256 * 1024);
       }
-      if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFW9)) {
+      if (ContainsQuicTag(config()->ReceivedConnectionOptions(), kIFW9)) {
         AdjustInitialFlowControlWindows(512 * 1024);
       }
-      if (ContainsQuicTag(config_.ReceivedConnectionOptions(), kIFWa)) {
+      if (ContainsQuicTag(config()->ReceivedConnectionOptions(), kIFWa)) {
         AdjustInitialFlowControlWindows(1024 * 1024);
       }
     }
 
-    config_.SetStatelessResetTokenToSend(GetStatelessResetToken());
+    config()->SetStatelessResetTokenToSend(GetStatelessResetToken());
   }
 
   if (VersionIsIetfQuic(transport_version())) {
     ietf_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams(
-        config_.GetMaxBidirectionalStreamsToSend());
+        config()->GetMaxBidirectionalStreamsToSend());
     ietf_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams(
-        config_.GetMaxUnidirectionalStreamsToSend());
+        config()->GetMaxUnidirectionalStreamsToSend());
   } else {
     // A small number of additional incoming streams beyond the limit should be
     // allowed. This helps avoid early connection termination when FIN/RSTs for
@@ -1478,7 +1478,7 @@
     // Use a minimum number of additional streams, or a percentage increase,
     // whichever is larger.
     uint32_t max_incoming_streams_to_send =
-        config_.GetMaxBidirectionalStreamsToSend();
+        config()->GetMaxBidirectionalStreamsToSend();
     uint32_t max_incoming_streams =
         std::max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement,
                  static_cast<uint32_t>(max_incoming_streams_to_send *
@@ -1489,49 +1489,49 @@
   if (connection_->version().IsIetfQuic()) {
     // When using IETF-style TLS transport parameters, inform existing streams
     // of new flow-control limits.
-    if (config_.HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()) {
+    if (config()->HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()) {
       OnNewStreamOutgoingBidirectionalFlowControlWindow(
-          config_.ReceivedInitialMaxStreamDataBytesOutgoingBidirectional());
+          config()->ReceivedInitialMaxStreamDataBytesOutgoingBidirectional());
     }
-    if (config_.HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()) {
+    if (config()->HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()) {
       OnNewStreamIncomingBidirectionalFlowControlWindow(
-          config_.ReceivedInitialMaxStreamDataBytesIncomingBidirectional());
+          config()->ReceivedInitialMaxStreamDataBytesIncomingBidirectional());
     }
-    if (config_.HasReceivedInitialMaxStreamDataBytesUnidirectional()) {
+    if (config()->HasReceivedInitialMaxStreamDataBytesUnidirectional()) {
       OnNewStreamUnidirectionalFlowControlWindow(
-          config_.ReceivedInitialMaxStreamDataBytesUnidirectional());
+          config()->ReceivedInitialMaxStreamDataBytesUnidirectional());
     }
   } else {  // The version uses Google QUIC Crypto.
-    if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) {
+    if (config()->HasReceivedInitialStreamFlowControlWindowBytes()) {
       // Streams which were created before the SHLO was received (0-RTT
       // requests) are now informed of the peer's initial flow control window.
       OnNewStreamFlowControlWindow(
-          config_.ReceivedInitialStreamFlowControlWindowBytes());
+          config()->ReceivedInitialStreamFlowControlWindowBytes());
     }
   }
 
-  if (config_.HasReceivedInitialSessionFlowControlWindowBytes()) {
+  if (config()->HasReceivedInitialSessionFlowControlWindowBytes()) {
     OnNewSessionFlowControlWindow(
-        config_.ReceivedInitialSessionFlowControlWindowBytes());
+        config()->ReceivedInitialSessionFlowControlWindowBytes());
   }
 
   if (perspective_ == Perspective::IS_SERVER && version().IsIetfQuic() &&
       connection_->effective_peer_address().IsInitialized()) {
-    if (config_.SupportsServerPreferredAddress(perspective_)) {
+    if (config()->SupportsServerPreferredAddress(perspective_)) {
       quiche::IpAddressFamily address_family =
           connection_->effective_peer_address()
               .Normalized()
               .host()
               .address_family();
       std::optional<QuicSocketAddress> expected_preferred_address =
-          config_.GetMappedAlternativeServerAddress(address_family);
+          config()->GetMappedAlternativeServerAddress(address_family);
       if (expected_preferred_address.has_value()) {
         // Set connection ID and token if SPAD has received and a preferred
         // address of the same address family is configured.
         std::optional<QuicNewConnectionIdFrame> frame =
             connection_->MaybeIssueNewConnectionIdForPreferredAddress();
         if (frame.has_value()) {
-          config_.SetPreferredAddressConnectionIdAndTokenToSend(
+          config()->SetPreferredAddressConnectionIdAndTokenToSend(
               frame->connection_id, frame->stateless_reset_token);
         }
         connection_->set_expected_server_preferred_address(
@@ -1539,15 +1539,17 @@
       }
       // Clear the alternative address of the other address family in the
       // config.
-      config_.ClearAlternateServerAddressToSend(
+      config()->ClearAlternateServerAddressToSend(
           address_family == quiche::IpAddressFamily::IP_V4
               ? quiche::IpAddressFamily::IP_V6
               : quiche::IpAddressFamily::IP_V4);
     } else {
       // Clear alternative IPv(4|6) addresses in config if the server hasn't
       // received 'SPAD' connection option.
-      config_.ClearAlternateServerAddressToSend(quiche::IpAddressFamily::IP_V4);
-      config_.ClearAlternateServerAddressToSend(quiche::IpAddressFamily::IP_V6);
+      config()->ClearAlternateServerAddressToSend(
+          quiche::IpAddressFamily::IP_V4);
+      config()->ClearAlternateServerAddressToSend(
+          quiche::IpAddressFamily::IP_V6);
     }
   }
 
@@ -1572,19 +1574,19 @@
 
 void QuicSession::AdjustInitialFlowControlWindows(size_t stream_window) {
   const float session_window_multiplier =
-      config_.GetInitialStreamFlowControlWindowToSend()
+      config()->GetInitialStreamFlowControlWindowToSend()
           ? static_cast<float>(
-                config_.GetInitialSessionFlowControlWindowToSend()) /
-                config_.GetInitialStreamFlowControlWindowToSend()
+                config()->GetInitialSessionFlowControlWindowToSend()) /
+                config()->GetInitialStreamFlowControlWindowToSend()
           : 1.5;
 
   QUIC_DVLOG(1) << ENDPOINT << "Set stream receive window to " << stream_window;
-  config_.SetInitialStreamFlowControlWindowToSend(stream_window);
+  config()->SetInitialStreamFlowControlWindowToSend(stream_window);
 
   size_t session_window = session_window_multiplier * stream_window;
   QUIC_DVLOG(1) << ENDPOINT << "Set session receive window to "
                 << session_window;
-  config_.SetInitialSessionFlowControlWindowToSend(session_window);
+  config()->SetInitialSessionFlowControlWindowToSend(session_window);
   flow_controller_.UpdateReceiveWindowSize(session_window);
   // Inform all existing streams about the new window.
   for (auto const& kv : stream_map_) {
@@ -1871,7 +1873,7 @@
     case ENCRYPTION_HANDSHAKE:
       break;
     case ENCRYPTION_FORWARD_SECURE:
-      QUIC_BUG_IF(quic_bug_12435_8, !config_.negotiated())
+      QUIC_BUG_IF(quic_bug_12435_8, !config()->negotiated())
           << ENDPOINT << "Handshake confirmed without parameter negotiation.";
       connection()->mutable_stats().handshake_completion_time =
           connection()->clock()->ApproximateNow();
@@ -1886,15 +1888,15 @@
   QUIC_BUG_IF(quic_bug_12435_9,
               !GetCryptoStream()->crypto_negotiated_params().cipher_suite)
       << ENDPOINT << "Handshake completes without cipher suite negotiation.";
-  QUIC_BUG_IF(quic_bug_12435_10, !config_.negotiated())
+  QUIC_BUG_IF(quic_bug_12435_10, !config()->negotiated())
       << ENDPOINT << "Handshake completes without parameter negotiation.";
   connection()->mutable_stats().handshake_completion_time =
       connection()->clock()->ApproximateNow();
-  if (connection()->ShouldFixTimeouts(config_)) {
+  if (connection()->ShouldFixTimeouts(*config())) {
     QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_timeouts, 2, 2);
     // Handshake complete, set handshake timeout to Infinite.
     connection()->SetNetworkTimeouts(QuicTime::Delta::Infinite(),
-                                     config_.IdleNetworkTimeout());
+                                     config()->IdleNetworkTimeout());
   }
   if (connection()->version().IsIetfQuic() &&
       perspective_ == Perspective::IS_SERVER) {
@@ -1968,6 +1970,7 @@
   GetMutableCryptoStream()->NeuterStreamDataOfEncryptionLevel(
       ENCRYPTION_HANDSHAKE);
   connection()->OnHandshakeComplete();
+  saved_config_.DeleteConfig();
 }
 
 void QuicSession::OnZeroRttRejected(int reason) {
@@ -1986,22 +1989,23 @@
 bool QuicSession::FillTransportParameters(TransportParameters* params) {
   if (version().IsIetfQuic()) {
     if (perspective() == Perspective::IS_SERVER) {
-      config_.SetOriginalConnectionIdToSend(
+      config()->SetOriginalConnectionIdToSend(
           connection_->GetOriginalDestinationConnectionId());
-      config_.SetInitialSourceConnectionIdToSend(connection_->connection_id());
+      config()->SetInitialSourceConnectionIdToSend(
+          connection_->connection_id());
     } else {
-      config_.SetInitialSourceConnectionIdToSend(
+      config()->SetInitialSourceConnectionIdToSend(
           connection_->client_connection_id());
     }
   }
-  return config_.FillTransportParameters(params);
+  return config()->FillTransportParameters(params);
 }
 
 QuicErrorCode QuicSession::ProcessTransportParameters(
     const TransportParameters& params, bool is_resumption,
     std::string* error_details) {
-  return config_.ProcessTransportParameters(params, is_resumption,
-                                            error_details);
+  return config()->ProcessTransportParameters(params, is_resumption,
+                                              error_details);
 }
 
 void QuicSession::OnHandshakeCallbackDone() {
diff --git a/quiche/quic/core/quic_session.h b/quiche/quic/core/quic_session.h
index 9faeb23..ca0d23c 100644
--- a/quiche/quic/core/quic_session.h
+++ b/quiche/quic/core/quic_session.h
@@ -115,6 +115,93 @@
     virtual void OnConfigNegotiated(const QuicConfig& config) = 0;
   };
 
+  // Wrapper around a `QuicConfig` which provides access to the underlying
+  // config.
+  class QUICHE_EXPORT SavedConfig {
+   public:
+    // Creates a new `SavedConfig` which stores a copy of `config`.
+    SavedConfig(const QuicConfig& config) : config_(config) {}
+
+    // Returns the underlying `QuicConfig`. Must not be called after the config
+    // is deleted.
+    QuicConfig* RawConfig() {
+      QUIC_BUG_IF(no_config, config_deleted_);
+      return &config_;
+    }
+
+    // Marks the config deleted but does not actually delete it.
+    // TODO(b/461482627): Store `config_` in a unique_ptr and reset it.
+    void DeleteConfig() { config_deleted_ = true; }
+
+    bool HasReceivedInitialStreamFlowControlWindowBytes() const {
+      return config_.HasReceivedInitialStreamFlowControlWindowBytes();
+    }
+
+    bool HasReceivedInitialMaxStreamDataBytesUnidirectional() const {
+      return config_.HasReceivedInitialMaxStreamDataBytesUnidirectional();
+    }
+
+    bool HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const {
+      return config_
+          .HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional();
+    }
+
+    bool HasReceivedInitialMaxStreamDataBytesIncomingBidirectional() const {
+      return config_
+          .HasReceivedInitialMaxStreamDataBytesIncomingBidirectional();
+    }
+
+    bool HasReceivedMaxBidirectionalStreams() const {
+      return config_.HasReceivedMaxBidirectionalStreams();
+    }
+
+    uint64_t ReceivedInitialStreamFlowControlWindowBytes() const {
+      return config_.ReceivedInitialStreamFlowControlWindowBytes();
+    }
+
+    uint64_t ReceivedInitialMaxStreamDataBytesUnidirectional() const {
+      return config_.ReceivedInitialMaxStreamDataBytesUnidirectional();
+    }
+
+    uint64_t ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const {
+      return config_.ReceivedInitialMaxStreamDataBytesOutgoingBidirectional();
+    }
+
+    uint64_t ReceivedInitialMaxStreamDataBytesIncomingBidirectional() const {
+      return config_.ReceivedInitialMaxStreamDataBytesIncomingBidirectional();
+    }
+
+    uint64_t GetInitialStreamFlowControlWindowToSend() const {
+      return config_.GetInitialStreamFlowControlWindowToSend();
+    }
+
+    uint64_t GetInitialMaxStreamDataBytesUnidirectionalToSend() const {
+      return config_.GetInitialMaxStreamDataBytesUnidirectionalToSend();
+    }
+
+    uint64_t GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() const {
+      return config_.GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend();
+    }
+
+    uint64_t GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() const {
+      return config_.GetInitialMaxStreamDataBytesIncomingBidirectionalToSend();
+    }
+
+    uint64_t ReceivedMaxBidirectionalStreams() const {
+      return config_.ReceivedMaxBidirectionalStreams();
+    }
+
+    QuicTime::Delta IdleNetworkTimeout() const {
+      return config_.IdleNetworkTimeout();
+    }
+
+   private:
+    // TODO(b/461482627): Store `config_` in a unique_ptr and reset it in
+    // `DeleteConfig()`.
+    QuicConfig config_;
+    bool config_deleted_ = false;
+  };
+
   // Does not take ownership of |connection| or |visitor|.
   QuicSession(QuicConnection* connection, Visitor* owner,
               const QuicConfig& config,
@@ -384,9 +471,10 @@
       const CryptoHandshakeMessage& message);
 
   // Returns mutable config for this session. Returned config is owned
-  // by QuicSession.
-  QuicConfig* config() { return &config_; }
-  const QuicConfig* config() const { return &config_; }
+  // by QuicSession. Must not be called after the handshake completes.
+  QuicConfig* config() { return saved_config_.RawConfig(); }
+
+  const SavedConfig& GetSavedConfig() const { return saved_config_; }
 
   // Returns true if the stream existed previously and has been closed.
   // Returns false if the stream is still active or if the stream has
@@ -1133,7 +1221,7 @@
   // Manages stream IDs for version99/IETF QUIC
   UberQuicStreamIdManager ietf_streamid_manager_;
 
-  QuicConfig config_;
+  SavedConfig saved_config_;
 };
 
 }  // namespace quic
diff --git a/quiche/quic/core/quic_stream.cc b/quiche/quic/core/quic_stream.cc
index 8447c57..2b2395e 100644
--- a/quiche/quic/core/quic_stream.cc
+++ b/quiche/quic/core/quic_stream.cc
@@ -66,32 +66,34 @@
                                                       QuicStreamId stream_id) {
   ParsedQuicVersion version = session->connection()->version();
   if (!version.IsIetfQuic()) {
-    return session->config()->GetInitialStreamFlowControlWindowToSend();
+    return session->GetSavedConfig().GetInitialStreamFlowControlWindowToSend();
   }
 
   // Unidirectional streams (v99 only).
   if (VersionIsIetfQuic(version.transport_version) &&
       !QuicUtils::IsBidirectionalStreamId(stream_id, version)) {
-    return session->config()
-        ->GetInitialMaxStreamDataBytesUnidirectionalToSend();
+    return session->GetSavedConfig()
+        .GetInitialMaxStreamDataBytesUnidirectionalToSend();
   }
 
   if (QuicUtils::IsOutgoingStreamId(version, stream_id,
                                     session->perspective())) {
-    return session->config()
-        ->GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend();
+    return session->GetSavedConfig()
+        .GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend();
   }
 
-  return session->config()
-      ->GetInitialMaxStreamDataBytesIncomingBidirectionalToSend();
+  return session->GetSavedConfig()
+      .GetInitialMaxStreamDataBytesIncomingBidirectionalToSend();
 }
 
 QuicByteCount GetReceivedFlowControlWindow(QuicSession* session,
                                            QuicStreamId stream_id) {
   ParsedQuicVersion version = session->connection()->version();
   if (!version.IsIetfQuic()) {
-    if (session->config()->HasReceivedInitialStreamFlowControlWindowBytes()) {
-      return session->config()->ReceivedInitialStreamFlowControlWindowBytes();
+    if (session->GetSavedConfig()
+            .HasReceivedInitialStreamFlowControlWindowBytes()) {
+      return session->GetSavedConfig()
+          .ReceivedInitialStreamFlowControlWindowBytes();
     }
 
     return DefaultFlowControlWindow(version);
@@ -100,10 +102,10 @@
   // Unidirectional streams (v99 only).
   if (VersionIsIetfQuic(version.transport_version) &&
       !QuicUtils::IsBidirectionalStreamId(stream_id, version)) {
-    if (session->config()
-            ->HasReceivedInitialMaxStreamDataBytesUnidirectional()) {
-      return session->config()
-          ->ReceivedInitialMaxStreamDataBytesUnidirectional();
+    if (session->GetSavedConfig()
+            .HasReceivedInitialMaxStreamDataBytesUnidirectional()) {
+      return session->GetSavedConfig()
+          .ReceivedInitialMaxStreamDataBytesUnidirectional();
     }
 
     return DefaultFlowControlWindow(version);
@@ -111,19 +113,19 @@
 
   if (QuicUtils::IsOutgoingStreamId(version, stream_id,
                                     session->perspective())) {
-    if (session->config()
-            ->HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()) {
-      return session->config()
-          ->ReceivedInitialMaxStreamDataBytesOutgoingBidirectional();
+    if (session->GetSavedConfig()
+            .HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()) {
+      return session->GetSavedConfig()
+          .ReceivedInitialMaxStreamDataBytesOutgoingBidirectional();
     }
 
     return DefaultFlowControlWindow(version);
   }
 
-  if (session->config()
-          ->HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()) {
-    return session->config()
-        ->ReceivedInitialMaxStreamDataBytesIncomingBidirectional();
+  if (session->GetSavedConfig()
+          .HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()) {
+    return session->GetSavedConfig()
+        .ReceivedInitialMaxStreamDataBytesIncomingBidirectional();
   }
 
   return DefaultFlowControlWindow(version);
diff --git a/quiche/quic/test_tools/quic_connection_peer.cc b/quiche/quic/test_tools/quic_connection_peer.cc
index e140b69..9e94e70 100644
--- a/quiche/quic/test_tools/quic_connection_peer.cc
+++ b/quiche/quic/test_tools/quic_connection_peer.cc
@@ -623,5 +623,11 @@
       .reordering_threshold_;
 }
 
+// static
+bool QuicConnectionPeer::ConnectionMigrationDisabled(
+    QuicConnection* connection) {
+  return connection->active_migration_disabled_;
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/quiche/quic/test_tools/quic_connection_peer.h b/quiche/quic/test_tools/quic_connection_peer.h
index c5fbddf..d7b9378 100644
--- a/quiche/quic/test_tools/quic_connection_peer.h
+++ b/quiche/quic/test_tools/quic_connection_peer.h
@@ -256,6 +256,8 @@
       const QuicConnection* connection);
 
   static uint64_t GetPeerReorderingThreshold(QuicConnection* connection);
+
+  static bool ConnectionMigrationDisabled(QuicConnection* connection);
 };
 
 }  // namespace test