Skip to content

CLI server: make all heap chunks self contained - #23745

Open
DanielEScherzer wants to merge 2 commits into
php:masterfrom
DanielEScherzer:cli-server-leaks
Open

DanielEScherzer wants to merge 2 commits into
php:masterfrom
DanielEScherzer:cli-server-leaks

Conversation

@DanielEScherzer

Copy link
Copy Markdown
Member

For chunks that were pointing to heap data outside of the chunk itself, ASAN would report some memory leaks. Rather than trying to figure out exactly where the right place to free that data is, just copy the data into a self-contained chunk. While this might not be the best option from a performance perspective, the CLI server is meant only as a development tool and accordingly performance is not a major concern.

The static php_cli_server_chunk_heap_new() function was removed.

The php_cli_server_chunk.data.heap.block pointer was removed. Now that all heap allocations are self contained, the block is always the same as the overall chunk; remove the unneeded field. Additionally, php_cli_server_chunk_dtor(), which only acts for heap allocations for which the block was different than the chunk, is no longer needed and is removed.

For chunks that were pointing to heap data outside of the chunk itself, ASAN
would report some memory leaks. Rather than trying to figure out exactly where
the right place to free that data is, just copy the data into a self-contained
chunk. While this might not be the best option from a performance perspective,
the CLI server is meant only as a development tool and accordingly performance
is not a major concern.

The static `php_cli_server_chunk_heap_new()` function was removed, additional
cleanup will be done in subsequent commits.
Now that all heap allocations are self contained, the block is always the same
as the overall chunk; remove the unneeded field. Additionally,
`php_cli_server_chunk_dtor()`, which only acts for heap allocations for which
the block was different than the chunk, is no longer needed and is removed.
@DanielEScherzer

DanielEScherzer commented Sep 18, 2026

Copy link
Copy Markdown
Member Author

I wasn't able to figure out a phpt test to show the leak, but was able to reproduce it reliably with

Details
#!/bin/bash
php -d post_max_size=8M -d memory_limit=128M -S 127.0.0.1:8001 &

PID=$!

echo "PID:"
echo $PID

sleep 2

python3 /var/www/html/leak.py --pid $PID

cleanup() {
	kill -INT $PID
}

trap cleanup EXIT

where that python file is

#!/usr/bin/env python3
import socket

payload = b"B" * (8 * 1024 * 1024)
chunk_hdr = f"800000\r\n".encode()
chunk = chunk_hdr + payload + b"\r\n"

req_head = (
    f"POST / HTTP/1.1\r\n"
    f"Transfer-Encoding: chunked\r\n"
    f"Content-Type: application/octet-stream\r\n"
    f"Connection: close\r\n"
    f"\r\n"
).encode()

s = socket.create_connection(("127.0.0.1", 8001), timeout=10)
s.settimeout(None)
s.sendall(req_head)

s.sendall(chunk)
s.sendall(chunk)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant