This time a number of comments have been added to make it easy for new devs to understand
what is going on. Also adjusted error message to use colons rather than dashes.
proc_open can accept stream resources in the descriptorspec, like this:
proc_open("command", array(0 => $resource), $pipes);
Previously, if a resource which was *not* of type "stream" was passed, proc_open would
return without freeing dynamically allocated memory. It's fixed now.
Back in 2004, a feature was added to proc_open which allowed it to open a PTY,
connecting specific FDs in the child process to the slave end of the PTY and returning
the master end of the PTY (wrapped as a PHP stream) in the `$pipes` array. However,
this feature was disabled just about a month later. Little information is available
about why this was done, but from talking to the original implementer, it seems there
were portability problems with some rare flavors of Unix.
Re-enable this feature with a simplified implementation which uses openpty(). No
attempt is made to support PTYs if the platform does not have openpty(). The configure
script checks if linking with -lutil is necessary to use openpty(), but if anything
else is required, like including some special header or linking with some other library,
PTY support will be disabled.
The original PTY support for proc_open automatically daemonized the child process
(disassociating it from the TTY session and process group of the parent). However,
I don't think this is a good idea. Just because a user opens a child process in a
PTY, it doesn't mean they want it to continue running even when the parent process
is killed. Of course, if the child process is some kind of server, it will likely
daemonize itself; but we have no reason to preempt that decision.
It turns out that since 2015, there has been one test case for PTY support in
proc_open() in the test suite. This test was added in GitHub PR #1588
(https://github.com/php/php-src/pull/1588). That PR mentioned that the PHP
binary in the Debian/Ubuntu repositories is patched to *enable* PTY support. Checking
the Debian PHP repository (https://salsa.debian.org/php-team/php.git) shows that this
is still true. Debian's patch does not modify the implementation from 2004 in any
way; it just removes the #if 0 line which disables it.
Naturally, the test case is skipped if PTY support is not enabled. This means that ever
since it was added, every test run against the 'vanilla' PHP codebase has skipped it.
Interestingly, the test case which was added in 2015 fails on my Linux Mint PC... both
with this simplified implementation *and* when enabling the original implementation.
Investigation reveals the reason: when the child process using the slave end of the
PTY exits and its FDs are all closed, and all buffered data is read from the master
end of the PTY, any further attempt to read from the master end fails with EIO. The
test case seems to expect that reading from the master end will always return an
empty string if no data is available.
Likely this is because PHP's fread() was updated to report errors from the underlying
system calls only recently.
One way out of this dilemma: IF at least one FD referring to the slave end of the PTY is
kept open *in the parent process*, the failure with EIO will not occur even after the child
process exits. However, that would raise another issue: we would need a way to ensure the FD
will be closed eventually in long-running programs.
Another discovery made while testing this code is that fread() does not always return
all the data written to the slave end of the PTY in a single call, even if the data was
written with a single syscall and it is only a few bytes long.
Specifically, when the child process in the test case writes "foo\n" to the PTY, the parent
sometimes receives "foo" (3 bytes) and sometimes "foo\r\n" (5 bytes). (The "\r" is from the
TTY line discipline converting "\n" to "\r\n".) A second call to fread() does return the
remaining bytes, though sometimes all the data is read in the first call, and by the time
the second call is made, the child process has already exited. It seems that liberal use
of the @ operator is needed when using fread() on pipes.
Thanks to Nikita Popov for suggesting that we should just use openpty() rather than
grantpt(), unlockpt(), etc.
We don't support persistent proc_open handles and have no plan
to suppor them. The mixture of persistent and non-persistent
allocations functions in this code is somewhat confusing to read.
While the `$command` passed to `proc_open()` had to be wrapped in
double-quotes manually, that was implicitly done for all other
program execution functions. This could easily introduce bugs and
even security issues when switching from one to another program
execution function.
Furthermore we ensure that the additional quotes are always
unwrapped regardless of what is passed as `$command` by passing
the `/s` flag to cmd.exe. As it was, `shell_exec('path with
spaces/program.exe')` did execute program.exe, but adding an
argument (`shell_exec('path with spaces/program.exe -h)`) failed
to execute program.exe, because cmd.exe stripped the additional
quotes.
While these changes obviously can cause BC breaks, we feel that in
the long run the benefits of having consistent behavior for all
program execution functions outweighs the drawbacks of potentially
breaking some code now.
The primary motivation to have each test worker running its own console
is to allow the windows_mb_path tests to run in parallel. A nice side
effect is that this also prevents changing the code page of the
tester's console window (which can even cause its font to be changed).
To be able to do so, we introduce the `create_new_console` option for
`proc_open()`, which might occasionally be useful for other purposes
than testing.
This adds support for doing something like:
[1 => ['pipe', 'w'], 2 => ['redirect', 1]]
This will make descriptor 2 on the child end a dup'd descriptor 1.
This is mainly useful in conjunction with shell-less mode, because
we don't have an easy way to do "2>&1" there.
Additionally we support:
[1 => ['pipe', 'w'], 2 => ['null']]
Which would be the same as a >/dev/null or >nul redirect, depending
on platform.
In this case the progarm will be executed directly, without a shell.
On Linux the arguments are passed directly to execvp and no escaping
is necessary. On Windows we construct a command string using escaping
with the default Windows command-line argument parsing method described
at https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments.
Apart from avoiding the issue of argument escaping, passing an array
and bypassing shell has the advantage of allowing proper signal
delivery to the opened process (rather than the shell).
RFC: https://wiki.php.net/rfc/tostring_exceptions
And convert some object to string conversion related recoverable
fatal errors into Error exceptions.
Improve exception safety of internal code performing string
conversions.
The `<signal.h>` header file is part of the standard C89 headers [1] and
on current systems can be included unconditionally.
Since file requires at least C89 or greater, the `HAVE_SIGNAL_H` symbol
defined by Autoconf in Zend.m4 [2] can be ommitted and simplifed.
The bundled libmagic (file) also ommits the usage of HAVE_SIGNAL_H since
5.35 however current version in PHP is very modified 5.34 version and
will be refactored separately. Check for HAVE_SIGNAL_H is therefore
still done in the configure.ac.
Refs:
[1] https://port70.net/~nsz/c/c89/c89-draft.html#4.1.2
[2] https://git.savannah.gnu.org/cgit/autoconf.git/tree/lib/autoconf/headers.m4
This patch removes the so called local variables defined per
file basis for certain editors to properly show tab width, and
similar settings. These are mainly used by Vim and Emacs editors
yet with recent changes the once working definitions don't work
anymore in Vim without custom plugins or additional configuration.
Neither are these settings synced across the PHP code base.
A simpler and better approach is EditorConfig and fixing code
using some code style fixing tools in the future instead.
This patch also removes the so called modelines for Vim. Modelines
allow Vim editor specifically to set some editor configuration such as
syntax highlighting, indentation style and tab width to be set in the
first line or the last 5 lines per file basis. Since the php test
files have syntax highlighting already set in most editors properly and
EditorConfig takes care of the indentation settings, this patch removes
these as well for the Vim 6.0 and newer versions.
With the removal of local variables for certain editors such as
Emacs and Vim, the footer is also probably not needed anymore when
creating extensions using ext_skel.php script.
Additionally, Vim modelines for setting php syntax and some editor
settings has been removed from some *.phpt files. All these are
mostly not relevant for phpt files neither work properly in the
middle of the file.
RFC: https://wiki.php.net/rfc/typed_properties_v2
This is a squash of PR #3734, which is a squash of PR #3313.
Co-authored-by: Bob Weinand <bobwei9@hotmail.com>
Co-authored-by: Joe Watkins <krakjoe@php.net>
Co-authored-by: Dmitry Stogov <dmitry@zend.com>
The $Id$ keywords were used in Subversion where they can be substituted
with filename, last revision number change, last changed date, and last
user who changed it.
In Git this functionality is different and can be done with Git attribute
ident. These need to be defined manually for each file in the
.gitattributes file and are afterwards replaced with 40-character
hexadecimal blob object name which is based only on the particular file
contents.
This patch simplifies handling of $Id$ keywords by removing them since
they are not used anymore.
Prohibit direct update of GC_REFCOUNT(), GC_SET_REFCOUNT(), GC_ADDREF() and GC_DELREF() shoukf be instead.
Added mactros to validate reference-counting (disabled for now).
These macros are going to be used to eliminate race-condintions during reference-counting on data shared between threads.