Commit d5a57af4e26 for php.net
commit d5a57af4e26db810875eb9ea8f00be5c3cda9635
Author: David Carlier <devnexen@gmail.com>
Date: Fri May 15 18:26:17 2026 +0100
ext/xml: Use zend_string_safe_realloc() for cdata concatenation.
The previous code computed `Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value)`
as a plain `size_t` addition before passing the result to
zend_string_extend(), which can wrap on 32-bit and lead to a heap
overflow in the following strncpy(). Switch to zend_string_safe_realloc()
so the size computation is bounds-checked.
close GH-22056
diff --git a/ext/xml/xml.c b/ext/xml/xml.c
index 8394bbf3cb3..5b098f5d91b 100644
--- a/ext/xml/xml.c
+++ b/ext/xml/xml.c
@@ -828,16 +828,15 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len)
zval *myval;
/* check if the current tag already has a value - if yes append to that! */
if ((myval = zend_hash_find(Z_ARRVAL_P(ctag), ZSTR_KNOWN(ZEND_STR_VALUE))) && Z_TYPE_P(myval) == IS_STRING) {
- size_t newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value);
- Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0);
+ Z_STR_P(myval) = zend_string_safe_realloc(Z_STR_P(myval), 1, Z_STRLEN_P(myval), ZSTR_LEN(decoded_value), false);
strncpy(Z_STRVAL_P(myval) + Z_STRLEN_P(myval) - ZSTR_LEN(decoded_value),
ZSTR_VAL(decoded_value), ZSTR_LEN(decoded_value) + 1);
- zend_string_release_ex(decoded_value, 0);
+ zend_string_release_ex(decoded_value, false);
} else {
if (doprint || (! parser->skipwhite)) {
add_assoc_str(ctag, "value", decoded_value);
} else {
- zend_string_release_ex(decoded_value, 0);
+ zend_string_release_ex(decoded_value, false);
}
}
} else {
@@ -855,11 +854,10 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len)
if (EXPECTED(Z_TYPE_P(mytype) == IS_STRING) && zend_string_equals_literal(Z_STR_P(mytype), "cdata")) {
SEPARATE_ARRAY(curtag);
if ((myval = zend_hash_find(Z_ARRVAL_P(curtag), ZSTR_KNOWN(ZEND_STR_VALUE)))) {
- size_t newlen = Z_STRLEN_P(myval) + ZSTR_LEN(decoded_value);
- Z_STR_P(myval) = zend_string_extend(Z_STR_P(myval), newlen, 0);
+ Z_STR_P(myval) = zend_string_safe_realloc(Z_STR_P(myval), 1, Z_STRLEN_P(myval), ZSTR_LEN(decoded_value), false);
strncpy(Z_STRVAL_P(myval) + Z_STRLEN_P(myval) - ZSTR_LEN(decoded_value),
ZSTR_VAL(decoded_value), ZSTR_LEN(decoded_value) + 1);
- zend_string_release_ex(decoded_value, 0);
+ zend_string_release_ex(decoded_value, false);
return;
}
}
@@ -877,7 +875,7 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len)
} else if (parser->level == (XML_MAXLEVEL + 1)) {
php_error_docref(NULL, E_WARNING, "Maximum depth exceeded - Results truncated");
} else {
- zend_string_release_ex(decoded_value, 0);
+ zend_string_release_ex(decoded_value, false);
}
}
}