summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-11-11 11:51:20 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-11-11 11:56:03 +0100
commitb4a2a9662b4244837e348f58d398523361dbcc7f (patch)
tree8a8f6b15216c330efb2286a7d941182225cce745
parent11c4821ba968d2a39310851ab89d673c553b72f3 (diff)
downloadphp-git-b4a2a9662b4244837e348f58d398523361dbcc7f.tar.gz
Retain reference to share handle from curl handle
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.
-rw-r--r--ext/curl/curl_private.h4
-rw-r--r--ext/curl/interface.c10
-rw-r--r--ext/curl/tests/curl_share_basic.phpt29
3 files changed, 42 insertions, 1 deletions
diff --git a/ext/curl/curl_private.h b/ext/curl/curl_private.h
index 8ff0aef605..6ed2eba3c3 100644
--- a/ext/curl/curl_private.h
+++ b/ext/curl/curl_private.h
@@ -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;
diff --git a/ext/curl/interface.c b/ext/curl/interface.c
index 8ff3e0f374..f01f6f775a 100644
--- a/ext/curl/interface.c
+++ b/ext/curl/interface.c
@@ -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
index 0000000000..2a37fce16a
--- /dev/null
+++ b/ext/curl/tests/curl_share_basic.phpt
@@ -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
+"