Skip to content

Commit fa78e17

Browse files
morrisonleviarnaud-lb
authored andcommitted
Stop closing stderr and stdout streams (php#8569)
Extensions may (and do) write to stderr in mshutdown and similar. In the best case, with the stderr stream closed, it's just swallowed. However, some libraries will do things like try to detect color, and these will outright fail and cause an error path to be taken.
1 parent 33850fb commit fa78e17

File tree

4 files changed

+31
-6
lines changed

4 files changed

+31
-6
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? 2022, PHP 8.0.20
44

5+
- CLI:
6+
. Fixed bug GH-8575 (CLI closes standard streams too early). (Levi Morrison)
7+
58
- Core:
69
. Fixed Haiku ZTS builds. (David Carlier)
710

ext/zend_test/test.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
4242
int observer_show_opcode;
4343
int observer_nesting_depth;
4444
int replace_zend_execute_ex;
45+
zend_bool print_stderr_mshutdown;
4546
HashTable global_weakmap;
4647
ZEND_END_MODULE_GLOBALS(zend_test)
4748

@@ -407,6 +408,7 @@ PHP_INI_BEGIN()
407408
STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
408409
STD_PHP_INI_BOOLEAN("zend_test.observer.show_opcode", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_opcode, zend_zend_test_globals, zend_test_globals)
409410
STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals)
411+
STD_PHP_INI_BOOLEAN("zend_test.print_stderr_mshutdown", "0", PHP_INI_SYSTEM, OnUpdateBool, print_stderr_mshutdown, zend_zend_test_globals, zend_test_globals)
410412
PHP_INI_END()
411413

412414
static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data);
@@ -526,6 +528,10 @@ PHP_MSHUTDOWN_FUNCTION(zend_test)
526528
UNREGISTER_INI_ENTRIES();
527529
}
528530

531+
if (ZT_G(print_stderr_mshutdown)) {
532+
fprintf(stderr, "[zend-test] MSHUTDOWN\n");
533+
}
534+
529535
return SUCCESS;
530536
}
531537

ext/zend_test/tests/gh8575.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
CLI: stderr is available in mshutdown
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('zend-test')) die('skip zend-test extension required');
6+
if (php_sapi_name() != "cli") die('skip cli test only');
7+
?>
8+
--INI--
9+
zend_test.print_stderr_mshutdown=1
10+
--FILE--
11+
==DONE==
12+
--EXPECTF--
13+
==DONE==
14+
[zend-test] MSHUTDOWN

sapi/cli/php_cli.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -539,19 +539,21 @@ static void cli_register_file_handles(void) /* {{{ */
539539
s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out);
540540
s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err);
541541

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

549-
#if PHP_DEBUG
550-
/* do not close stdout and stderr */
551-
s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE;
552-
s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;
553-
#endif
554-
555557
s_in_process = s_in;
556558

557559
php_stream_to_zval(s_in, &ic.value);

0 commit comments

Comments
 (0)