From 9c443c96aeab597a031cc35d2998a34646898d2e Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Tue, 14 Jul 2026 11:23:37 +0000 Subject: [PATCH 1/2] Fix leak when cURL PREREQFUNCTION returns a string The return value of the function registered with CURLOPT_PREREQFUNCTION was not cleaned up. Destroy the return value. Increase the returned string in the test so that the address sanitizer picks up the leak. --- ext/curl/interface.c | 1 + ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 7fc1c77e9a9a..4e4da5503bbb 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -770,6 +770,7 @@ static int curl_prereqfunction(void *clientp, char *conn_primary_ip, char *conn_ zend_value_error("The CURLOPT_PREREQFUNCTION callback must return either CURL_PREREQFUNC_OK or CURL_PREREQFUNC_ABORT"); } } else { + zval_ptr_dtor(&retval); zend_type_error("The CURLOPT_PREREQFUNCTION callback must return either CURL_PREREQFUNC_OK or CURL_PREREQFUNC_ABORT"); } } diff --git a/ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt b/ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt index d11e29f078c0..89105734a556 100644 --- a/ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt +++ b/ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt @@ -77,7 +77,7 @@ try { echo "\nTesting with invalid type\n"; curl_setopt($ch, CURLOPT_PREREQFUNCTION, function() use ($port) { - return 'this should be an integer'; + return str_repeat('this should be an integer', 20); }); try { curl_exec($ch); From d7b9b3fc9afab4fb8e6043293d4ebf4bf57e160f Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Tue, 14 Jul 2026 11:36:33 +0000 Subject: [PATCH 2/2] Return an array instead of string to test memleak The CURLOPT_PREREQFUNCTION leak test returned a constant string value. Under opcache optimization, SCCP/constant folding may turn this into an interned string, which is process-lifetime allocated and therefore does not reliably trigger leak detection. Use a dynamically allocated array containing random_bytes() instead. This guarantees a non-interned, refcounted return value that exercises the missing zval_ptr_dtor() path consistently under leak analyzers. --- ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt b/ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt index 89105734a556..75d9324f15db 100644 --- a/ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt +++ b/ext/curl/tests/curl_setopt_CURLOPT_PREREQFUNCTION.phpt @@ -77,7 +77,7 @@ try { echo "\nTesting with invalid type\n"; curl_setopt($ch, CURLOPT_PREREQFUNCTION, function() use ($port) { - return str_repeat('this should be an integer', 20); + return ['this should be an integer' => random_bytes(64)]; }); try { curl_exec($ch);