From 6cd78a438eb637fe4487643dcd05b0e171f13b27 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Thu, 25 Jun 2026 13:35:08 -0400 Subject: [PATCH] Fix GH-16217: 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 --- NEWS | 2 ++ ext/spl/spl_directory.c | 4 ++++ ext/spl/tests/gh16217.phpt | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 ext/spl/tests/gh16217.phpt diff --git a/NEWS b/NEWS index 7dd1aea4b881..39f2359152f0 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 f83ea9f84aca..eb3fb8caef64 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 000000000000..71760389c8e4 --- /dev/null +++ b/ext/spl/tests/gh16217.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-16217 (SplFileObject methods on an uninitialized object segfault) +--FILE-- +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