Skip to content

Commit 5d993e9

Browse files
committed
Fix GH-16477 (Segmentation fault when calling __debugInfo() after failed SplFileObject::__constructor)
Closes GH-16480 Closes GH-16604
1 parent 3599fd0 commit 5d993e9

File tree

3 files changed

+50
-7
lines changed

3 files changed

+50
-7
lines changed

ext/spl/spl_directory.c

+12-7
Original file line numberDiff line numberDiff line change
@@ -2016,22 +2016,21 @@ static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *i
20162016
PHP_METHOD(SplFileObject, __construct)
20172017
{
20182018
spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2019+
zend_string *file_name = NULL;
20192020
zend_string *open_mode = ZSTR_CHAR('r');
2021+
zval *stream_context = NULL;
20202022
bool use_include_path = 0;
20212023
size_t path_len;
20222024
zend_error_handling error_handling;
20232025

2024-
intern->u.file.open_mode = ZSTR_CHAR('r');
2025-
2026-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|Sbr!",
2027-
&intern->file_name, &open_mode,
2028-
&use_include_path, &intern->u.file.zcontext) == FAILURE) {
2029-
intern->u.file.open_mode = NULL;
2030-
intern->file_name = NULL;
2026+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|Sbr!", &file_name, &open_mode, &use_include_path, &stream_context) == FAILURE) {
20312027
RETURN_THROWS();
20322028
}
20332029

20342030
intern->u.file.open_mode = zend_string_copy(open_mode);
2031+
/* file_name and zcontext are copied by spl_filesystem_file_open() */
2032+
intern->file_name = file_name;
2033+
intern->u.file.zcontext = stream_context;
20352034

20362035
/* spl_filesystem_file_open() can generate E_WARNINGs which we want to promote to exceptions */
20372036
zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
@@ -2070,6 +2069,12 @@ PHP_METHOD(SplTempFileObject, __construct)
20702069
RETURN_THROWS();
20712070
}
20722071

2072+
/* Prevent reinitialization of Object */
2073+
if (intern->u.file.stream) {
2074+
zend_throw_error(NULL, "Cannot call constructor twice");
2075+
RETURN_THROWS();
2076+
}
2077+
20732078
if (max_memory < 0) {
20742079
file_name = ZSTR_INIT_LITERAL("php://memory", 0);
20752080
} else if (ZEND_NUM_ARGS()) {

ext/spl/tests/gh16477-2.phpt

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
GH-16477-2: Memory leak when calling SplTempFileObject::__constructor() twice
3+
--FILE--
4+
<?php
5+
6+
$obj = new SplTempFileObject();
7+
8+
try {
9+
$obj->__construct();
10+
} catch (Throwable $e) {
11+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
12+
}
13+
$obj->__debugInfo();
14+
15+
?>
16+
DONE
17+
--EXPECT--
18+
Error: Cannot call constructor twice
19+
DONE

ext/spl/tests/gh16477.phpt

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
GH-16477: Segmentation fault when calling __debugInfo() after failed SplFileObject::__constructor
3+
--FILE--
4+
<?php
5+
6+
$obj = new SplFileObject(__FILE__);
7+
8+
try {
9+
$obj->__construct();
10+
} catch (Throwable $e) {
11+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
12+
}
13+
$obj->__debugInfo();
14+
15+
?>
16+
DONE
17+
--EXPECT--
18+
ArgumentCountError: SplFileObject::__construct() expects at least 1 argument, 0 given
19+
DONE

0 commit comments

Comments
 (0)