mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix memory leaks when returning refcounted value from curl callback
Closes GH-18883.
This commit is contained in:
4
NEWS
4
NEWS
@@ -6,6 +6,10 @@ PHP NEWS
|
||||
. Fixed bug GH-18833 (Use after free with weakmaps dependent on destruction
|
||||
order). (Daniil Gentili)
|
||||
|
||||
- Curl:
|
||||
. Fix memory leaks when returning refcounted value from curl callback.
|
||||
(nielsdos)
|
||||
|
||||
03 Jul 2025, PHP 8.3.23
|
||||
|
||||
- Core:
|
||||
|
||||
@@ -147,6 +147,9 @@ void _php_curl_multi_cleanup_list(void *data);
|
||||
void _php_curl_verify_handlers(php_curl *ch, bool reporterror);
|
||||
void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source);
|
||||
|
||||
/* Consumes `zv` */
|
||||
zend_long php_curl_get_long(zval *zv);
|
||||
|
||||
static inline php_curl *curl_from_obj(zend_object *obj) {
|
||||
return (php_curl *)((char *)(obj) - XtOffsetOf(php_curl, std));
|
||||
}
|
||||
|
||||
@@ -623,7 +623,7 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
|
||||
length = -1;
|
||||
} else if (!Z_ISUNDEF(retval)) {
|
||||
_php_curl_verify_handlers(ch, /* reporterror */ true);
|
||||
length = zval_get_long(&retval);
|
||||
length = php_curl_get_long(&retval);
|
||||
}
|
||||
|
||||
zval_ptr_dtor(&argv[0]);
|
||||
@@ -667,7 +667,7 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string)
|
||||
php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_FNMATCH_FUNCTION");
|
||||
} else if (!Z_ISUNDEF(retval)) {
|
||||
_php_curl_verify_handlers(ch, /* reporterror */ true);
|
||||
rval = zval_get_long(&retval);
|
||||
rval = php_curl_get_long(&retval);
|
||||
}
|
||||
zval_ptr_dtor(&argv[0]);
|
||||
zval_ptr_dtor(&argv[1]);
|
||||
@@ -715,7 +715,7 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double
|
||||
php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_PROGRESSFUNCTION");
|
||||
} else if (!Z_ISUNDEF(retval)) {
|
||||
_php_curl_verify_handlers(ch, /* reporterror */ true);
|
||||
if (0 != zval_get_long(&retval)) {
|
||||
if (0 != php_curl_get_long(&retval)) {
|
||||
rval = 1;
|
||||
}
|
||||
}
|
||||
@@ -764,7 +764,7 @@ static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
|
||||
php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_XFERINFOFUNCTION");
|
||||
} else if (!Z_ISUNDEF(retval)) {
|
||||
_php_curl_verify_handlers(ch, /* reporterror */ true);
|
||||
if (0 != zval_get_long(&retval)) {
|
||||
if (0 != php_curl_get_long(&retval)) {
|
||||
rval = 1;
|
||||
}
|
||||
}
|
||||
@@ -821,6 +821,7 @@ static int curl_ssh_hostkeyfunction(void *clientp, int keytype, const char *key,
|
||||
}
|
||||
} else {
|
||||
zend_throw_error(NULL, "The CURLOPT_SSH_HOSTKEYFUNCTION callback must return either CURLKHMATCH_OK or CURLKHMATCH_MISMATCH");
|
||||
zval_ptr_dtor(&retval);
|
||||
}
|
||||
}
|
||||
zval_ptr_dtor(&argv[0]);
|
||||
@@ -938,7 +939,7 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx
|
||||
length = -1;
|
||||
} else if (!Z_ISUNDEF(retval)) {
|
||||
_php_curl_verify_handlers(ch, /* reporterror */ true);
|
||||
length = zval_get_long(&retval);
|
||||
length = php_curl_get_long(&retval);
|
||||
}
|
||||
zval_ptr_dtor(&argv[0]);
|
||||
zval_ptr_dtor(&argv[1]);
|
||||
@@ -1290,6 +1291,17 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
|
||||
(*source->clone)++;
|
||||
}
|
||||
|
||||
zend_long php_curl_get_long(zval *zv)
|
||||
{
|
||||
if (EXPECTED(Z_TYPE_P(zv) == IS_LONG)) {
|
||||
return Z_LVAL_P(zv);
|
||||
} else {
|
||||
zend_long ret = zval_get_long(zv);
|
||||
zval_ptr_dtor(zv);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */
|
||||
static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */
|
||||
{
|
||||
|
||||
@@ -430,7 +430,7 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea
|
||||
if (error == FAILURE) {
|
||||
php_error_docref(NULL, E_WARNING, "Cannot call the CURLMOPT_PUSHFUNCTION");
|
||||
} else if (!Z_ISUNDEF(retval)) {
|
||||
if (CURL_PUSH_DENY != zval_get_long(&retval)) {
|
||||
if (CURL_PUSH_DENY != php_curl_get_long(&retval)) {
|
||||
rval = CURL_PUSH_OK;
|
||||
zend_llist_add_element(&mh->easyh, &pz_ch);
|
||||
} else {
|
||||
|
||||
27
ext/curl/tests/refcounted_return_must_not_leak.phpt
Normal file
27
ext/curl/tests/refcounted_return_must_not_leak.phpt
Normal file
@@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
Returning refcounted value from callback must not leak
|
||||
--EXTENSIONS--
|
||||
curl
|
||||
--FILE--
|
||||
<?php
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
|
||||
$url = "{$host}/get.inc";
|
||||
$ch = curl_init($url);
|
||||
|
||||
function return_non_interned_string() {
|
||||
return str_repeat('x', random_int(5, 5));
|
||||
}
|
||||
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'return_non_interned_string');
|
||||
curl_setopt($ch, CURLOPT_XFERINFOFUNCTION, 'return_non_interned_string');
|
||||
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'return_non_interned_string');
|
||||
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'return_non_interned_string');
|
||||
echo curl_exec($ch), PHP_EOL;
|
||||
echo "ok";
|
||||
?>
|
||||
--EXPECT--
|
||||
ok
|
||||
Reference in New Issue
Block a user