diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 0440ff59c8ba9..83653f65e9f5f 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2042,22 +2042,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); @@ -2096,6 +2095,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 = zend_string_init("php://memory", sizeof("php://memory")-1, 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 0000000000000..a51b9408c2d44 --- /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 0000000000000..f35c9538e8556 --- /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