]> granicus.if.org Git - php/commitdiff
Retain reference to share handle from curl handle
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 11 Nov 2020 10:51:20 +0000 (11:51 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 11 Nov 2020 10:56:03 +0000 (11:56 +0100)
Not keeping a reference will not result in use after free, because
curl protects against it, but it will result in a memory leak,
because curl_share_cleanup() will fail. We should make sure that
the share handle object stays alive as long as the curl handles
use it.

ext/curl/curl_private.h
ext/curl/interface.c
ext/curl/tests/curl_share_basic.phpt [new file with mode: 0644]

index 8ff0aef605c8e41f3443c0ecdffa3ef307450bc6..6ed2eba3c3080a3c49b0441a7ec4da7300832b04 100644 (file)
@@ -104,6 +104,8 @@ typedef struct {
        zend_bool                     in_callback;
        uint32_t*                     clone;
        zval                          postfields;
+       /* CurlShareHandle object set using CURLOPT_SHARE. */
+       struct _php_curlsh *share;
        zend_object                   std;
 } php_curl;
 
@@ -124,7 +126,7 @@ typedef struct {
        zend_object std;
 } php_curlm;
 
-typedef struct {
+typedef struct _php_curlsh {
        CURLSH                   *share;
        struct {
                int no;
index 8ff3e0f37471f713dc764700cb1283fc81821698..f01f6f775a22a11e435ddb0b7958c0dedc470257 100644 (file)
@@ -2832,6 +2832,12 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool i
                                if (Z_TYPE_P(zvalue) == IS_OBJECT && Z_OBJCE_P(zvalue) == curl_share_ce) {
                                        php_curlsh *sh = Z_CURL_SHARE_P(zvalue);
                                        curl_easy_setopt(ch->cp, CURLOPT_SHARE, sh->share);
+
+                                       if (ch->share) {
+                                               OBJ_RELEASE(&ch->share->std);
+                                       }
+                                       GC_ADDREF(&sh->std);
+                                       ch->share = sh;
                                }
                        }
                        break;
@@ -3373,6 +3379,10 @@ static void curl_free_obj(zend_object *object)
        efree(ch->handlers);
        zval_ptr_dtor(&ch->postfields);
 
+       if (ch->share) {
+               OBJ_RELEASE(&ch->share->std);
+       }
+
        zend_object_std_dtor(&ch->std);
 }
 /* }}} */
diff --git a/ext/curl/tests/curl_share_basic.phpt b/ext/curl/tests/curl_share_basic.phpt
new file mode 100644 (file)
index 0000000..2a37fce
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+Basic curl_share test
+--FILE--
+<?php
+
+$sh = curl_share_init();
+
+$ch1 = curl_init();
+curl_setopt($ch1, CURLOPT_URL, 'file://' . __DIR__ . '/curl_testdata1.txt');
+curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch1, CURLOPT_SHARE, $sh);
+
+$ch2 = curl_init();
+curl_setopt($ch2, CURLOPT_URL, 'file://' . __DIR__ . '/curl_testdata2.txt');
+curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch2, CURLOPT_SHARE, $sh);
+
+// Make sure nothing bad handles if the share handle is unset early.
+unset($sh);
+
+var_dump(curl_exec($ch1));
+var_dump(curl_exec($ch2));
+
+?>
+--EXPECT--
+string(6) "CURL1
+"
+string(6) "CURL2
+"