Skip to content

ProxyProtocol: free pp_info heap on NetVConnection recycle#13292

Closed
moonchen wants to merge 1 commit into
masterfrom
mchen/proxyprotocol-free-pp-info
Closed

ProxyProtocol: free pp_info heap on NetVConnection recycle#13292
moonchen wants to merge 1 commit into
masterfrom
mchen/proxyprotocol-free-pp-info

Conversation

@moonchen

Copy link
Copy Markdown
Contributor

Problem

NetVConnection embeds ProxyProtocol pp_info by value, and ProxyProtocol owns heap (the additional_data string and the parsed tlv map). has_proxy_protocol() parses an inbound PROXY v2 header into pp_info once per connection, allocating both.

The NetVC ClassAllocators are Destruct_on_free=false, so ~ProxyProtocol never runs when a VC is recycled and UnixNetVConnection::clear() did not release pp_info. The slot's next placement-new then abandons the string buffer and map nodes — leaking once per recycled connection that carried a PROXY v2 header, i.e. every inbound connection behind a PROXY-protocol load balancer.

Fix

Add ProxyProtocol::reset() and call it from UnixNetVConnection::clear(), the single recycle chokepoint (SSL and QUIC clear() chain to it, and clear() runs only on the free path). reset() swaps the members with empty containers rather than clear()ing them, since clear() keeps capacity that the recycle would still abandon. Releasing pp_info in clear() is safe: it is read only while the VC is live.

Targeted rather than flipping the allocators to Destruct_on_free=true, which would run the full destructor chain on top of the existing manual clear()/free_thread() teardown and needs a separate idempotency audit.

Copilot AI review requested due to automatic review settings June 17, 2026 22:04
@moonchen moonchen self-assigned this Jun 17, 2026
@moonchen moonchen added this to the 11.0.0 milestone Jun 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a per-connection recycle memory leak when inbound PROXY v2 headers are parsed into NetVConnection::pp_info but the VC is later recycled via a ClassAllocator configured with Destruct_on_free=false.

Changes:

  • Add ProxyProtocol::reset() to explicitly release heap-owned state (additional_data and tlv) and restore default values.
  • Call pp_info.reset() from UnixNetVConnection::clear() so recycled NetVCs don’t retain/abandon PROXY-protocol allocations.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/iocore/net/UnixNetVConnection.cc Ensures pp_info heap allocations are released during VC recycle (clear()).
include/iocore/net/ProxyProtocol.h Adds ProxyProtocol::reset() which frees container capacity via swap and resets fields.

Comment on lines +86 to +102
/** 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 = {};
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a TEST_CASE("ProxyProtocol reset") in test_ProxyProtocol.cc (commit 98c0183): it parses a PROXY v2 header carrying TLVs into pp_info, calls reset(), and asserts version == UNDEFINED, ip_family == AF_UNSPEC, type == 0, both addresses cleared, tlv.empty(), and get_tlv(PP2_TYPE_ALPN) == nullopt, plus an idempotent second reset(). Verified locally: All tests passed (14 assertions).

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) <noreply@anthropic.com>
@moonchen moonchen force-pushed the mchen/proxyprotocol-free-pp-info branch from 6f21391 to 98c0183 Compare June 17, 2026 22:15
@moonchen

Copy link
Copy Markdown
Contributor Author

Superseded by #13293, which carries the identical commit from my fork (moonchen) instead of a branch on the apache repo.

@moonchen moonchen closed this Jun 17, 2026
@moonchen moonchen deleted the mchen/proxyprotocol-free-pp-info branch June 17, 2026 22:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants