Commit 97a90f43617 for php.net

commit 97a90f43617badc7b917d51f6138a7387ab03a46
Author: David Carlier <devnexen@gmail.com>
Date:   Sat Dec 13 10:20:58 2025 +0000

    Fix GH-20678: resource created by GlobIterator crashes with fclose().

    close GH-20697

diff --git a/NEWS b/NEWS
index 007faa02495..ed2c4149a03 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,10 @@ PHP                                                                        NEWS
 - LDAP:
   . Fix memory leak in ldap_set_options(). (ndossche)

+- SPL:
+  . Fixed bug GH-20678 (resource created by GlobIterator crashes with fclose()).
+    (David Carlier)
+
 - Standard:
   . Fix error check for proc_open() command. (ndossche)

diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index 0a4d1456d65..16bb6a11e52 100644
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -306,6 +306,11 @@ static void spl_filesystem_dir_open(spl_filesystem_object* intern, zend_string *
 	intern->type = SPL_FS_DIR;
 	intern->u.dir.dirp = php_stream_opendir(ZSTR_VAL(path), REPORT_ERRORS, FG(default_context));

+	if (intern->u.dir.dirp) {
+		/* we prevent potential UAF with conflicting explicit fclose(), relying on the object destructor for this */
+		intern->u.dir.dirp->flags |= PHP_STREAM_FLAG_NO_FCLOSE;
+	}
+
 	if (ZSTR_LEN(path) > 1 && IS_SLASH_AT(ZSTR_VAL(path), ZSTR_LEN(path)-1)) {
 		intern->path = zend_string_init(ZSTR_VAL(path), ZSTR_LEN(path)-1, 0);
 	} else {
diff --git a/ext/spl/tests/gh20678.phpt b/ext/spl/tests/gh20678.phpt
new file mode 100644
index 00000000000..243f8cef06d
--- /dev/null
+++ b/ext/spl/tests/gh20678.phpt
@@ -0,0 +1,14 @@
+--TEST--
+GH-20678 (resource created by GlobalIterator crashes when it is called with fclose())
+--CREDITS--
+chongwick
+--FILE--
+<?php
+$iter = new GlobIterator(__DIR__ . '/*.abcdefghij');
+$resources = get_resources();
+$resource = end($resources);
+fclose($resource);
+?>
+--EXPECTF--
+
+Warning: fclose(): %d is not a valid stream resource in %s on line %d