Skip to content

Commit b10a3b9

Browse files
committed
Merge branch 'PHP-5.3' into PHP-5.4
* PHP-5.3: Fixed segfault due to libcurl connection caching
2 parents 5499c7d + a2b6d9c commit b10a3b9

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

ext/curl/interface.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,15 @@ PHP_MSHUTDOWN_FUNCTION(curl)
977977
}
978978
/* }}} */
979979

980+
/* {{{ curl_write_nothing
981+
* Used as a work around. See _php_curl_close_ex
982+
*/
983+
static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ctx)
984+
{
985+
return size * nmemb;
986+
}
987+
/* }}} */
988+
980989
/* {{{ curl_write
981990
*/
982991
static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
@@ -2648,6 +2657,21 @@ static void _php_curl_close_ex(php_curl *ch TSRMLS_DC)
26482657
#endif
26492658

26502659
_php_curl_verify_handlers(ch, 0 TSRMLS_CC);
2660+
2661+
/*
2662+
* Libcurl is doing connection caching. When easy handle is cleaned up,
2663+
* if the handle was previously used by the curl_multi_api, the connection
2664+
* remains open un the curl multi handle is cleaned up. Some protocols are
2665+
* sending content like the FTP one, and libcurl try to use the
2666+
* WRITEFUNCTION or the HEADERFUNCTION. Since structures used in those
2667+
* callback are freed, we need to use an other callback to which avoid
2668+
* segfaults.
2669+
*
2670+
* Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2
2671+
*/
2672+
curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing);
2673+
curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing);
2674+
26512675
curl_easy_cleanup(ch->cp);
26522676

26532677
/* cURL destructors should be invoked only by last curl handle */
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
Segfault due to libcurl connection caching
3+
--CREDITS--
4+
--SKIPIF--
5+
<?php
6+
if (!extension_loaded("curl")) exit("skip curl extension not loaded");
7+
if (false === getenv('PHP_CURL_FTP_REMOTE_SERVER')) exit("skip PHP_CURL_FTP_REMOTE_SERVER env variable is not defined");
8+
if (false === getenv('PHP_CURL_FTP_REMOTE_USER')) exit("skip PHP_CURL_FTP_REMOTE_USER env variable is not defined");
9+
if (false === getenv('PHP_CURL_FTP_REMOTE_PASSWD')) exit("skip PHP_CURL_FTP_REMOTE_PASSWD env variable is not defined");
10+
?>
11+
--FILE--
12+
<?php
13+
$host = getenv('PHP_CURL_FTP_REMOTE_SERVER');
14+
$username = getenv('PHP_CURL_FTP_REMOTE_USER');
15+
$password = getenv('PHP_CURL_FTP_REMOTE_PASSWD');
16+
17+
// FTP this script to a server
18+
$fp = fopen ( __FILE__ , "r" );
19+
$url = "ftp://$username:$password@$host/" ;
20+
21+
$ch = curl_init ();
22+
23+
curl_setopt ( $ch , CURLOPT_URL, $url );
24+
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER, 1 );
25+
26+
//force passive connection
27+
curl_setopt ( $ch , CURLOPT_FTP_USE_EPSV, 0 );
28+
curl_setopt ( $ch , CURLOPT_FTP_SKIP_PASV_IP, 1 );
29+
30+
$cmh = curl_multi_init();
31+
curl_multi_add_handle($cmh, $ch);
32+
33+
$active = null;
34+
35+
do {
36+
$mrc = curl_multi_exec($cmh, $active);
37+
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
38+
39+
40+
while ($active && $mrc == CURLM_OK) {
41+
if (curl_multi_select($cmh) != -1) {
42+
do {
43+
$mrc = curl_multi_exec($cmh, $active);
44+
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
45+
}
46+
}
47+
48+
var_dump(is_string(curl_multi_getcontent($ch)));
49+
curl_multi_remove_handle($cmh, $ch);
50+
curl_close($ch);
51+
curl_multi_close($cmh);
52+
?>
53+
===DONE===
54+
--EXPECTF--
55+
bool(true)
56+
===DONE===

0 commit comments

Comments
 (0)