Skip to content

Commit 40e6672

Browse files
committed
Fix GH-18597: Heap-buffer-overflow in zend_alloc.c when assigning string with UTF-8 bytes
xmlSave() also can flush in some cases. When the encoding is not available this can fail for short inputs, resulting in an empty string which is interned but then wrongly tagged by RETURN_NEW_STR. Fix this by checking the error condition and switching to RETURN_STR for defense-in-depth. This issue also exists on 8.3, but does not crash; however, due to the different API usage internally I cannot easily fix it on 8.3. There it gives a partial output. Closes GH-18606.
1 parent 3e0a425 commit 40e6672

File tree

6 files changed

+26
-5
lines changed

6 files changed

+26
-5
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.4.9
44

5+
- SimpleXML:
6+
. Fixed bug GH-18597 (Heap-buffer-overflow in zend_alloc.c when assigning
7+
string with UTF-8 bytes). (nielsdos)
58

69
06 Jun 2025, PHP 8.4.8
710

ext/dom/inner_html_mixin.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ zend_result dom_element_inner_html_read(dom_object *obj, zval *retval)
9898
status |= xmlOutputBufferFlush(out);
9999
status |= xmlOutputBufferClose(out);
100100
}
101-
(void) xmlSaveClose(ctxt);
101+
status |= xmlSaveClose(ctxt);
102102
xmlCharEncCloseFunc(handler);
103103
}
104104
if (UNEXPECTED(status < 0)) {

ext/dom/xml_document.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ static zend_string *php_new_dom_dump_node_to_str_ex(xmlNodePtr node, int options
282282
} else {
283283
xmlCharEncCloseFunc(handler);
284284
}
285-
(void) xmlSaveClose(ctxt);
285+
status |= xmlSaveClose(ctxt);
286286
}
287287

288288
if (UNEXPECTED(status < 0)) {
@@ -319,7 +319,7 @@ zend_long php_new_dom_dump_node_to_file(const char *filename, xmlDocPtr doc, xml
319319
if (EXPECTED(ctxt != NULL)) {
320320
status = dom_xml_serialize(ctxt, out, node, format, false, get_private_data_from_node(node));
321321
status |= xmlOutputBufferFlush(out);
322-
(void) xmlSaveClose(ctxt);
322+
status |= xmlSaveClose(ctxt);
323323
}
324324

325325
size_t offset = php_stream_tell(stream);

ext/libxml/libxml.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1519,7 +1519,7 @@ static zend_string *php_libxml_default_dump_doc_to_str(xmlDocPtr doc, int option
15191519
}
15201520

15211521
long status = xmlSaveDoc(ctxt, doc);
1522-
(void) xmlSaveClose(ctxt);
1522+
status |= xmlSaveClose(ctxt);
15231523
if (status < 0) {
15241524
smart_str_free_ex(&str, false);
15251525
return NULL;

ext/simplexml/simplexml.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1404,7 +1404,8 @@ PHP_METHOD(SimpleXMLElement, asXML)
14041404
if (!result) {
14051405
RETURN_FALSE;
14061406
} else {
1407-
RETURN_NEW_STR(result);
1407+
/* Defense-in-depth: don't use the NEW variant in case somehow an empty string gets returned */
1408+
RETURN_STR(result);
14081409
}
14091410
}
14101411
/* }}} */

ext/simplexml/tests/gh18597.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
GH-18597 (Heap-buffer-overflow in zend_alloc.c when assigning string with UTF-8 bytes)
3+
--EXTENSIONS--
4+
simplexml
5+
--FILE--
6+
<?php
7+
$sx1 = new SimpleXMLElement("<root />");
8+
$sx1->node[0] = 'node1';
9+
$node = $sx1->node[0];
10+
11+
$node[0] = '��c';
12+
13+
$sx1->asXML(); // Depends on the available system encodings whether this fails or not, point is, it should not crash
14+
echo "Done\n";
15+
?>
16+
--EXPECT--
17+
Done

0 commit comments

Comments
 (0)