Skip to content

Commit d543ced

Browse files
committed
Allow to not close stream on rscr dtor in php cli sapi
1 parent 332ac8e commit d543ced

File tree

5 files changed

+35
-14
lines changed

5 files changed

+35
-14
lines changed

ext/zend_test/tests/gh8575.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
--TEST--
22
CLI: stderr is available in mshutdown
3-
--XFAIL--
4-
GH-8952 / GH-8833
53
--SKIPIF--
64
<?php if (php_sapi_name() != "cli") die('skip cli test only'); ?>
75
--EXTENSIONS--

main/php_streams.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ struct _php_stream_wrapper {
185185
* Currently for internal use only. */
186186
#define PHP_STREAM_FLAG_SUPPRESS_ERRORS 0x100
187187

188+
/* Do not close handle except it is explicitly closed by user (e.g. fclose) */
189+
#define PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE 0x200
190+
188191
#define PHP_STREAM_FLAG_WAS_WRITTEN 0x80000000
189192

190193
struct _php_stream {

main/streams/streams.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,8 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options) /* {{{ */
383383

384384
context = PHP_STREAM_CONTEXT(stream);
385385

386-
if (stream->flags & PHP_STREAM_FLAG_NO_CLOSE) {
386+
if ((stream->flags & PHP_STREAM_FLAG_NO_CLOSE) ||
387+
((stream->flags & PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE) && (close_options & PHP_STREAM_FREE_RSRC_DTOR))) {
387388
preserve_handle = 1;
388389
}
389390

sapi/cli/php_cli.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ static void php_cli_usage(char *argv0)
526526

527527
static php_stream *s_in_process = NULL;
528528

529-
static void cli_register_file_handles(bool no_close) /* {{{ */
529+
static void cli_register_file_handles(void)
530530
{
531531
php_stream *s_in, *s_out, *s_err;
532532
php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL;
@@ -536,19 +536,21 @@ static void cli_register_file_handles(bool no_close) /* {{{ */
536536
s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out);
537537
s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err);
538538

539+
/* Release stream resources, but don't free the underlying handles. Othewrise,
540+
* extensions which write to stderr or company during mshutdown/gshutdown
541+
* won't have the expected functionality.
542+
*/
543+
if (s_in) s_in->flags |= PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE;
544+
if (s_out) s_out->flags |= PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE;
545+
if (s_err) s_err->flags |= PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE;
546+
539547
if (s_in==NULL || s_out==NULL || s_err==NULL) {
540548
if (s_in) php_stream_close(s_in);
541549
if (s_out) php_stream_close(s_out);
542550
if (s_err) php_stream_close(s_err);
543551
return;
544552
}
545553

546-
if (no_close) {
547-
s_in->flags |= PHP_STREAM_FLAG_NO_CLOSE;
548-
s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE;
549-
s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;
550-
}
551-
552554
s_in_process = s_in;
553555

554556
php_stream_to_zval(s_in, &ic.value);
@@ -567,7 +569,6 @@ static void cli_register_file_handles(bool no_close) /* {{{ */
567569
ec.name = zend_string_init_interned("STDERR", sizeof("STDERR")-1, 0);
568570
zend_register_constant(&ec);
569571
}
570-
/* }}} */
571572

572573
static const char *param_mode_conflict = "Either execute direct code, process stdin or use a file.\n";
573574

@@ -954,7 +955,7 @@ static int do_cli(int argc, char **argv) /* {{{ */
954955
switch (behavior) {
955956
case PHP_MODE_STANDARD:
956957
if (script_file) {
957-
cli_register_file_handles(/* no_close */ PHP_DEBUG || num_repeats > 1);
958+
cli_register_file_handles();
958959
}
959960

960961
if (interactive) {
@@ -990,7 +991,7 @@ static int do_cli(int argc, char **argv) /* {{{ */
990991
}
991992
break;
992993
case PHP_MODE_CLI_DIRECT:
993-
cli_register_file_handles(/* no_close */ PHP_DEBUG || num_repeats > 1);
994+
cli_register_file_handles();
994995
zend_eval_string_ex(exec_direct, NULL, "Command line code", 1);
995996
break;
996997

@@ -1005,7 +1006,7 @@ static int do_cli(int argc, char **argv) /* {{{ */
10051006
file_handle.filename = NULL;
10061007
}
10071008

1008-
cli_register_file_handles(/* no_close */ PHP_DEBUG || num_repeats > 1);
1009+
cli_register_file_handles();
10091010

10101011
if (exec_begin) {
10111012
zend_eval_string_ex(exec_begin, NULL, "Command line begin code", 1);

sapi/cli/tests/gh8827.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
std handles can be deliberately closed
3+
--SKIPIF--
4+
<?php
5+
if (php_sapi_name() != "cli") {
6+
die("skip CLI only");
7+
}
8+
if (substr(PHP_OS, 0, 3) == 'WIN') {
9+
die("skip not for Windows");
10+
}
11+
?>
12+
--FILE--
13+
<?php
14+
fclose(STDERR);
15+
var_dump(@fopen('php://stderr', 'a'));
16+
?>
17+
--EXPECT--
18+
bool(false)

0 commit comments

Comments
 (0)