Skip to content

Commit 18f2f0a

Browse files
committed
Merge branch 'PHP-8.2'
* PHP-8.2: Fix phpGH-11433: Unable to set CURLOPT_ACCEPT_ENCODING to NULL Fix "invalid state error" with cloned namespace declarations Fix lifetime issue with getAttributeNodeNS()
2 parents 49fbbea + c160693 commit 18f2f0a

6 files changed

+179
-30
lines changed

ext/curl/interface.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1839,7 +1839,6 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
18391839
case CURLOPT_TLSAUTH_TYPE:
18401840
case CURLOPT_TLSAUTH_PASSWORD:
18411841
case CURLOPT_TLSAUTH_USERNAME:
1842-
case CURLOPT_ACCEPT_ENCODING:
18431842
case CURLOPT_TRANSFER_ENCODING:
18441843
case CURLOPT_DNS_SERVERS:
18451844
case CURLOPT_MAIL_AUTH:
@@ -1914,6 +1913,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
19141913
case CURLOPT_RANGE:
19151914
case CURLOPT_FTP_ACCOUNT:
19161915
case CURLOPT_RTSP_SESSION_ID:
1916+
case CURLOPT_ACCEPT_ENCODING:
19171917
#if LIBCURL_VERSION_NUM >= 0x072100 /* Available since 7.33.0 */
19181918
case CURLOPT_DNS_INTERFACE:
19191919
case CURLOPT_DNS_LOCAL_IP4:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
Test curl_setopt() with CURLOPT_ACCEPT_ENCODING
3+
--EXTENSIONS--
4+
curl
5+
--FILE--
6+
<?php
7+
8+
include 'server.inc';
9+
$host = curl_cli_server_start();
10+
11+
$ch = curl_init();
12+
13+
$url = "{$host}/get.inc?test=";
14+
curl_setopt($ch, CURLOPT_URL, $url);
15+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
16+
curl_setopt($ch, CURLOPT_ACCEPT_ENCODING, "gzip");
17+
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
18+
19+
// First execution, with gzip accept
20+
curl_exec($ch);
21+
echo curl_getinfo($ch, CURLINFO_HEADER_OUT);
22+
23+
// Second execution, with the encoding accept disabled
24+
curl_setopt($ch, CURLOPT_ACCEPT_ENCODING, NULL);
25+
curl_exec($ch);
26+
echo curl_getinfo($ch, CURLINFO_HEADER_OUT);
27+
28+
curl_close($ch);
29+
?>
30+
--EXPECTF--
31+
GET /get.inc?test= HTTP/1.1
32+
Host: %s
33+
Accept: */*
34+
Accept-Encoding: gzip
35+
36+
GET /get.inc?test= HTTP/1.1
37+
Host: %s
38+
Accept: */*

ext/dom/element.c

+4-16
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ Since: DOM Level 2
785785
PHP_METHOD(DOMElement, getAttributeNodeNS)
786786
{
787787
zval *id;
788-
xmlNodePtr elemp, fakeAttrp;
788+
xmlNodePtr elemp;
789789
xmlAttrPtr attrp;
790790
dom_object *intern;
791791
size_t uri_len, name_len;
@@ -806,21 +806,9 @@ PHP_METHOD(DOMElement, getAttributeNodeNS)
806806
xmlNsPtr nsptr;
807807
nsptr = dom_get_nsdecl(elemp, (xmlChar *)name);
808808
if (nsptr != NULL) {
809-
xmlNsPtr curns;
810-
curns = xmlNewNs(NULL, nsptr->href, NULL);
811-
if (nsptr->prefix) {
812-
curns->prefix = xmlStrdup((xmlChar *) nsptr->prefix);
813-
}
814-
if (nsptr->prefix) {
815-
fakeAttrp = xmlNewDocNode(elemp->doc, NULL, (xmlChar *) nsptr->prefix, nsptr->href);
816-
} else {
817-
fakeAttrp = xmlNewDocNode(elemp->doc, NULL, (xmlChar *)"xmlns", nsptr->href);
818-
}
819-
fakeAttrp->type = XML_NAMESPACE_DECL;
820-
fakeAttrp->parent = elemp;
821-
fakeAttrp->ns = curns;
822-
823-
DOM_RET_OBJ(fakeAttrp, &ret, intern);
809+
/* Keep parent alive, because we're a fake child. */
810+
GC_ADDREF(&intern->std);
811+
(void) php_dom_create_fake_namespace_decl(elemp, nsptr, return_value, intern);
824812
} else {
825813
RETURN_NULL();
826814
}

ext/dom/php_dom.c

+44-13
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ static HashTable dom_xpath_prop_handlers;
8989

9090
static zend_object *dom_objects_namespace_node_new(zend_class_entry *class_type);
9191
static void dom_object_namespace_node_free_storage(zend_object *object);
92+
static xmlNodePtr php_dom_create_fake_namespace_decl_node_ptr(xmlNodePtr nodep, xmlNsPtr original);
9293

9394
typedef int (*dom_read_t)(dom_object *obj, zval *retval);
9495
typedef int (*dom_write_t)(dom_object *obj, zval *newval);
@@ -480,6 +481,19 @@ PHP_FUNCTION(dom_import_simplexml)
480481

481482
static dom_object* dom_objects_set_class(zend_class_entry *class_type);
482483

484+
static void dom_update_refcount_after_clone(dom_object *original, xmlNodePtr original_node, dom_object *clone, xmlNodePtr cloned_node)
485+
{
486+
/* If we cloned a document then we must create new doc proxy */
487+
if (cloned_node->doc == original_node->doc) {
488+
clone->document = original->document;
489+
}
490+
php_libxml_increment_doc_ref((php_libxml_node_object *)clone, cloned_node->doc);
491+
php_libxml_increment_node_ptr((php_libxml_node_object *)clone, cloned_node, (void *)clone);
492+
if (original->document != clone->document) {
493+
dom_copy_doc_props(original->document, clone->document);
494+
}
495+
}
496+
483497
static zend_object *dom_objects_store_clone_obj(zend_object *zobject) /* {{{ */
484498
{
485499
dom_object *intern = php_dom_obj_from_obj(zobject);
@@ -492,15 +506,7 @@ static zend_object *dom_objects_store_clone_obj(zend_object *zobject) /* {{{ */
492506
if (node != NULL) {
493507
xmlNodePtr cloned_node = xmlDocCopyNode(node, node->doc, 1);
494508
if (cloned_node != NULL) {
495-
/* If we cloned a document then we must create new doc proxy */
496-
if (cloned_node->doc == node->doc) {
497-
clone->document = intern->document;
498-
}
499-
php_libxml_increment_doc_ref((php_libxml_node_object *)clone, cloned_node->doc);
500-
php_libxml_increment_node_ptr((php_libxml_node_object *)clone, cloned_node, (void *)clone);
501-
if (intern->document != clone->document) {
502-
dom_copy_doc_props(intern->document, clone->document);
503-
}
509+
dom_update_refcount_after_clone(intern, node, clone, cloned_node);
504510
}
505511

506512
}
@@ -512,6 +518,26 @@ static zend_object *dom_objects_store_clone_obj(zend_object *zobject) /* {{{ */
512518
}
513519
/* }}} */
514520

521+
static zend_object *dom_object_namespace_node_clone_obj(zend_object *zobject)
522+
{
523+
dom_object_namespace_node *intern = php_dom_namespace_node_obj_from_obj(zobject);
524+
zend_object *clone = dom_objects_namespace_node_new(intern->dom.std.ce);
525+
dom_object_namespace_node *clone_intern = php_dom_namespace_node_obj_from_obj(clone);
526+
527+
xmlNodePtr original_node = dom_object_get_node(&intern->dom);
528+
ZEND_ASSERT(original_node->type == XML_NAMESPACE_DECL);
529+
xmlNodePtr cloned_node = php_dom_create_fake_namespace_decl_node_ptr(original_node->parent, original_node->ns);
530+
531+
if (intern->parent_intern) {
532+
clone_intern->parent_intern = intern->parent_intern;
533+
GC_ADDREF(&clone_intern->parent_intern->std);
534+
}
535+
dom_update_refcount_after_clone(&intern->dom, original_node, &clone_intern->dom, cloned_node);
536+
537+
zend_objects_clone_members(clone, &intern->dom.std);
538+
return clone;
539+
}
540+
515541
static void dom_copy_prop_handler(zval *zv) /* {{{ */
516542
{
517543
dom_prop_handler *hnd = Z_PTR_P(zv);
@@ -580,6 +606,7 @@ PHP_MINIT_FUNCTION(dom)
580606
memcpy(&dom_object_namespace_node_handlers, &dom_object_handlers, sizeof(zend_object_handlers));
581607
dom_object_namespace_node_handlers.offset = XtOffsetOf(dom_object_namespace_node, dom.std);
582608
dom_object_namespace_node_handlers.free_obj = dom_object_namespace_node_free_storage;
609+
dom_object_namespace_node_handlers.clone_obj = dom_object_namespace_node_clone_obj;
583610

584611
zend_hash_init(&classes, 0, NULL, NULL, 1);
585612

@@ -1608,8 +1635,7 @@ xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName) {
16081635
}
16091636
/* }}} end dom_get_nsdecl */
16101637

1611-
/* Note: Assumes the additional lifetime was already added in the caller. */
1612-
xmlNodePtr php_dom_create_fake_namespace_decl(xmlNodePtr nodep, xmlNsPtr original, zval *return_value, dom_object *parent_intern)
1638+
static xmlNodePtr php_dom_create_fake_namespace_decl_node_ptr(xmlNodePtr nodep, xmlNsPtr original)
16131639
{
16141640
xmlNodePtr attrp;
16151641
xmlNsPtr curns = xmlNewNs(NULL, original->href, NULL);
@@ -1622,11 +1648,16 @@ xmlNodePtr php_dom_create_fake_namespace_decl(xmlNodePtr nodep, xmlNsPtr origina
16221648
attrp->type = XML_NAMESPACE_DECL;
16231649
attrp->parent = nodep;
16241650
attrp->ns = curns;
1651+
return attrp;
1652+
}
16251653

1654+
/* Note: Assumes the additional lifetime was already added in the caller. */
1655+
xmlNodePtr php_dom_create_fake_namespace_decl(xmlNodePtr nodep, xmlNsPtr original, zval *return_value, dom_object *parent_intern)
1656+
{
1657+
xmlNodePtr attrp = php_dom_create_fake_namespace_decl_node_ptr(nodep, original);
16261658
php_dom_create_object(attrp, return_value, parent_intern);
16271659
/* This object must exist, because we just created an object for it via php_dom_create_object(). */
1628-
dom_object *obj = ((php_libxml_node_ptr *)attrp->_private)->_private;
1629-
php_dom_namespace_node_obj_from_obj(&obj->std)->parent_intern = parent_intern;
1660+
php_dom_namespace_node_obj_from_obj(Z_OBJ_P(return_value))->parent_intern = parent_intern;
16301661
return attrp;
16311662
}
16321663

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Lifetime issue with parentNode on getAttributeNodeNS()
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
$xmlString = '<?xml version="1.0" encoding="utf-8" ?>
8+
<root xmlns="http://ns" xmlns:ns2="http://ns2">
9+
<ns2:child />
10+
</root>';
11+
12+
$xml=new DOMDocument();
13+
$xml->loadXML($xmlString);
14+
$ns2 = $xml->documentElement->getAttributeNodeNS("http://www.w3.org/2000/xmlns/", "ns2");
15+
$ns2->parentNode->remove();
16+
var_dump($ns2->parentNode->localName);
17+
18+
?>
19+
--EXPECT--
20+
string(4) "root"

ext/dom/tests/clone_nodes.phpt

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
--TEST--
2+
Clone nodes
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
8+
echo "-- Clone DOMNameSpaceNode --\n";
9+
10+
$doc = new DOMDocument;
11+
$doc->loadXML('<foo xmlns="http://php.net/test" xmlns:foo="urn:foo" />');
12+
13+
$attr = $doc->documentElement->getAttributeNode('xmlns');
14+
var_dump($attr);
15+
16+
$attrClone = clone $attr;
17+
var_dump($attrClone->nodeValue);
18+
var_dump($attrClone->parentNode->nodeName);
19+
20+
unset($doc);
21+
unset($attr);
22+
23+
var_dump($attrClone->nodeValue);
24+
var_dump($attrClone->parentNode->nodeName);
25+
26+
echo "-- Clone DOMNode --\n";
27+
28+
$doc = new DOMDocument;
29+
$doc->loadXML('<foo><bar/></foo>');
30+
31+
$bar = $doc->documentElement->firstChild;
32+
$barClone = clone $bar;
33+
$bar->remove();
34+
unset($bar);
35+
36+
var_dump($barClone->nodeName);
37+
38+
$doc->firstElementChild->remove();
39+
unset($doc);
40+
41+
var_dump($barClone->nodeName);
42+
var_dump($barClone->parentNode);
43+
44+
?>
45+
--EXPECT--
46+
-- Clone DOMNameSpaceNode --
47+
object(DOMNameSpaceNode)#3 (8) {
48+
["nodeName"]=>
49+
string(5) "xmlns"
50+
["nodeValue"]=>
51+
string(19) "http://php.net/test"
52+
["nodeType"]=>
53+
int(18)
54+
["prefix"]=>
55+
string(0) ""
56+
["localName"]=>
57+
string(5) "xmlns"
58+
["namespaceURI"]=>
59+
string(19) "http://php.net/test"
60+
["ownerDocument"]=>
61+
string(22) "(object value omitted)"
62+
["parentNode"]=>
63+
string(22) "(object value omitted)"
64+
}
65+
string(19) "http://php.net/test"
66+
string(3) "foo"
67+
string(19) "http://php.net/test"
68+
string(3) "foo"
69+
-- Clone DOMNode --
70+
string(3) "bar"
71+
string(3) "bar"
72+
NULL

0 commit comments

Comments
 (0)