Skip to content

Commit 6d12aec

Browse files
committed
Stop closing stderr and stdout streams
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 84ea0aa commit 6d12aec

File tree

4 files changed

+28
-6
lines changed

4 files changed

+28
-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 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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--TEST--
2+
CLI: stderr is available in mshutdown
3+
--SKIPIF--
4+
<?php if (!extension_loaded('zend-test')) die('skip: zend-test extension required'); ?>
5+
--INI--
6+
zend_test.print_stderr_mshutdown=1
7+
--FILE--
8+
==DONE==
9+
--EXPECTF--
10+
==DONE==
11+
[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)