Skip to content

Commit 12e4628

Browse files
committed
Merge branch 'PHP-8.2'
* PHP-8.2: Fix phpGH-11455: Segmentation fault with custom object date properties Revert "Fix phpGH-11404: DOMDocument::savexml and friends ommit xmlns="" declaration for null namespace, creating incorrect xml representation of the DOM"
2 parents 798c40a + 93becab commit 12e4628

File tree

8 files changed

+52
-215
lines changed

8 files changed

+52
-215
lines changed

ext/date/php_date.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -2333,7 +2333,9 @@ static void add_common_properties(HashTable *myht, zend_object *zobj)
23332333
common = zend_std_get_properties(zobj);
23342334

23352335
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL_IND(common, name, prop) {
2336-
zend_hash_add(myht, name, prop);
2336+
if (zend_hash_add(myht, name, prop) != NULL) {
2337+
Z_TRY_ADDREF_P(prop);
2338+
}
23372339
} ZEND_HASH_FOREACH_END();
23382340
}
23392341

ext/date/tests/gh11455.phpt

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
Bug GH-11455 (PHP 8.2 Segmentation fault on nesbot/carbon)
3+
--FILE--
4+
<?php
5+
class MyDateTimeImmutable extends DateTimeImmutable {
6+
public function __construct(
7+
string $datetime = "now",
8+
?DateTimeZone $timezone = null,
9+
public ?stdClass $myProperty = null,
10+
) {
11+
parent::__construct($datetime, $timezone);
12+
}
13+
}
14+
15+
$datetime = new MyDateTimeImmutable('2022-12-22T11:26:00Z', myProperty: new stdClass);
16+
$datetime->myProperty->field = str_repeat("hello", 3);
17+
$serialized = serialize($datetime);
18+
var_dump($datetime->myProperty);
19+
$unserialized = unserialize($serialized);
20+
var_dump($unserialized);
21+
?>
22+
--EXPECT--
23+
object(stdClass)#2 (1) {
24+
["field"]=>
25+
string(15) "hellohellohello"
26+
}
27+
object(MyDateTimeImmutable)#3 (4) {
28+
["myProperty"]=>
29+
object(stdClass)#4 (1) {
30+
["field"]=>
31+
string(15) "hellohellohello"
32+
}
33+
["date"]=>
34+
string(26) "2022-12-22 11:26:00.000000"
35+
["timezone_type"]=>
36+
int(2)
37+
["timezone"]=>
38+
string(1) "Z"
39+
}

ext/dom/document.c

-4
Original file line numberDiff line numberDiff line change
@@ -877,10 +877,6 @@ PHP_METHOD(DOMDocument, createElementNS)
877877

878878
if (errorcode == 0) {
879879
if (xmlValidateName((xmlChar *) localname, 0) == 0) {
880-
/* https://dom.spec.whatwg.org/#validate-and-extract: demands us to set an empty string uri to NULL */
881-
if (uri_len == 0) {
882-
uri = NULL;
883-
}
884880
nodep = xmlNewDocNode(docp, NULL, (xmlChar *) localname, (xmlChar *) value);
885881
if (nodep != NULL && uri != NULL) {
886882
xmlNsPtr nsptr = xmlSearchNsByHref(nodep->doc, nodep, (xmlChar *) uri);

ext/dom/element.c

-4
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ PHP_METHOD(DOMElement, __construct)
5656
if (uri_len > 0) {
5757
errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
5858
if (errorcode == 0) {
59-
/* https://dom.spec.whatwg.org/#validate-and-extract: demands us to set an empty string uri to NULL */
60-
if (uri_len == 0) {
61-
uri = NULL;
62-
}
6359
nodep = xmlNewNode (NULL, (xmlChar *)localname);
6460
if (nodep != NULL && uri != NULL) {
6561
nsptr = dom_get_ns(nodep, uri, &errorcode, prefix);

ext/dom/node.c

+9-7
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ Since: DOM Level 2
532532
int dom_node_namespace_uri_read(dom_object *obj, zval *retval)
533533
{
534534
xmlNode *nodep = dom_object_get_node(obj);
535+
char *str = NULL;
535536

536537
if (nodep == NULL) {
537538
php_dom_throw_error(INVALID_STATE_ERR, 1);
@@ -543,19 +544,20 @@ int dom_node_namespace_uri_read(dom_object *obj, zval *retval)
543544
case XML_ATTRIBUTE_NODE:
544545
case XML_NAMESPACE_DECL:
545546
if (nodep->ns != NULL) {
546-
char *str = (char *) nodep->ns->href;
547-
/* https://dom.spec.whatwg.org/#concept-attribute: namespaceUri is "null or a non-empty string" */
548-
if (str != NULL && str[0] != '\0') {
549-
ZVAL_STRING(retval, str);
550-
return SUCCESS;
551-
}
547+
str = (char *) nodep->ns->href;
552548
}
553549
break;
554550
default:
551+
str = NULL;
555552
break;
556553
}
557554

558-
ZVAL_NULL(retval);
555+
if (str != NULL) {
556+
ZVAL_STRING(retval, str);
557+
} else {
558+
ZVAL_NULL(retval);
559+
}
560+
559561
return SUCCESS;
560562
}
561563

ext/dom/php_dom.c

-38
Original file line numberDiff line numberDiff line change
@@ -1497,33 +1497,13 @@ static void dom_libxml_reconcile_ensure_namespaces_are_declared(xmlNodePtr nodep
14971497
xmlDOMWrapReconcileNamespaces(&dummy_ctxt, nodep, /* options */ 0);
14981498
}
14991499

1500-
static bool dom_must_replace_namespace_by_empty_default(xmlDocPtr doc, xmlNodePtr nodep)
1501-
{
1502-
xmlNsPtr default_ns = xmlSearchNs(doc, nodep->parent, NULL);
1503-
return default_ns != NULL && default_ns->href != NULL && default_ns->href[0] != '\0';
1504-
}
1505-
1506-
static void dom_replace_namespace_by_empty_default(xmlDocPtr doc, xmlNodePtr nodep)
1507-
{
1508-
ZEND_ASSERT(nodep->ns == NULL);
1509-
/* The node uses the default empty namespace, but the current default namespace is non-empty.
1510-
* We can't unconditionally do this because otherwise libxml2 creates an xmlns="" declaration.
1511-
* Note: there's no point searching the oldNs list, because we haven't found it in the tree anyway.
1512-
* Ideally this would be pre-allocated but unfortunately libxml2 doesn't offer such a functionality. */
1513-
xmlSetNs(nodep, xmlNewNs(nodep, (const xmlChar *) "", NULL));
1514-
}
1515-
15161500
void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep) /* {{{ */
15171501
{
15181502
/* Although the node type will be checked by the libxml2 API,
15191503
* we still want to do the internal reconciliation conditionally. */
15201504
if (nodep->type == XML_ELEMENT_NODE) {
15211505
dom_reconcile_ns_internal(doc, nodep, nodep->parent);
15221506
dom_libxml_reconcile_ensure_namespaces_are_declared(nodep);
1523-
/* Check nodep->ns first to avoid an expensive lookup. */
1524-
if (nodep->ns == NULL && dom_must_replace_namespace_by_empty_default(doc, nodep)) {
1525-
dom_replace_namespace_by_empty_default(doc, nodep);
1526-
}
15271507
}
15281508
}
15291509
/* }}} */
@@ -1547,30 +1527,12 @@ static void dom_reconcile_ns_list_internal(xmlDocPtr doc, xmlNodePtr nodep, xmlN
15471527

15481528
void dom_reconcile_ns_list(xmlDocPtr doc, xmlNodePtr nodep, xmlNodePtr last)
15491529
{
1550-
bool did_compute_must_replace_namespace_by_empty_default = false;
1551-
bool must_replace_namespace_by_empty_default = false;
1552-
15531530
dom_reconcile_ns_list_internal(doc, nodep, last, nodep->parent);
1554-
15551531
/* The loop is outside of the recursion in the above call because
15561532
* dom_libxml_reconcile_ensure_namespaces_are_declared() performs its own recursion. */
15571533
while (true) {
15581534
/* The internal libxml2 call will already check the node type, no need for us to do it here. */
15591535
dom_libxml_reconcile_ensure_namespaces_are_declared(nodep);
1560-
1561-
/* We don't have to handle the children, because if their ns's are NULL they'll just take on the default
1562-
* which should've been reconciled before. */
1563-
if (nodep->ns == NULL) {
1564-
/* This is an optimistic approach: we assume that most of the time we don't need the result of the computation. */
1565-
if (!did_compute_must_replace_namespace_by_empty_default) {
1566-
did_compute_must_replace_namespace_by_empty_default = true;
1567-
must_replace_namespace_by_empty_default = dom_must_replace_namespace_by_empty_default(doc, nodep);
1568-
}
1569-
if (must_replace_namespace_by_empty_default) {
1570-
dom_replace_namespace_by_empty_default(doc, nodep);
1571-
}
1572-
}
1573-
15741536
if (nodep == last) {
15751537
break;
15761538
}

ext/dom/tests/bug47530.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ test_appendChild_with_shadowing();
121121
<html xmlns="https://php.net/something" xmlns:ns="https://php.net/whatever"><element ns:foo="https://php.net/bar"/></html>
122122
-- Test document fragment without import --
123123
<?xml version="1.0"?>
124-
<html xmlns=""><element xmlns:foo="https://php.net/bar"><foo:bar/><bar/></element></html>
124+
<html xmlns=""><element xmlns:foo="https://php.net/bar"><foo:bar/><bar xmlns=""/></element></html>
125125
string(7) "foo:bar"
126126
string(19) "https://php.net/bar"
127127
-- Test document import --

ext/dom/tests/gh11404.phpt

-160
This file was deleted.

0 commit comments

Comments
 (0)