]> granicus.if.org Git - php/commitdiff
- Fixed bug #48774 (SIGSEGVs when using curl_copy_handle()).
authorSriram Natarajan <srinatar@php.net>
Tue, 21 Jul 2009 20:32:32 +0000 (20:32 +0000)
committerSriram Natarajan <srinatar@php.net>
Tue, 21 Jul 2009 20:32:32 +0000 (20:32 +0000)
NEWS
ext/curl/interface.c
ext/curl/php_curl.h
ext/curl/tests/curl_copy_handle_basic_007.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index e7387d478853e33a44f6e831418353b4d6f5d875..60da3f5a1adeb6172ca90bf2036c5c940aaddeeb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -48,3 +48,4 @@ PHP                                                                        NEWS
 
 - Fixed bug #46647 (SplFileObject::fgetcsv segfaults). (Etienne)
 - Fixed bug #40325 (Vary: header missing in gzip output handlers). (Mike)
+- Fixed bug #48774 (SIGSEGVs when using curl_copy_handle()). (Sriram Natarajan)
index eef4db2a0e7a9f29f958b3e98f91d7f3ab2c9da8..220d5892e0bde484667ab88f675167657fbac3c6 100644 (file)
@@ -1334,6 +1334,7 @@ PHP_FUNCTION(curl_init)
 {
        php_curl        *ch;
        CURL            *cp;
+       zval            *clone;
        zstr            url = NULL_ZSTR;
        int             url_len = 0;
        zend_uchar      url_type = 0;
@@ -1368,6 +1369,9 @@ PHP_FUNCTION(curl_init)
 
        ch->uses = 0;
 
+       MAKE_STD_ZVAL(clone);
+       ch->clone = clone;
+
        curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS,        1);
        curl_easy_setopt(ch->cp, CURLOPT_VERBOSE,           0);
        curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER,       ch->err.str);
@@ -1467,6 +1471,10 @@ PHP_FUNCTION(curl_copy_handle)
        zend_llist_copy(&dupch->to_free.slist, &ch->to_free.slist);
        zend_llist_copy(&dupch->to_free.post, &ch->to_free.post);
 
+       /* Keep track of cloned copies to avoid invoking curl destructors for every clone */
+       Z_ADDREF_P(ch->clone);
+       dupch->clone = ch->clone;
+
        ZEND_REGISTER_RESOURCE(return_value, dupch, le_curl);
        dupch->id = Z_LVAL_P(return_value);
 }
@@ -2364,8 +2372,19 @@ static void _php_curl_close_ex(php_curl *ch TSRMLS_DC)
 #if LIBCURL_VERSION_NUM < 0x071101
        zend_llist_clean(&ch->to_free.str);
 #endif
-       zend_llist_clean(&ch->to_free.slist);
-       zend_llist_clean(&ch->to_free.post);
+
+       /* cURL destructors should be invoked only by last curl handle */
+       if (Z_REFCOUNT_P(ch->clone) <= 1) {
+               zend_llist_clean(&ch->to_free.slist);
+               zend_llist_clean(&ch->to_free.post);
+               zval_ptr_dtor(&ch->clone);
+       } else {
+               Z_DELREF_P(ch->clone);
+               ch->to_free.slist.dtor = NULL;
+               ch->to_free.post.dtor = NULL;
+               zend_llist_clean(&ch->to_free.slist);
+               zend_llist_clean(&ch->to_free.post);
+       }
 
        if (ch->handlers->write->buf.len > 0) {
                smart_str_free(&ch->handlers->write->buf);
index e85fa4df252146c87afb3669054d6b309068f9a3..3063d8b42df2dfb82ee682a343fd3deb72d14423 100644 (file)
@@ -139,6 +139,7 @@ typedef struct {
        long                     id;
        unsigned int             uses;
        zend_bool                in_callback;
+       zval                     *clone;
 } php_curl;
 
 typedef struct {
diff --git a/ext/curl/tests/curl_copy_handle_basic_007.phpt b/ext/curl/tests/curl_copy_handle_basic_007.phpt
new file mode 100644 (file)
index 0000000..5be9048
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+Test curl_copy_handle() with simple POST
+--SKIPIF--
+<?php if (!extension_loaded("curl") || false === getenv('PHP_CURL_HTTP_REMOTE_SERVER')) print "skip"; ?>
+--FILE--
+<?php
+  $host = getenv('PHP_CURL_HTTP_REMOTE_SERVER');
+
+  echo '*** Testing curl copy handle with simple POST using array as arguments ***' . "\n";
+
+  $url = "{$host}/get.php?test=getpost";
+  $ch = curl_init();
+
+  ob_start(); // start output buffering
+  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+  curl_setopt($ch, CURLOPT_POST, 1);
+  curl_setopt($ch, CURLOPT_POSTFIELDS, array("Hello" => "World", "Foo" => "Bar", "Person" => "John Doe"));
+  curl_setopt($ch, CURLOPT_URL, $url); //set the url we want to use
+  
+  $copy = curl_copy_handle($ch);
+  curl_close($ch);
+  $curl_content = curl_exec($copy);
+  curl_close($copy);
+
+  var_dump( $curl_content );
+?>
+===DONE===
+--EXPECTF--
+*** Testing curl copy handle with simple POST using array as arguments ***
+string(163) "array(1) {
+  ["test"]=>
+  string(7) "getpost"
+}
+array(3) {
+  ["Hello"]=>
+  string(5) "World"
+  ["Foo"]=>
+  string(3) "Bar"
+  ["Person"]=>
+  string(8) "John Doe"
+}
+"
+===DONE===