The TSRM keeps a hashtable mapping the thread IDs to the thread resource pointers.
It's possible that the thread disappears without us knowing, and then another thread
gets spawned some time later with the same ID as the disappeared thread.
Note that since it's a new thread the TSRM key pointer and cached pointer will be NULL.
The Apache request handler `php_handler()` will try to fetch some fields from the SAPI globals.
It uses a lazy thread resource allocation by calling `ts_resource(0);`.
This allocates a thread resource and sets up the TSRM pointers if they haven't been set up yet.
At least, that's what's supposed to happen. But since we are in a situation where the thread ID
still has the resources of the *old* thread associated in the hashtable,
the loop in `ts_resource_ex` will find that thread resource and assume the thread has been setup
already. But this is not the case since this thread is actually a new thread, just reusing the ID
of the old one, without any relation whatsoever to the old thread.
Because of this assumption, the TSRM pointers will not be setup, leading to a
NULL pointer dereference when trying to access the SAPI globals.
We can easily detect this scenario: if we're in the fallback path, and the pointer is NULL,
and we're looking for our own thread resource, we know we're actually reusing a thread ID.
In that case, we'll free up the old thread resources gracefully (gracefully because
there might still be resources open like database connection which need to be
shut down cleanly). After freeing the resources, we'll create the new resources for
this thread as if the stale resources never existed in the first place.
From that point forward, it is as if that situation never occurred.
The fact that this situation happens isn't that bad because a child process containing
threads will eventually be respawned anyway by the SAPI, so the stale thread resources
won't remain forever.
Note that we can't simply assign our own TSRM pointers to the existing
thread resource for our ID, since it was actually from a different thread
(just with the same ID!). Furthermore, the dynamically loaded extensions
have their own pointer, which is only set when their constructor is
called, so we'd have to call their constructor anyway...
I also tried to call the dtor and then the ctor again for those resources
on the pre-existing thread resource to reuse storage, but that didn't work properly
because other code doesn't expect something like that to happen, which breaks assumptions,
and this in turn caused Valgrind to (rightfully) complain about memory bugs.
Note 2: I also had to fix a bug in the core globals destruction because it
always assumed that the thread destroying them was the owning thread,
which on TSRM shutdown isn't always the case. A similar bug was fixed
recently with the JIT globals.
Closes GH-10863.
This change restores the old behaviour for the server socket streams
that don't support IO. This is now stored in the stream flags so it can
be later used to do some other decisions and possibly introduce some
better error reporting.
Closes GH-10877
Fixes GH-10692
php_fopen_primary_script() does not initialize all fields of
zend_file_handle. So when it fails and when fastcgi is true, the
zend_destroy_file_handle() function will try to free uninitialized
pointers, causing a segmentation fault. Fix it by zero-initializing file
handles just like the zend_stream_init_fp() counterpart does.
Closes GH-10697.
Fix it by extending the array sizes by one character. As the input is
limited to the maximum path length, there will always be place to append
the slash. As the php_check_specific_open_basedir() simply uses the
strings to compare against each other, no new failures related to too
long paths are introduced.
We'll let the DOM and XML case handle a potentially too long path in the
library code.
On some filesystems, the copy operation fails if we specify a size
larger than the file size in certain circumstances and configurations.
In those cases EIO will be returned as errno and we will therefore fall
back to other methods.
copy_file_range can return early without copying all the data. This is
legal behaviour and worked properly, unless the mmap fallback was used.
The mmap fallback would read too much data into the destination,
corrupting the destination file. Furthermore, if the mmap fallback would
fail and have to fallback to the regular file copying mechanism, a
similar issue would occur because both maxlen and haveread are modified.
Furthermore, there was a mmap-resource in one of the failure paths of
the mmap fallback code.
This patch fixes these issues. This also adds regression tests using the
new copy_file_range early-return simulation added in the previous
commit.
The precision "minimum" for spprintf was changed in
3f23e6bca9 with the cryptic comment "Enable 0
mode for echo/print". Since then the behaviour of spprintf and snprintf has not
been the same. This results in some APIs handling precision differently than
others, which then resulted in the following Xdebug issue:
https://bugs.xdebug.org/view.php?id=2151
The "manpage" for snprinf says about precision:
An optional precision, in the form of a period ('.') followed by an
optional decimal digit string. Instead of a decimal digit string one
may write "*" or "*m$" (for some decimal integer m) to specify that the
precision is given in the next argument, or in the m-th argument, re‐
spectively, which must be of type int. If the precision is given as
just '.', the precision is taken to be zero. A negative precision is
taken as if the precision were omitted.
However, the snprintf implementation never supported this "negative precision",
which is what PHP's default setting is in PG(precision). However, in
3f23e6bca9 spprintf was made to support this.
Although this techinically can break BC, there is clearly a bug here, and I
could not see any failing tests locally.
When this INI option is enabled, it reverts the line separator for
headers and message to LF which was a non conformant behavior in PHP 7.
It is done because some non conformant MTAs fail to parse CRLF line
separator for headers and body.
This is used for mail and mb_send_mail functions.
* main: Fix comment for php_safe_bcmp
* main: Include note about php_safe_bcmp being security sensitive
This is taken from the implementation of `hash_equals()`.