diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 10134c21e1e9..ca54db7ef3c9 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2016,22 +2016,21 @@ static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *i PHP_METHOD(SplFileObject, __construct) { spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); + zend_string *file_name = NULL; zend_string *open_mode = ZSTR_CHAR('r'); + zval *stream_context = NULL; bool use_include_path = 0; size_t path_len; zend_error_handling error_handling; - intern->u.file.open_mode = ZSTR_CHAR('r'); - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|Sbr!", - &intern->file_name, &open_mode, - &use_include_path, &intern->u.file.zcontext) == FAILURE) { - intern->u.file.open_mode = NULL; - intern->file_name = NULL; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|Sbr!", &file_name, &open_mode, &use_include_path, &stream_context) == FAILURE) { RETURN_THROWS(); } intern->u.file.open_mode = zend_string_copy(open_mode); + /* file_name and zcontext are copied by spl_filesystem_file_open() */ + intern->file_name = file_name; + intern->u.file.zcontext = stream_context; /* spl_filesystem_file_open() can generate E_WARNINGs which we want to promote to exceptions */ zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling); @@ -2070,6 +2069,12 @@ PHP_METHOD(SplTempFileObject, __construct) RETURN_THROWS(); } + /* Prevent reinitialization of Object */ + if (intern->u.file.stream) { + zend_throw_error(NULL, "Cannot call constructor twice"); + RETURN_THROWS(); + } + if (max_memory < 0) { file_name = ZSTR_INIT_LITERAL("php://memory", 0); } else if (ZEND_NUM_ARGS()) { diff --git a/ext/spl/tests/gh16477-2.phpt b/ext/spl/tests/gh16477-2.phpt new file mode 100644 index 000000000000..a51b9408c2d4 --- /dev/null +++ b/ext/spl/tests/gh16477-2.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-16477-2: Memory leak when calling SplTempFileObject::__constructor() twice +--FILE-- +__construct(); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +$obj->__debugInfo(); + +?> +DONE +--EXPECT-- +Error: Cannot call constructor twice +DONE diff --git a/ext/spl/tests/gh16477.phpt b/ext/spl/tests/gh16477.phpt new file mode 100644 index 000000000000..f35c9538e855 --- /dev/null +++ b/ext/spl/tests/gh16477.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-16477: Segmentation fault when calling __debugInfo() after failed SplFileObject::__constructor +--FILE-- +__construct(); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +$obj->__debugInfo(); + +?> +DONE +--EXPECT-- +ArgumentCountError: SplFileObject::__construct() expects at least 1 argument, 0 given +DONE