AC_CHECK_DECLS defines HAVE_DECL_ARC4RANDOM_BUF to 0 or 1. On Windows
this isn't defined to 0. To avoid the undefined state, the AC_CHECK_DECL
is used to manually define the HAVE_ARC4RANDOM_BUF to 1 if declaration
is found, otherwise undefined.
In the future on current platforms, also AC_CHECK_FUNCS can be used
instead since the arc4random_buf is located in default libraries (C)
with declaration available in headers.
The original calculation method for prod_arr_size allowed for some error,
which could have increased the number of simple loops without byte tricks
at the end of the calculation when converting to bc_num.
The new method calculates the size accurately, so the number of loops does
not increase unnecessarily.
The pg_encoding_to_char is available in PostgreSQL since ~7.3 where also
the --enable-multibyte option was removed. PHP minimum PostgreSQL
version at this point is 9.1, which also has the pg_encoding_to_char
declaration in libpq-fe.h.
This removes conditional usage and the HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
symbol.
The image output functions imagegif/imagepng/imagewebp/imageavif/imagejpeg
were all calling the static function _php_image_output_ctx which was basically
a big switch statement between each image type which also have different
parameters.
The only identical part was the call to create_stream_context_from_zval that
is now merged with create_output_context.
* zend_compile: Add `zend_compile_rope_finalize()`
This just extracts the implementation as-is into a dedicated function to make
it reusable in preparation of a future commit.
* zend_compile: Use clearer parameter names for `zend_compile_rope_finalize()`
* zend_compile: Fix `zend_compile_rope_finalize()` for ropes containing a single constant string
Without this Opcache will trigger a use-after-free in
`zend_optimizer_compact_literals()`.
Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
* zend_compile: Optimize `sprintf()` into a rope
This optimization will compile `sprintf()` using only `%s` placeholders into a
rope at compile time, effectively making those calls equivalent to the use of
string interpolation, with the added benefit of supporting arbitrary
expressions instead of just expressions starting with a `$`.
For a synthetic test using:
<?php
$a = 'foo';
$b = 'bar';
for ($i = 0; $i < 100_000_000; $i++) {
sprintf("%s-%s", $a, $b);
}
This optimization yields a 2.1× performance improvement:
$ hyperfine 'sapi/cli/php -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php' \
'/tmp/unoptimized -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php'
Benchmark 1: sapi/cli/php -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php
Time (mean ± σ): 1.869 s ± 0.033 s [User: 1.865 s, System: 0.003 s]
Range (min … max): 1.840 s … 1.945 s 10 runs
Benchmark 2: /tmp/unoptimized -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php
Time (mean ± σ): 4.011 s ± 0.034 s [User: 4.006 s, System: 0.005 s]
Range (min … max): 3.964 s … 4.079 s 10 runs
Summary
sapi/cli/php -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php ran
2.15 ± 0.04 times faster than /tmp/unoptimized -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php
This optimization comes with a small and probably insignificant behavioral
change: If one of the values cannot be (cleanly) converted to a string, for
example when attempting to insert an object that is not `Stringable`, the
resulting Exception will naturally not show the `sprintf()` call in the
resulting stack trace, because there is no call to `sprintf()`.
Nevertheless it will correctly point out the line of the `sprintf()` call as
the source of the Exception, pointing the user towards the correct location.
* zend_compile: Eagerly handle empty format strings in `sprintf()` optimization
* zend_compile: Add additional explanatory comments to zend_compile_func_sprintf()
* Add zero-argument test to sprintf_rope_optimization_001.phpt
---------
Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
These are either undefined or defined (to value 1):
- __DragonFly__
- __FreeBSD__
- HAS_MCAST_EXT
- HAVE_GETCWD
- HAVE_GETWD
- HAVE_GLIBC_ICONV
- HAVE_JIT
- HAVE_LCHOWN
- HAVE_NL_LANGINFO
- HAVE_RL_CALLBACK_READ_CHAR
- HAVE_RL_ON_NEW_LINE
- HAVE_SQL_EXTENDED_FETCH
- HAVE_UTIME
Follow up of GH-5526 (-Wundef)
This syncs few inconsistencies between the Windows and Autotools build
systems:
- HAVE_OPENSSL_EXT is now defined in the same style on both systems
(undefined - extension is not available, defined to 1 - extension is
available)
- HAVE_OPENSSL removed as it was only defined on Windows
* Replace WIN32 conditions with _WIN32 or PHP_WIN32
WIN32 is defined by the SDK and not defined all the time on Windows by
compilers or the environment. _WIN32 is defined as 1 when the
compilation target is 32-bit ARM, 64-bit ARM, x86, or x64. Otherwise,
undefined.
This syncs these usages one step further.
Upstream libgd has replaced WIN32 with _WIN32 via
https://github.com/libgd/libgd/commit/c60d9fe577ae8dad88e26344c4ceaa90da86e2f6
PHP_WIN32 is added to ext/sockets/sockets.stub.php as done in other
*.stub.php files at this point.
* Use PHP_WIN32 in ext/random
* Use PHP_WIN32 in ext/sockets
* Use _WIN32 in xxhash.h as done upstream
See https://github.com/Cyan4973/xxHash/pull/931
* Update end comment with PHP_WIN32
Although the issue was demonstrated using Curl, the issue is purely in
the streams layer of PHP.
Full analysis is written in GH-11078 [1], but here is the brief version:
Here's what actually happens:
1) We're creating a FILE handle from a stream using the casting mechanism.
This will create a cookie-based FILE handle using funopen.
2) We're reading stream data using fread from the userspace stream. This will
temporarily set a buffer into a field _bf.base [2]. This buffer is now equal
to the upload buffer that Curl allocated and note that that buffer is owned
by Curl.
3) The fatal error occurs and we bail out from the fread function, notice how
the reset code is never executed and so the buffer will still point to
Curl's upload buffer instead of FILE's own buffer [3].
4) The resources are destroyed, this includes our opened stream and because the
FILE handle is cached, it gets destroyed as well.
In fact, the stream code calls through fclose on purpose in this case.
5) The fclose code frees the _bs.base buffer [4].
However, this is not the buffer that FILE owns but the one that Curl owns
because it isn't reset properly due to the bailout!
6) The objects are getting destroyed, and so the curl free logic is invoked.
When Curl tries to gracefully clean up, it tries to free the buffer.
But that buffer is actually already freed mistakingly by the C library!
This also explains why we can't reproduce it on Linux: this bizarre buffer
swapping only happens on macOS and BSD, not on Linux.
To solve this, we switch to an unbuffered mode for cookie-based FILEs.
This avoids any stateful problems related to buffers especially when the
bailout mechanism triggers. As streams have their own buffering
mechanism, I don't expect this to impact performance.
[1] https://github.com/php/php-src/issues/11078#issuecomment-2155616843
[2] https://github.com/apple-open-source-mirror/Libc/blob/5e566be7a7047360adfb35ffc44c6a019a854bea/stdio/FreeBSD/fread.c#L102-L103
[3] https://github.com/apple-open-source-mirror/Libc/blob/5e566be7a7047360adfb35ffc44c6a019a854bea/stdio/FreeBSD/fread.c#L117
[4] https://github.com/apple-open-source-mirror/Libc/blob/5e566be7a7047360adfb35ffc44c6a019a854bea/stdio/FreeBSD/fclose.c#L66-L67
Closes GH-14524.
This fixes few more -Wundef warnings in ext/fileinfo. The
PHP_FILEINFO_UNCOMPRESS seems to be present to be defined at some point
but is currently unused in all build systems. Leaving this intact for
now.
Follow up of GH-5526 (-Wundef)