Commit 60d8e92ed4a for php.net

commit 60d8e92ed4a0c1b310a81103f3b423713aece6c8
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date:   Thu Jun 25 13:35:08 2026 -0400

    Guard uninitialized SplFileObject in fputcsv() and next()

    fputcsv() and next() reached the file stream without the
    CHECK_SPL_FILE_OBJECT_IS_INITIALIZED guard their siblings carry, so
    invoking them via reflection on an object from
    newInstanceWithoutConstructor() (constructor bypassed, stream NULL)
    crashed instead of throwing. next() only touches the stream with the
    READ_AHEAD flag, itself settable through the equally unguarded
    setFlags(). Both now throw "Object not initialized".

    Fixes GH-16217
    Closes GH-22454

diff --git a/NEWS b/NEWS
index 7dd1aea4b88..39f2359152f 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,8 @@ PHP                                                                        NEWS
     (jorgsowa)
   . Ignore leading back-slash in class_parents(), class_implements(), and
     class_uses(). (jorgsowa)
+  . Fixed bug GH-16217 (SplFileObject::fputcsv() on an uninitialized object
+    segfaults). (iliaal)

 - Standard:
   . Fixed bug GH-22360 (convert.base64-encode corruption on
diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index f83ea9f84ac..eb3fb8caef6 100644
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -2224,6 +2224,8 @@ PHP_METHOD(SplFileObject, next)
 		RETURN_THROWS();
 	}

+	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
+
 	spl_filesystem_file_free_line(intern);
 	if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
 		spl_filesystem_file_read_line(ZEND_THIS, intern, true);
@@ -2376,6 +2378,8 @@ PHP_METHOD(SplFileObject, fputcsv)
 		RETURN_THROWS();
 	}

+	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
+
 	if (delim) {
 		if (d_len != 1) {
 			zend_argument_value_error(2, "must be a single character");
diff --git a/ext/spl/tests/gh16217.phpt b/ext/spl/tests/gh16217.phpt
new file mode 100644
index 00000000000..71760389c8e
--- /dev/null
+++ b/ext/spl/tests/gh16217.phpt
@@ -0,0 +1,35 @@
+--TEST--
+GH-16217 (SplFileObject methods on an uninitialized object segfault)
+--FILE--
+<?php
+function uninitialized(): SplFileObject {
+    return (new ReflectionClass(SplFileObject::class))->newInstanceWithoutConstructor();
+}
+
+try {
+    (new ReflectionMethod(SplFileObject::class, "fputcsv"))->invoke(uninitialized(), []);
+} catch (Error $e) {
+    echo "fputcsv: ", $e->getMessage(), "\n";
+}
+
+try {
+    (new ReflectionMethod(SplFileObject::class, "next"))->invoke(uninitialized());
+} catch (Error $e) {
+    echo "next: ", $e->getMessage(), "\n";
+}
+
+$obj = uninitialized();
+(new ReflectionMethod(SplFileObject::class, "setFlags"))->invoke($obj, SplFileObject::READ_AHEAD);
+try {
+    (new ReflectionMethod(SplFileObject::class, "next"))->invoke($obj);
+} catch (Error $e) {
+    echo "next (READ_AHEAD): ", $e->getMessage(), "\n";
+}
+
+echo "Done\n";
+?>
+--EXPECT--
+fputcsv: Object not initialized
+next: Object not initialized
+next (READ_AHEAD): Object not initialized
+Done