Skip to content

[curl] Free pushed handle when CURLMOPT_PUSHFUNCTION denies or throws - #297

Open
iliaal wants to merge 1 commit into
PHP-8.4from
fix/curl-push-deny-leak-84
Open

[curl] Free pushed handle when CURLMOPT_PUSHFUNCTION denies or throws#297
iliaal wants to merge 1 commit into
PHP-8.4from
fix/curl-push-deny-leak-84

Conversation

@iliaal

@iliaal iliaal commented Aug 24, 2026

Copy link
Copy Markdown
Owner

On CURL_PUSH_DENY or a throw in the CURLMOPT_PUSHFUNCTION callback, libcurl destroys the pushed handle itself, but ext/curl leaves ch->cp stale and never releases the new CurlHandle zval, leaking a wrapper per denied push. _php_setup_easy_copy_handlers() had cloned it from the parent, so the shared clone counter stays permanently bumped and ch->cp dangles. Teardown moves from curl_free_obj() into _php_curl_free_instance(), reused when the callback denies or throws to clear ch->cp, undo the increment, release state and drop the zval. The phpt drives 200 denied pushes, skipping when none arrive.

When the server push callback denies the push (or throws, leaving retval
undefined) libcurl destroys the easy handle itself, so the wrapper must
not touch ch->cp afterwards; previously the newly created CurlHandle zval
was never released, leaking the object and permanently bumping the shared
parent clone counter because _php_setup_easy_copy_handlers() had already
registered the clone. The per-instance teardown (handler buffers, FCCs,
stream refs, postfields/private_data) is factored out of curl_free_obj()
into _php_curl_free_instance() and reused for the denied handle, keeping
curl destructors owned by the surviving clone counter invariant intact;
sibling audit found no other affected call sites.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant