Commit b2163be5ff1 for php
commit b2163be5ff10a4347b314ee8cecf2866138e3d7a
Author: lacatoire <la.catoire@gmail.com>
Date: Tue Oct 13 15:31:27 2026 +0200
Clear the libxml last error in libxml_use_internal_errors(false)
libxml_use_internal_errors(false) destroyed the internal error list but
left libxml's own last error in place. libxml_get_last_error() falls
back to it once the list is gone, so it kept returning an error while
libxml_get_errors() was empty, although the documentation says that
disabling clears the existing errors.
Reset the last error when the list is destroyed. Calling the function
again while the internal errors are already disabled leaves it alone.
Closes GH-24295.
diff --git a/NEWS b/NEWS
index a93cb03247e..67c44a4420e 100644
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,10 @@ PHP NEWS
encoding used for percent-encoding, the URLSearchParams tail pointer and
fragment serialization without a query. (alexandre-daubois)
+- LibXML:
+ . Clear the libxml last error in libxml_use_internal_errors(false).
+ (lacatoire)
+
- MBString:
. Fixed bug GH-23106 (mb_strpos() reads past the end of a haystack ending in
a truncated UTF-8 sequence). (Lazizbek Ergashev)
diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
index e5374637942..489dea57710 100644
--- a/ext/libxml/libxml.c
+++ b/ext/libxml/libxml.c
@@ -1137,6 +1137,9 @@ PHP_FUNCTION(libxml_use_internal_errors)
zend_llist_destroy(LIBXML(error_list));
efree(LIBXML(error_list));
LIBXML(error_list) = NULL;
+ /* libxml_get_last_error() falls back to libxml's own last error
+ * once the list is gone, so it must not outlive the cleared list. */
+ xmlResetLastError();
}
} else {
xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
diff --git a/ext/libxml/tests/libxml_use_internal_errors_clears_last_error.phpt b/ext/libxml/tests/libxml_use_internal_errors_clears_last_error.phpt
new file mode 100644
index 00000000000..a0a40d100a6
--- /dev/null
+++ b/ext/libxml/tests/libxml_use_internal_errors_clears_last_error.phpt
@@ -0,0 +1,29 @@
+--TEST--
+libxml_use_internal_errors(false) clears the last error
+--EXTENSIONS--
+libxml
+dom
+--FILE--
+<?php
+
+libxml_use_internal_errors(true);
+
+$document = new DOMDocument();
+$document->loadXML('<a><b></a>');
+
+var_dump(count(libxml_get_errors()) > 0);
+var_dump(libxml_get_last_error() instanceof LibXMLError);
+
+var_dump(libxml_use_internal_errors(false));
+
+var_dump(libxml_get_errors());
+var_dump(libxml_get_last_error());
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+array(0) {
+}
+bool(false)