You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by mo...@apache.org on 2026/06/17 22:03:40 UTC
(trafficserver) branch mchen/proxyprotocol-free-pp-info created (now 6f21391e7d)
This is an automated email from the ASF dual-hosted git repository.
moonchen pushed a change to branch mchen/proxyprotocol-free-pp-info
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
at 6f21391e7d ProxyProtocol: free pp_info heap on NetVConnection recycle
This branch includes the following new commits:
new 6f21391e7d ProxyProtocol: free pp_info heap on NetVConnection recycle
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(trafficserver) 01/01: ProxyProtocol: free pp_info heap on NetVConnection recycle
Posted by mo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
moonchen pushed a commit to branch mchen/proxyprotocol-free-pp-info
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 6f21391e7de3f8905aec58b00de898a324cd768a
Author: Mo Chen <mo...@apache.org>
AuthorDate: Wed Jun 17 15:44:25 2026 -0500
ProxyProtocol: free pp_info heap on NetVConnection recycle
NetVConnection embeds a ProxyProtocol by value, and a PROXY v2 header parsed
by has_proxy_protocol() heap-allocates ProxyProtocol::additional_data (the TLV
blob) plus the tlv map. The NetVConnection ClassAllocators are
Destruct_on_free=false, so ~ProxyProtocol never runs when a VC is recycled and
UnixNetVConnection::clear() did not release pp_info -- the next placement-new on
the recycled slot abandoned the buffer and map nodes, leaking once per recycled
connection that carried a PROXY v2 header. Behind a PROXY-protocol load
balancer that is every inbound connection.
Add ProxyProtocol::reset() and call it from UnixNetVConnection::clear() (the
single recycle chokepoint for the Unix, SSL and QUIC VCs). reset() swaps the
members with empty containers rather than clear()ing them, because clear()
retains capacity that the recycle would still abandon.
Co-Authored-By: Claude Opus 4.8 (1M context) <no...@anthropic.com>
---
include/iocore/net/ProxyProtocol.h | 19 +++++++++++++++++++
src/iocore/net/UnixNetVConnection.cc | 3 +++
2 files changed, 22 insertions(+)
diff --git a/include/iocore/net/ProxyProtocol.h b/include/iocore/net/ProxyProtocol.h
index d3a7c73671..7d7fc34e46 100644
--- a/include/iocore/net/ProxyProtocol.h
+++ b/include/iocore/net/ProxyProtocol.h
@@ -82,6 +82,25 @@ public:
other.tlv.clear();
}
~ProxyProtocol() = default;
+
+ /** Release owned heap and reset to the default-constructed state.
+ *
+ * Swap rather than clear() the containers: clear() retains capacity, which would be abandoned
+ * (leaked) when the slot is reused, since the NetVConnection allocators are Destruct_on_free=false
+ * and so never run ~ProxyProtocol.
+ */
+ void
+ reset()
+ {
+ std::string{}.swap(additional_data);
+ std::unordered_map<uint8_t, std::string_view>{}.swap(tlv);
+ version = ProxyProtocolVersion::UNDEFINED;
+ ip_family = AF_UNSPEC;
+ type = 0;
+ src_addr = {};
+ dst_addr = {};
+ }
+
int set_additional_data(std::string_view data);
void set_ipv4_addrs(in_addr_t src_addr, uint16_t src_port, in_addr_t dst_addr, uint16_t dst_port);
void set_ipv6_addrs(const in6_addr &src_addr, uint16_t src_port, const in6_addr &dst_addr, uint16_t dst_port);
diff --git a/src/iocore/net/UnixNetVConnection.cc b/src/iocore/net/UnixNetVConnection.cc
index 29e1b4dead..8e18df53ed 100644
--- a/src/iocore/net/UnixNetVConnection.cc
+++ b/src/iocore/net/UnixNetVConnection.cc
@@ -1220,6 +1220,9 @@ UnixNetVConnection::clear()
read.vio.vc_server = nullptr;
write.vio.vc_server = nullptr;
options.reset();
+ // The VC allocator is Destruct_on_free=false (~ProxyProtocol never runs on recycle), so release
+ // pp_info's heap explicitly here.
+ pp_info.reset();
if (netvc_context == NET_VCONNECTION_OUT) {
read.vio.buffer.clear();
write.vio.buffer.clear();