Change quicpacketwriter::getnextwritelocation to return a release function used to free a writer-allocated buffer. use this release function to avoid buffer leak if a writer buffer is allocated but writer->writepacket is not called. protected by --gfe2_reloadable_flag_quic_avoid_leak_writer_buffer.
This is needed to fix a buffer leak when the new PigeonWriter is used.
PiperOrigin-RevId: 312369772
Change-Id: I0d12327b58989ec69e401b03f7b9ebb4d8ce22fd
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index 4db87e2..a91d264 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -439,12 +439,23 @@
}
QUIC_CACHELINE_ALIGNED char stack_buffer[kMaxOutgoingPacketSize];
- char* serialized_packet_buffer = delegate_->GetPacketBuffer();
- if (serialized_packet_buffer == nullptr) {
- serialized_packet_buffer = stack_buffer;
+ QuicOwnedPacketBuffer external_buffer(delegate_->GetPacketBuffer());
+
+ if (!avoid_leak_writer_buffer_ && external_buffer.release_buffer != nullptr) {
+ // This is not a flag count because it is incremented when flag is false.
+ QUIC_CODE_COUNT(quic_avoid_leak_writer_buffer_flag_false_noop_1);
+
+ // Setting it to nullptr to keep the behavior unchanged when flag is false.
+ external_buffer.release_buffer = nullptr;
}
- SerializePacket(serialized_packet_buffer, kMaxOutgoingPacketSize);
+ if (external_buffer.buffer == nullptr) {
+ external_buffer.buffer = stack_buffer;
+ external_buffer.release_buffer = nullptr;
+ }
+
+ DCHECK_EQ(nullptr, packet_.encrypted_buffer);
+ SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize);
OnSerializedPacket();
}
@@ -471,6 +482,12 @@
packet_.transmission_type = NOT_RETRANSMISSION;
packet_.encrypted_buffer = nullptr;
packet_.encrypted_length = 0;
+ if (avoid_leak_writer_buffer_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_avoid_leak_writer_buffer, 2, 3);
+ QUIC_BUG_IF(packet_.release_encrypted_buffer != nullptr)
+ << "packet_.release_encrypted_buffer should be empty";
+ packet_.release_encrypted_buffer = nullptr;
+ }
DCHECK(packet_.retransmittable_frames.empty());
DCHECK(packet_.nonretransmittable_frames.empty());
packet_.largest_acked.Clear();
@@ -514,7 +531,7 @@
return 0;
}
}
- SerializePacket(buffer, buffer_len);
+ SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len);
const size_t encrypted_length = packet_.encrypted_length;
// Clear frames in packet_. No need to DeleteFrames since frames are owned by
// initial_packet.
@@ -538,11 +555,23 @@
FillPacketHeader(&header);
QUIC_CACHELINE_ALIGNED char stack_buffer[kMaxOutgoingPacketSize];
- char* encrypted_buffer = delegate_->GetPacketBuffer();
- if (encrypted_buffer == nullptr) {
- encrypted_buffer = stack_buffer;
+ QuicOwnedPacketBuffer packet_buffer(delegate_->GetPacketBuffer());
+
+ if (!avoid_leak_writer_buffer_ && packet_buffer.release_buffer != nullptr) {
+ // This is not a flag count because it is incremented when flag is false.
+ QUIC_CODE_COUNT(quic_avoid_leak_writer_buffer_flag_false_noop_2);
+
+ // Setting it to nullptr to keep the behavior unchanged when flag is false.
+ packet_buffer.release_buffer = nullptr;
}
+ if (packet_buffer.buffer == nullptr) {
+ packet_buffer.buffer = stack_buffer;
+ packet_buffer.release_buffer = nullptr;
+ }
+
+ char* encrypted_buffer = packet_buffer.buffer;
+
QuicDataWriter writer(kMaxOutgoingPacketSize, encrypted_buffer);
size_t length_field_offset = 0;
if (!framer_->AppendPacketHeader(header, &writer, &length_field_offset)) {
@@ -623,6 +652,14 @@
packet_size_ = 0;
packet_.encrypted_buffer = encrypted_buffer;
packet_.encrypted_length = encrypted_length;
+ if (avoid_leak_writer_buffer_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_avoid_leak_writer_buffer, 3, 3);
+ packet_.release_encrypted_buffer = std::move(packet_buffer).release_buffer;
+ } else {
+ // If flag --quic_avoid_leak_writer_buffer is false, the release function
+ // should be empty.
+ DCHECK(packet_buffer.release_buffer == nullptr);
+ }
packet_.retransmittable_frames.push_back(QuicFrame(frame));
OnSerializedPacket();
}
@@ -691,7 +728,7 @@
return false;
}
-void QuicPacketCreator::SerializePacket(char* encrypted_buffer,
+void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
size_t encrypted_buffer_len) {
DCHECK_LT(0u, encrypted_buffer_len);
QUIC_BUG_IF(queued_frames_.empty() && pending_padding_bytes_ == 0)
@@ -719,7 +756,7 @@
// Use the packet_size_ instead of the buffer size to ensure smaller
// packet sizes are properly used.
size_t length =
- framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer,
+ framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer.buffer,
packet_size_, packet_.encryption_level);
if (length == 0) {
QUIC_BUG << "Failed to serialize " << QuicFramesToString(queued_frames_)
@@ -746,7 +783,7 @@
const size_t encrypted_length = framer_->EncryptInPlace(
packet_.encryption_level, packet_.packet_number,
GetStartOfEncryptedData(framer_->transport_version(), header), length,
- encrypted_buffer_len, encrypted_buffer);
+ encrypted_buffer_len, encrypted_buffer.buffer);
if (encrypted_length == 0) {
QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number;
return;
@@ -754,8 +791,17 @@
packet_size_ = 0;
queued_frames_.clear();
- packet_.encrypted_buffer = encrypted_buffer;
+ packet_.encrypted_buffer = encrypted_buffer.buffer;
packet_.encrypted_length = encrypted_length;
+ if (avoid_leak_writer_buffer_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_avoid_leak_writer_buffer, 1, 3);
+ packet_.release_encrypted_buffer =
+ std::move(encrypted_buffer).release_buffer;
+ } else {
+ // If flag --quic_avoid_leak_writer_buffer is false, the release function
+ // should be empty.
+ DCHECK(encrypted_buffer.release_buffer == nullptr);
+ }
}
std::unique_ptr<QuicEncryptedPacket>