Skip to content

Commit 89be689

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix memory leaks when returning refcounted value from curl callback
2 parents 9859d83 + ca487ae commit 89be689

File tree

4 files changed

+48
-6
lines changed

4 files changed

+48
-6
lines changed

ext/curl/curl_private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ void _php_curl_multi_cleanup_list(void *data);
150150
void _php_curl_verify_handlers(php_curl *ch, bool reporterror);
151151
void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source);
152152

153+
/* Consumes `zv` */
154+
zend_long php_curl_get_long(zval *zv);
155+
153156
static inline php_curl *curl_from_obj(zend_object *obj) {
154157
return (php_curl *)((char *)(obj) - XtOffsetOf(php_curl, std));
155158
}

ext/curl/interface.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
624624
if (!Z_ISUNDEF(retval)) {
625625
_php_curl_verify_handlers(ch, /* reporterror */ true);
626626
/* TODO Check callback returns an int or something castable to int */
627-
length = zval_get_long(&retval);
627+
length = php_curl_get_long(&retval);
628628
}
629629

630630
zval_ptr_dtor(&argv[0]);
@@ -657,7 +657,7 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string)
657657
if (!Z_ISUNDEF(retval)) {
658658
_php_curl_verify_handlers(ch, /* reporterror */ true);
659659
/* TODO Check callback returns an int or something castable to int */
660-
rval = zval_get_long(&retval);
660+
rval = php_curl_get_long(&retval);
661661
}
662662
zval_ptr_dtor(&argv[0]);
663663
zval_ptr_dtor(&argv[1]);
@@ -694,7 +694,7 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double
694694
if (!Z_ISUNDEF(retval)) {
695695
_php_curl_verify_handlers(ch, /* reporterror */ true);
696696
/* TODO Check callback returns an int or something castable to int */
697-
if (0 != zval_get_long(&retval)) {
697+
if (0 != php_curl_get_long(&retval)) {
698698
rval = 1;
699699
}
700700
}
@@ -732,7 +732,7 @@ static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
732732
if (!Z_ISUNDEF(retval)) {
733733
_php_curl_verify_handlers(ch, /* reporterror */ true);
734734
/* TODO Check callback returns an int or something castable to int */
735-
if (0 != zval_get_long(&retval)) {
735+
if (0 != php_curl_get_long(&retval)) {
736736
rval = 1;
737737
}
738738
}
@@ -831,6 +831,7 @@ static int curl_ssh_hostkeyfunction(void *clientp, int keytype, const char *key,
831831
}
832832
} else {
833833
zend_throw_error(NULL, "The CURLOPT_SSH_HOSTKEYFUNCTION callback must return either CURLKHMATCH_OK or CURLKHMATCH_MISMATCH");
834+
zval_ptr_dtor(&retval);
834835
}
835836
}
836837

@@ -925,7 +926,7 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx
925926
if (!Z_ISUNDEF(retval)) {
926927
// TODO: Check for valid int type for return value
927928
_php_curl_verify_handlers(ch, /* reporterror */ true);
928-
length = zval_get_long(&retval);
929+
length = php_curl_get_long(&retval);
929930
}
930931
zval_ptr_dtor(&argv[0]);
931932
zval_ptr_dtor(&argv[1]);
@@ -1343,6 +1344,17 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
13431344
(*source->clone)++;
13441345
}
13451346

1347+
zend_long php_curl_get_long(zval *zv)
1348+
{
1349+
if (EXPECTED(Z_TYPE_P(zv) == IS_LONG)) {
1350+
return Z_LVAL_P(zv);
1351+
} else {
1352+
zend_long ret = zval_get_long(zv);
1353+
zval_ptr_dtor(zv);
1354+
return ret;
1355+
}
1356+
}
1357+
13461358
static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */
13471359
{
13481360
struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg;

ext/curl/multi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea
435435
zval_ptr_dtor_nogc(&headers);
436436

437437
if (!Z_ISUNDEF(retval)) {
438-
if (CURL_PUSH_DENY != zval_get_long(&retval)) {
438+
if (CURL_PUSH_DENY != php_curl_get_long(&retval)) {
439439
rval = CURL_PUSH_OK;
440440
zend_llist_add_element(&mh->easyh, &pz_ch);
441441
} else {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Returning refcounted value from callback must not leak
3+
--EXTENSIONS--
4+
curl
5+
--FILE--
6+
<?php
7+
include 'server.inc';
8+
$host = curl_cli_server_start();
9+
10+
$url = "{$host}/get.inc";
11+
$ch = curl_init($url);
12+
13+
function return_non_interned_string() {
14+
return str_repeat('x', random_int(5, 5));
15+
}
16+
17+
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
18+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
19+
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'return_non_interned_string');
20+
curl_setopt($ch, CURLOPT_XFERINFOFUNCTION, 'return_non_interned_string');
21+
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'return_non_interned_string');
22+
curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'return_non_interned_string');
23+
echo curl_exec($ch), PHP_EOL;
24+
echo "ok";
25+
?>
26+
--EXPECT--
27+
ok

0 commit comments

Comments
 (0)