Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7300fa5
ext/sqlite3: reject close() from inside a callback
iliaal Aug 24, 2026
0b0784a
Merge branch 'PHP-8.4' into PHP-8.5
iliaal Sep 16, 2026
92b0894
dom: fix attribute namespaces from foreign content in the HTML parser
iliaal Sep 6, 2026
d84d188
Merge branch 'PHP-8.4' into PHP-8.5
iliaal Sep 16, 2026
2bca736
ext/sockets: socket_select() silent set truncation on Windows.
devnexen Sep 17, 2026
57b16fc
Merge branch 'PHP-8.4' into PHP-8.5
devnexen Sep 17, 2026
b55c619
ext/xsl: XSLTProcessor::importStylesheet() use-after-free during a tr…
devnexen Sep 17, 2026
db2d448
Merge branch 'PHP-8.4' into PHP-8.5
devnexen Sep 18, 2026
132403d
ext/zip: ZipArchive::close() use-after-free from a progress or cancel…
devnexen Sep 18, 2026
8ceef7f
Merge branch 'PHP-8.4' into PHP-8.5
devnexen Sep 18, 2026
a74f826
Fix GH-23729: DOMXPath::__construct() use-after-free during an evalua…
devnexen Sep 17, 2026
392d4a6
Merge branch 'PHP-8.4' into PHP-8.5
devnexen Sep 19, 2026
6d91020
Zend: reorganise some type declarations tests
Girgias Sep 19, 2026
8d38af6
Zend: fix OSS-Fuzz 532353396, static is a built-in type
Girgias Sep 19, 2026
4e64a26
Fix GH-22567 (Windows ZTS CLI SAPI should refresh its TSRMLS cache du…
matyhtf Jul 3, 2026
921c689
Merge branch 'PHP-8.4' into PHP-8.5
Girgias Sep 19, 2026
30920e9
Fix GH-23662: avoid NAN warning in print_r()
CodedByManish Sep 12, 2026
c2c01ae
Fix heap over-read in cli_get_prompt() for empty cli.prompt
iliaal Aug 21, 2026
6bad8fd
Merge branch 'PHP-8.4' into PHP-8.5
iliaal Sep 19, 2026
8d0d630
Fix three Win32-only defects in proc_open descriptor handling
iliaal Aug 21, 2026
6baec62
Merge branch 'PHP-8.4' into PHP-8.5
iliaal Sep 19, 2026
3213c3f
Fix OSS-Fuzz #546798343: Heap-buffer-overflow in zend_delete_call_ins…
ndossche Sep 19, 2026
c091db1
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Sep 19, 2026
fb76b3d
ext/zlib: honor preset dictionary for raw inflate with non-default wi…
iliaal Jun 21, 2026
9c2acc3
Fix GH-23693: JIT guard branches on stale flags across basic blocks
iliaal Sep 16, 2026
80444c5
Merge branch 'PHP-8.4' into PHP-8.5
iliaal Sep 20, 2026
1b4d9f1
ext/pdo: Report $options as the argument for constructor option errors
iliaal Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,22 @@ PHP NEWS
- Core:
. Fixed bug GH-23644 (Optimizer leaves a constant-vs-constant comparison
unfolded, crashing the VM in zval_undefined_cv). (ndossche)
. Fixed OSS-Fuzz 532353396 (assertion failure with static type). (Girgias)
. Fix GH-23662 (Avoid NAN warning in print_r()). (CodedByManish)

- CLI
. Fix GH-22567 (Windows ZTS CLI SAPI should refresh its TSRMLS cache during
request activation). (matyhtf)

- DOM:
. Fixed use-after-free when re-constructing a DOMXPath whose php:function
registrations are freed while still reachable from the cycle collector.
(Ilia Alshanetsky)
. Fixed Dom\HTMLDocument::getElementById() not finding ids of SVG and
MathML elements. (Ilia Alshanetsky)
. Fixed Dom\HTMLDocument giving attributes the namespace of their element
when a fragment is parsed with an xlink, xml or xmlns context element.
(Ilia Alshanetsky)

- Intl:
. Fixed cloning IntlDateFormatter and MessageFormatter losing PHP-side state
Expand All @@ -27,13 +38,38 @@ PHP NEWS
. Fixed bug GH-23106 (mb_strpos() reads past the end of a haystack ending in
a truncated UTF-8 sequence). (Lazizbek Ergashev)

- Opcache:
. Fixed OSS-Fuzz #546798343 (Heap-buffer-overflow in optimizer with
FCCs and inlining). (ndossche)
. Fixed bug GH-23693 (Tracing JIT produces wrong results for a guard on a
loop-invariant addition). (Ilia Alshanetsky)

- PDO:
. Fixed PDOStatement::getColumnMeta() reading out of bounds for an invalid
column index. (Ilia Alshanetsky)
. Fixed the argument reported in error messages when setting an invalid
attribute via the PDO constructor options array. (Ilia Alshanetsky)

- PGSQL:
. Fixed pg_lo_write() rejecting data containing null bytes. (Ilia Alshanetsky)

- Readline:
. Fixed a heap over-read in the interactive shell prompt when cli.prompt is
set to an empty string. (Ilia Alshanetsky)

- SQLite:
. Fixed a crash when SQLite3::close() is called from a userland callback.
(Ilia Alshanetsky)

- Standard:
. Fixed three Windows-only proc_open() defects: an uninitialized
PROCESS_INFORMATION, an indeterminate comspec pointer after a failed
lookup, and an unchecked CreateFileA() failure. (Ilia Alshanetsky)

- Zlib:
. Fixed inflate_init() dropping the preset dictionary for raw streams with
a non-default window. (Ilia Alshanetsky)


24 Sep 2026, PHP 8.5.11

Expand Down
1 change: 1 addition & 0 deletions Zend/Optimizer/optimize_func_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ static void zend_delete_call_instructions(zend_op_array *op_array, zend_op *opli
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
case ZEND_CALLABLE_CONVERT:
call++;
break;
case ZEND_SEND_VAL:
Expand Down
12 changes: 12 additions & 0 deletions Zend/tests/gh23662.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
GH-23662 (print_r() results in warning for NAN)
--FILE--
<?php
print_r(NAN);
print_r([NAN]);
?>
--EXPECT--
NANArray
(
[0] => NAN
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
Bug #43332.1 (self and parent as type hint in namespace)
Bug #43332.1 (self and parent as type declaration in namespace)
--FILE--
<?php
namespace foobar;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
Bug #43332.2 (self and parent as type hint in namespace)
Bug #43332.2 (self and parent as type declaration in namespace)
--FILE--
<?php
namespace foobar;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
Bug #60573 (type hinting with "self" keyword causes weird errors)
Bug #60573 (type declaration with "self" keyword causes weird errors)
--FILE--
<?php
class Foo1 {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
Bug #60573 (type hinting with "self" keyword causes weird errors) -- variation 2
Bug #60573 (type declaration with "self" keyword causes weird errors) -- variation 2
--FILE--
<?php
class Foo1 {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
Fully qualified (leading backslash) static type names must fail
--DESCRIPTION--
OSS-Fuzz: https://issues.oss-fuzz.com/issues/532353396
--FILE--
<?php

function test($i): \static {}

?>
--EXPECTF--
Fatal error: Type declaration 'static' must be unqualified in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
namespace\static is not a valid type declaration
--DESCRIPTION--
OSS-Fuzz: https://issues.oss-fuzz.com/issues/532353396
--FILE--
<?php

function test($i): namespace\static {}

?>
--EXPECTF--
Fatal error: Type declaration 'static' must be unqualified in %s on line %d
3 changes: 3 additions & 0 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,9 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /*
case IS_LONG:
smart_str_append_long(buf, Z_LVAL_P(expr));
break;
case IS_DOUBLE:
smart_str_append_double(buf, Z_DVAL_P(expr), EG(precision), false);
break;
case IS_REFERENCE:
zend_print_zval_r_to_buf(buf, Z_REFVAL_P(expr), indent);
break;
Expand Down
3 changes: 3 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ static const builtin_type_info builtin_types[] = {
{ZEND_STRL("iterable"), IS_ITERABLE},
{ZEND_STRL("object"), IS_OBJECT},
{ZEND_STRL("mixed"), IS_MIXED},
{ZEND_STRL("static"), IS_STATIC},
{NULL, 0, IS_UNDEF}
};

Expand Down Expand Up @@ -7100,6 +7101,8 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
ZSTR_VAL(zend_string_tolower(type_name)));
}

ZEND_ASSERT(type_code != IS_STATIC && "unqualified static type should have been handled by ZEND_AST_TYPE branch");

/* Transform iterable into a type union alias */
if (type_code == IS_ITERABLE) {
/* Set iterable bit for BC compat during Reflection and string representation of type */
Expand Down
8 changes: 4 additions & 4 deletions ext/dom/html5_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
lxml_attr->children = lxml_attr->last = lxml_text;
lxml_text->parent = (xmlNodePtr) lxml_attr;

if (attr->node.ns == LXB_NS_XMLNS) {
if (attr->node.ns == LXB_NS_XMLNS && (attr->node.prefix || strcmp((const char *) local_name, "xmlns") == 0)) {
if (strcmp((const char *) local_name, "xmlns") != 0) {
if (prefixed_xmlns_ns == NULL) {
prefixed_xmlns_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xmlns", DOM_XMLNS_NS_URI);
Expand All @@ -251,13 +251,13 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
lxml_attr->ns = php_dom_libxml_ns_mapper_ensure_prefixless_xmlns_ns(ns_mapper);
}
lxml_attr->ns->_private = (void *) php_dom_ns_is_xmlns_magic_token;
} else if (attr->node.ns == LXB_NS_XLINK) {
} else if (attr->node.prefix && attr->node.ns == LXB_NS_XLINK) {
if (xlink_ns == NULL) {
xlink_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xlink", DOM_XLINK_NS_URI);
xlink_ns->_private = (void *) php_dom_ns_is_xlink_magic_token;
}
lxml_attr->ns = xlink_ns;
} else if (attr->node.ns == LXB_NS_XML) {
} else if (attr->node.prefix && attr->node.ns == LXB_NS_XML) {
if (xml_ns == NULL) {
xml_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xml", DOM_XML_NS_URI);
xml_ns->_private = (void *) php_dom_ns_is_xml_magic_token;
Expand All @@ -274,7 +274,7 @@ static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
last_added_attr = lxml_attr;

/* xmlIsID does some other stuff too that is irrelevant here. */
if (local_name_length == 2 && local_name[0] == 'i' && local_name[1] == 'd' && attr->node.ns == LXB_NS_HTML) {
if (local_name_length == 2 && local_name[0] == 'i' && local_name[1] == 'd' && lxml_attr->ns == NULL) {
if (xmlAddID(NULL, lxml_doc, value, lxml_attr) == 0) {
/* If the ID already exists, the ID attribute still needs to be marked as an ID. */
lxml_attr->atype = XML_ATTRIBUTE_ID;
Expand Down
1 change: 1 addition & 0 deletions ext/dom/php_dom.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ extern zend_module_entry dom_module_entry;

typedef struct dom_xpath_object {
php_dom_xpath_callbacks xpath_callbacks;
uint32_t evaluation_depth;
bool register_node_ns;
dom_object dom;
} dom_xpath_object;
Expand Down
73 changes: 73 additions & 0 deletions ext/dom/tests/gh23729.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
--TEST--
GH-23729 (Use-after-free when DOMXPath is reconstructed during an evaluation)
--CREDITS--
djarfluka
--EXTENSIONS--
dom
--FILE--
<?php

function reconstruct() {
try {
$GLOBALS['xpath']->__construct($GLOBALS['other']);
} catch (Error $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
return 'r';
}

function nested() {
echo 'nested: ', $GLOBALS['xpath']->evaluate('string(/root/b)'), PHP_EOL;
return 'n';
}

function test(string $class, object $doc, object $other) {
$xpath = new $class($doc);
$xpath->registerNamespace('php', 'http://php.net/xpath');
$xpath->registerPhpFunctions();

$GLOBALS['xpath'] = $xpath;
$GLOBALS['other'] = $other;

var_dump($xpath->evaluate('string(php:function("reconstruct"))'));
/* The evaluation the callback tried to destroy must still be usable. */
var_dump($xpath->evaluate('string(/root/a)'));
/* A nested evaluation must not lift the guard of the outer one. */
var_dump($xpath->evaluate('concat(php:function("nested"), php:function("reconstruct"))'));
var_dump($xpath->query('//b[php:function("reconstruct")]')->length);

/* Reconstructing outside of an evaluation is still allowed. */
$xpath->__construct($other);
var_dump($xpath->document->documentElement->nodeName);
}

$doc = new DOMDocument();
$doc->loadXML('<root><a>1</a><b>2</b></root>');
$other = new DOMDocument();
$other->loadXML('<other/>');
test(DOMXPath::class, $doc, $other);

$doc = Dom\XMLDocument::createFromString('<root><a>1</a><b>2</b></root>');
$other = Dom\XMLDocument::createFromString('<other/>');
test(Dom\XPath::class, $doc, $other);

?>
--EXPECT--
Error: Cannot call DOMXPath::__construct() while an XPath evaluation is in progress
string(1) "r"
string(1) "1"
nested: 2
Error: Cannot call DOMXPath::__construct() while an XPath evaluation is in progress
string(2) "nr"
Error: Cannot call DOMXPath::__construct() while an XPath evaluation is in progress
int(1)
string(5) "other"
Error: Cannot call Dom\XPath::__construct() while an XPath evaluation is in progress
string(1) "r"
string(1) "1"
nested: 2
Error: Cannot call Dom\XPath::__construct() while an XPath evaluation is in progress
string(2) "nr"
Error: Cannot call Dom\XPath::__construct() while an XPath evaluation is in progress
int(1)
string(5) "other"
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
--TEST--
Unprefixed attributes in foreign content are in no namespace
--EXTENSIONS--
dom
--FILE--
<?php
$html = '<!DOCTYPE html><html><body><svg id="s" xlink:href="#a" xml:lang="en" xmlns:xlink="urn:x"><rect xml:id="r"/></svg><math id="m"></math><p id="p"></p></body></html>';
$doc = Dom\HTMLDocument::createFromString($html, LIBXML_NOERROR);

var_dump([
'svg #s' => $doc->getElementById('s')?->tagName,
'math #m' => $doc->getElementById('m')?->tagName,
'html #p' => $doc->getElementById('p')?->tagName,
'xml:id #r' => $doc->getElementById('r')?->tagName,
]);

foreach ($doc->getElementById('s')->attributes as $attr) {
echo $attr->name, ' => ', var_export($attr->namespaceURI, true), "\n";
}

$contexts = [
'http://www.w3.org/1999/xlink' => 'z',
'http://www.w3.org/XML/1998/namespace' => 'z',
'http://www.w3.org/2000/xmlns/' => 'xmlns',
];
foreach ($contexts as $uri => $name) {
$fragment_doc = Dom\HTMLDocument::createEmpty();
$context = $fragment_doc->createElementNS($uri, $name);
$fragment_doc->appendChild($context);
$context->innerHTML = '<z id="q" xlink:href="#a"></z>';

echo $uri, "\n ", $context->innerHTML, "\n ";
var_dump($fragment_doc->getElementById('q')?->tagName);
}
?>
--EXPECT--
array(4) {
["svg #s"]=>
string(3) "svg"
["math #m"]=>
string(4) "math"
["html #p"]=>
string(1) "P"
["xml:id #r"]=>
NULL
}
id => NULL
xlink:href => 'http://www.w3.org/1999/xlink'
xml:lang => 'http://www.w3.org/XML/1998/namespace'
xmlns:xlink => 'http://www.w3.org/2000/xmlns/'
http://www.w3.org/1999/xlink
<z id="q" xlink:href="#a"></z>
string(1) "Z"
http://www.w3.org/XML/1998/namespace
<z id="q" xlink:href="#a"></z>
string(1) "Z"
http://www.w3.org/2000/xmlns/
<z id="q" xlink:href="#a"></z>
string(1) "Z"
10 changes: 9 additions & 1 deletion ext/dom/xpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@ static void dom_xpath_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *
RETURN_THROWS();
}

dom_xpath_object *intern = Z_XPATHOBJ_P(ZEND_THIS);
if (UNEXPECTED(intern->evaluation_depth > 0)) {
zend_throw_error(NULL, "Cannot call %s::__construct() while an XPath evaluation is in progress",
ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
RETURN_THROWS();
}

DOM_GET_OBJ(docp, doc, xmlDocPtr, docobj);

xmlXPathContextPtr ctx = xmlXPathNewContext(docp);
Expand All @@ -172,7 +179,6 @@ static void dom_xpath_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *
RETURN_THROWS();
}

dom_xpath_object *intern = Z_XPATHOBJ_P(ZEND_THIS);
xmlXPathContextPtr oldctx = intern->dom.ptr;
if (oldctx != NULL) {
php_libxml_decrement_doc_ref((php_libxml_node_object *) &intern->dom);
Expand Down Expand Up @@ -330,7 +336,9 @@ static void php_xpath_eval(INTERNAL_FUNCTION_PARAMETERS, int type, bool modern)
ctxp->nsNr = in_scope_ns.count;
}

intern->evaluation_depth++;
xmlXPathObjectPtr xpathobjp = xmlXPathEvalExpression(BAD_CAST expr, ctxp);
intern->evaluation_depth--;
ctxp->node = NULL;

if (register_node_ns && nodep != NULL) {
Expand Down
Loading
Loading