Keep this up to date in all non-security-only branches, because the node.js
runtime for older versions might get deprecated in the future and fixing this
for all branches at once is easier.
see 45e60e585e
* Remove references to ODBCVER and assume ODBC 3.x
See https://wiki.php.net/rfc/deprecations_php_8_5#remove_support_for_older_odbc_versions
* Avoid calling deprecated ODBC functions
`SQLGetConnectOption`, `SQLSetConnectOption` and `SQLSetStmtOption` are
deprecated, so if ODBC 3 is available, we use `SQLSetConnectAttr`,
`SQLGetConnectAttr`, and `SQLSetStmtAttr` instead.
(This is based on GH-17556, but just assumes ODBC 3.x.)
* Remove wrappers for SQLColAttribute
We don't need to support the old way of doing it.
* Just call SQLAllocHandle directly
Again, no need for the version specific wrapper
* Update NEWS for ODBCVER in beta2
* [skip ci] UPGRADING for ODBCVER changes
---------
Co-authored-by: Christoph M. Becker <cmbecker69@gmx.de>
The allows cipher_algo to be specified as a string. It means the not
only predefined ID ciphers are available which means that also auth
enveloped data can be created using AES GCM.
Closes GH-19459
* Emit EXT_STMT after each pipe stage, and attach the TMP var that holds the intermediary result
* Add ZEND_EXT_STMT to keeps_op1_alive as per review
* Fix leak with EXT_STMT when pipe result is unused
Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
This adds PKCS7_NOSMIMECAP, PKCS7_CRLFEOL, PKCS7_NOCRL and
PKCS7_NO_DUAL_CONTENT constants. They might be potentially useful
in some scenarious.
Test is not added as it is not clear if there is much need for those and
it would require much bigger effort just to test OpenSSL functionality.
Closes GH-19450
This does not seem like an issue as the aliases seem to be already
fetched most of the time. But there might be cases when it could be
failing like it was failing for MD in GH-19369.
It should be noted that the test does not fail without this change but
it seems useful anyway so it is added as part of this change. I
actually have not found the case where alias is not fetched for cipher
but there might be some.
Closes GH-19437
The motivation is two fold:
- Userland code that deals with ext/intl can be expected to handle IntlException but not necessarily ext/date exceptions
- This removes the possibility of superfluous warnings being emitted by ext/intl when an exception has already been thrown
Currently, configure fails when no SHM backend is available. Additionally,
even after bypassing the configure check, opcache emits a fatal error if no
SHM backend is available.
Make the configure check non-fatal (a warning is printed). At runtime, disable
opcache if no backend is available, in the same way we disable opcache by
default on CLI.
Closes GH-19350
The stack limit is checked when entering execute_ex(), but the fuzzer has
its own execute function and does not call execute_ex().
Add a stack limit check in the fuzzer's execute function.
Closes GH-19391
Add a C function, opcache_preloading(), that returns true during
preloading. Extensions can use this to detect preloading, not only during
compilation/execution, but also in RINIT()/RSHUTDOWN().
Since opcache currently doesn't install any header, I'm adding a new one:
zend_accelerator_api.h. Header name is based on other files in ext/opcache.
Closes GH-19288
* Fix Windows test for openssl-3.5 upgrade
* Update ext/openssl/tests/check_default_conf_path.phpt
Co-authored-by: Christoph M. Becker <cmbecker69@gmx.de>
---------
Co-authored-by: Christoph M. Becker <cmbecker69@gmx.de>
JIT used to not have a compile-time dependency on VM kind, such that a single
build of opcache could work with different VM kinds at runtime. This has been broken
over time and would be difficult to restore. Additionally, as opcache is now
built-in, this would not be useful anymore.
Remove the zend_jit_vm_kind variable.
First of all, the last successful build had been before opcache was made required - therefore the PHP_OPCACHE setting should be 2 to manually enable it.
Then, the manual flow should comment on the PR of the triggering repo (github.repository), not the repo of the benchmarked code (env.REPOSITORY).
* Add SAPI_HEADER_DELETE_PREFIX operation
The session ext currently munges into the linked list of headers
itself, because the delete header API is given the key for headers to
delete. The session ext wants to use a prefix past the colon separator,
for i.e. "Set-Cookie: PHPSESSID=", to eliminate only the specific cookie
rather than all cookies.
This changes the SAPI code to add a new header op to take a prefix
instead. Call sites are yet unchanged. Also fix some whitespace.
* Simplify cookie setting code in ext/session
Use the modern SAPI header ops API, including the remove prefix op we
just added.
* [ci skip] Remove redundant and unnecessary comment
The purpose of this is clear, and after refactoring, the special case is
no longer there, so it has no value.
* Un-deprecate simple add/replace header API, use it
Suggestion from Jakub.
* Restore the optimization removing session cookies had
I don't think this needs to be special cased with the parameter.
* Move setting header length to caller
Suggestion from Jakub.
* [ci skip] adjust tab count
It may be better to use spaces in here instead.
* Use session_cookie_len rather than calling strlen
Reuse the helper zend_foreach_op_array() that we move to the
zend_optimizer.h header to be usable in opcache.
Note that applying this to other op_array loops is not easy because they either:
- start from EG(persistent_classes_count)
- or only apply to classes
Since GH-17755 self and parent are compile-time resolved. We may now also
encounter this type error at runtime outside of the class itself.
Fixes GH-19304
If the test is skipped, the `--SKIPIF--` section exits (via `die()`) without
removing the "bug81145_src.bin" file that gets created, and because the test
was skipped the `--CLEAN--` section is not run, leaving the .bin file behind.
Adjust the `--SKIPIF--` section to remove the .bin file before exiting.
This is a comprehensive refactoring of the error mechanism of the Intl extension.
By moving the prefixing of the current method/function being executed to actual error message creation by accessing the execution context, we get the following benefits:
- Accurate error messages indicating *what* call caused the error
- As we *always* "copy" the message, the `copyMsg` arg becomes unused, meaning we can reduce the size of the `intl_error` struct by 4 bytes.
- Saving it as a zend_string means we know the length of the message
- Remove the need to pass around a "function name" `char*` across multiple calls
- Use Intl's exception mechanism to generate exceptions for constructor call
- This removes the need for replacing the error handler
- Which didn't do anything anyway in silent mode, which required throwing non-descriptive exceptions
The objective of this is to stop relying on the fci.function_name zval field,
to see if in the future we can get rid of said field and fit an FCI/FCC pair in a single cache line
In the absence of `PHP_ARG_WITH([opcache],` the value of ext_shared is not
initialized while processing directives of ext/opcache/config.m4, causing
PHP_EVAL_LIBLINE() to add libs to OPCACHE_SHARED_LIBADD instead of LIBS.
Closes GH-19301
We can create the FCI/FCC pair ourself outside of the loop as the method getTraceAsString is final
Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
setpgid accepts values from 0 to "PID_MAX".
for setrlimit the culprit is using zend_long to represent rlim_t
but at least we accept -1 for RLIM_INFINITY, however rl_cur should
not be greater than rl_max value.
close GH-19281
The shadow key is refreshed when resetting the memory manager between two
requests. But in forking SAPIs the first request of a child process inherits the
shadow key of the parent. As a result, a leak of the shadow key during the first
request of one process gives away the shadow key used during the first request
of other processes. This makes the key refresh mechanism less useful.
Here I ensure that we refresh the shadow key after a fork. We can not reset the
manager as there may be active allocations. Instead, we have to recompute shadow
pointers with the new key.
Closes GH-16765
It sets the access log limit as configurable log_limit to allow larger
log limit than the currently fixed limit of 1024 characters.
Fixes GH-12302
Closes GH-18725
Introduced by GH-18541.
This path is hit when compilation fails with a compile error, rather than
bailout. If a non-fatal error is recorded, it will not be emitted nor freed.
Handle accordingly.
https://wiki.php.net/rfc/make_opcache_required removed the --enable-opcache option, and this change creates a problem for the benchmark: the master branch (containing the RFC implementation) cannot use the deprecated options and config anymore, while earlier versions must still use them.
Therefore, the benchmark had to introduce the PHP_OPCACHE=2 config value (3455b34856) to signal that opcache still has to be manually enabled. After the next benchmark run, PHP_OPCACHE for the previous PHP version has to be switched back to "1".
[skip-ci]
pid_t is, for the most part, represented by a signed int, by overflowing
it, we end up being in the -1 case which affect all accessible processes.
close GH-18944
Avoid initializing the same string content multiple times and make use of the
fact that the strings created to initialize attribute values are not freed by
simply making use of an existing zend_string with the same content if one is
available.
When opcache is enabled, error handling is altered in the following ways:
* Errors emitted during compilation bypass the user-defined error handler
* Exceptions emitted during class linking are turned into fatal errors
Changes here make the behavior consistent regardless of opcache being enabled or
not:
* Errors emitted during compilation and class linking are always delayed and
handled after compilation or class linking. During handling, user-defined
error handlers are not bypassed. Fatal errors emitted during compilation or
class linking cause any delayed errors to be handled immediately (without
calling user-defined error handlers, as it would be unsafe).
* Exceptions thrown by user-defined error handlers when handling class linking
error are not promoted to fatal errors anymore and do not prevent linking.
Fixes GH-17422.
Closes GH-18541.
Closes GH-17627.
Co-authored-by: Tim Düsterhus <tim@bastelstu.be>
This removes the --enable-opcache/--disable-opcache configure switch. OPcache
is now always builtin. The default value of opcache.enable and
opcache.enable_cli is unchanged.
RFC: https://wiki.php.net/rfc/make_opcache_required
Closes GH-18961.
Co-authored-by: Tim Düsterhus <tim@tideways-gmbh.com>
We use linker relocations to fetch the TLS index and offset of _tsrm_ls_cache.
When building Opcache statically, linkers may attempt to optimize that into a
more efficient code sequence (relaxing from "General Dynamic" to "Local Exec"
model [1]). Unfortunately, linkers will fail, rather than ignore our
relocations, when they don't recognize the exact code sequence they are
expecting.
This results in errors as reported by GH-15074:
TLS transition from R_X86_64_TLSGD to R_X86_64_GOTTPOFF against
`_tsrm_ls_cache' at 0x12fc3 in section `.text' failed"
Here I take a different approach:
* Emit the exact full code sequence expected by linkers
* Extract the TLS index/offset by inspecting the linked ASM code, rather than
executing it (execution would give us the thread-local address).
* We detect when the code was relaxed, in which case we can extract the TCB
offset instead.
* This is done in a conservative way so that if the linker did something we
didn't expect, we fallback to a safer (but slower) mechanism.
One additional benefit of that is we are now able to use the Local Exec model in
more cases, in JIT'ed code. This makes non-glibc builds faster in these cases.
Closes GH-18939.
Related RFC: https://wiki.php.net/rfc/make_opcache_required.
[1] https://www.akkadia.org/drepper/tls.pdf
This reduces the chances of confusion between opcode handlers used by the
VM, and opcode handler functions used for tracing or debugging. Depending
on the VM, zend_vm_opcode_handler_t may not be a function. For instance in
the HYBRID VM this is a label pointer.
Closes GH-19006
Reduce the number of global functions by moving it to static method
`FileInfo::getFileDocComments()`. Since it is only used by
`FileInfo::parseStubFile()`, also make it private.
This new class holds the logic for applying different flags based on the PHP
version, and replaces `VariableLike::addFlagForVersionsAbove()` (use
`VersionFlags::addForVersionsAbove()`) and `generateVersionDependentFlagCode()`
(use `VersionFlags::generateVersionDependentFlagCode()`).
In preparation for moving this logic to a dedicated class, add support for a
maximum version of PHP in the generation of version-dependent flags. This
replaces the manual logic in `FuncInfo::getFunctionEntry()` to split up the
flags that are used when PHP 8.4 is not supported.
* opcache: Reset `accel_startup_ok` after shutting down
This is necessary for phpdbg, which runs multiple startup/shutdown cycles in
the same process.
* opcache: Disallow changing `opcache.memory_consumption` when SHM is set up
Normally changing the INI value is not possible after SHM is set up, since it
is `PHP_INI_SYSTEM`. FPM is a notable exception: SHM is set up in the master
process, but when spawning the individual pools, the `php_admin_value` config
option can be used to change `PHP_INI_SYSTEM` INIs on a per-pool basis. This
does not work for this option, since it will only be read on early start,
leading to misleading PHPInfo output, since the INI value appears to be
successfully set and since some of the calculated values are derived from the
INI value rather than the actual value.
This function always returned SUCCESS unconditionally; removing the return type
revealed some impossible code for handling FAILURE that could also be removed.
Specifically, it is added to openssl_public_encrypt() and
openssl_private_decrypt() functions. The purpose is to specify digest
algorithm for OEAP padding. It currently defaults to SHA1 for some
OpenSSL versions which is not preferred for modern setup and causes
problems in compatibility with web crypto.
Closes GH-19223
For this benchmark:
```php
$length = 25;
for ($i=0;$i<1000;$i++)
array_chunk(range(0, 10000), $length);
```
On an i7-4790, length=25 speeds up by 1.8x and length=1 by 1.27x.
On an i7-1185G7, length=25 speeds up by 1.08x and length=1 by 1.02x.
Instead of
* adding a zval on the stack
* initializing it
* copying the value to the attribute
Just initialize the value directly in the zend_attribute_arg
This constant can be handy for tools like PIE to determine the origin of a PHP
binary to provide better output / diagnostics.
see php/pie#275
see php/php-src#18168
This implements an SVG handler using the libxml reader API. This does
not parse the entire document but instead uses a pull parser to locate
the root element, check whether it's an svg root, do some extra sanity
checks on the attribute, and fill in the php_gfxinfo structure.
This is modelled similarly to the password registry API.
We have an array to which new handlers can be added, and when a built-in
handler cannot handle the image, we try the handlers in the array.
The standard module is in control of registering a new constant for the
image file type so that no clashes can occur. It also updates the image
file type count constant. As such, the registration may only happen
during module startup.
This is necessary for future commits, when we extend the image handling
to support extensions adding their own handlers.
Also extend the struct with fields for when the width and height are not
numbers but strings (e.g. for SVG).
* uri: Streamline implementation of `uriparser_parse_uri_ex()`
Avoid the use of a macro and streamline the logic.
* uri: Improve exceptions for `Uri\Rfc3986\Uri`
* uri: Allow empty URIs for RFC3986
* NEWS
* uri: Improve ext/uri/tests/004.phpt for empty URIs
Support for attaching arbitrary metadata for consumption by stream notifier
functions got broken in php/php-src#19024 when the previous `zval ptr` got
changed to `zend_fcall_info_cache *fcc`, making the data specific to the
`user_space_stream_notifier`.
Fix this by changing the field to `void *ptr`, avoiding the indirection through
a `zval`, but preserving the ability to store arbitrary data. If necessary to
support different types than `IS_PTR`, extensions can heap-allocate a `zval` to
store within `->ptr` as a minimal change to keep compatibility with PHP 8.4 or
lower.
This patch adds support for the CURLINFO_QUEUE_TIME_T constant in the
curl_getinfo() function when compiled with libcurl >= 8.6.0.
CURLINFO_QUEUE_TIME_T This constant allows retrieving the time (in
microseconds) that the request spent in libcurl’s connection queue
before it was sent.
We previously changed the lineno of the property to the cpp argument, but now
also update the lineno for RECV and ASSIGN_OBJ. No test because we don't have a
way to enable lineno's in the opcode dump, and this is not easily testable
through error messages.
This patch adds support for the CURLINFO_CONN_ID constant in the curl_getinfo() function when compiled with libcurl >= 8.2.0.
CURLINFO_CONN_ID allows retrieving the unique identifier of the underlying connection used in the most recent transfer. This is useful for advanced features like connection reuse tracking, diagnostics, or connection pooling implementations at the PHP level.
The following changes are cherry-picked:
- c60846689d core/str.c: Fix undefined behavior in function lexbor_str_append
- 92260fd670 URL: fixed hostname setter if port is specified.
- When building with bundled libgd, it has support for BMP
- When building with external libgd, at least 2.1.0 is required, which
has BMP support.
- The HAVE_GD_PNG moved to PHP_GD_PNG Autoconf macro as it is always
required when building with bundled libgd.
Pipe compilation uses a temporary znode with QM_ASSIGN to remove
references. Assert compilation wants to look at the operand AST and
convert it to a string. However the original AST is lost due to the
temporary znode. To solve this we either have to handle this specially
in pipe compilation [1], or store the AST anyway somehow.
Special casing this either way is not worth the complexity in my
opinion, especially as it looks like a dynamic call anyway due to the
FCC syntax.
[1] Prototype (incomplete) at
https://gist.github.com/nielsdos/50dc71718639c3af05db84a4dea6eb71
shows this is not worthwhile in my opinion.
Closes GH-18965.
Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
This never worked and creates a broken object,
and on master can cause a crash with foreach.
It makes no sense to fix a behaviour that never worked, block it
instead.
Closes GH-19089.
* PHP-8.4:
Update NEWS for GH-19068
ext/gd: Drop useless and doubtful MSVC specific code (libgd/libgd@f1480ab)
Zend: fix undefined symbol 'execute_ex' on Windows ARM64 #19064; ext/gd: fix emmintrin.h not found on Windows ARM64
* pdo_odbc: Don't fetch 256 byte blocks for long columns
Fetching 256 byte blocks can confuse some drivers with conversion
routines. That, and it seems to me the round trips to and from a
database could be a major performance impact.
Instead, we try to fetch all at once, and continue fetching if a
driver somehow has more for us.
This has been tested with a problematic case with the Db2i driver
with stateful MBCS encodings.
See GH-10733 for discussion about this and issues it can resolve.
* change to separate by 256 bytes, when C->fetched_len == SQL_NO_TOTAL
change to separate by 256 bytes, when C->fetched_len == SQL_NO_TOTAL
changed from 256 byte to 2048 byte buf block.
* Make long column buffer size single define
Could be configurable maybe, but best to avoid magic numbers even for a
compile-time constant.
* Use ZendMM page size minus zend_string overhead
Change recommended by Christoph.
Probably a little better performance wise I have to guess.
* [skip ci] Update comment to mention constant
* Update UPGRADING for PDO_ODBC change
mention GH issues in UPGRADING too
* Update NEWS for PDO_ODBC change
---------
Co-authored-by: SakiTakamachi <saki@sakiot.com>
This is a macro defined in stddef, which is already included in this
header. Since this is a macro, we can just check for the define rather
than add any additional build system checks.
Fixes GH-18975
Instead of using lookup tables, we can use a combination of shifts and
byte swapping to achieve the same thing in less cycles and with less
code.
Benchmark files
---------------
pack1.php:
```php
for ($i = 0; $i < 10_000_000; ++$i) {
pack("J", 0x7FFFFFFFFFFFFFFF);
}
```
pack2.php:
```php
for ($i = 0; $i < 4000000; ++$i) {
pack("nvc*", 0x1234, 0x5678, 65, 66);
}
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php pack1.php
Time (mean ± σ): 408.8 ms ± 3.4 ms [User: 406.1 ms, System: 1.6 ms]
Range (min … max): 403.6 ms … 413.6 ms 10 runs
Benchmark 2: ./sapi/cli/php_old pack1.php
Time (mean ± σ): 451.7 ms ± 7.7 ms [User: 448.5 ms, System: 2.0 ms]
Range (min … max): 442.8 ms … 461.2 ms 10 runs
Summary
./sapi/cli/php pack1.php ran
1.11 ± 0.02 times faster than ./sapi/cli/php_old pack1.php
Benchmark 1: ./sapi/cli/php pack2.php
Time (mean ± σ): 239.3 ms ± 6.0 ms [User: 236.2 ms, System: 2.3 ms]
Range (min … max): 233.2 ms … 256.8 ms 12 runs
Benchmark 2: ./sapi/cli/php_old pack2.php
Time (mean ± σ): 271.9 ms ± 3.3 ms [User: 269.7 ms, System: 1.3 ms]
Range (min … max): 267.4 ms … 279.0 ms 11 runs
Summary
./sapi/cli/php pack2.php ran
1.14 ± 0.03 times faster than ./sapi/cli/php_old pack2.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php pack1.php
Time (mean ± σ): 263.7 ms ± 1.8 ms [User: 262.6 ms, System: 0.9 ms]
Range (min … max): 261.5 ms … 268.2 ms 11 runs
Benchmark 2: ./sapi/cli/php_old pack1.php
Time (mean ± σ): 303.3 ms ± 6.5 ms [User: 300.7 ms, System: 2.3 ms]
Range (min … max): 297.4 ms … 318.1 ms 10 runs
Summary
./sapi/cli/php pack1.php ran
1.15 ± 0.03 times faster than ./sapi/cli/php_old pack1.php
Benchmark 1: ./sapi/cli/php pack2.php
Time (mean ± σ): 156.7 ms ± 2.9 ms [User: 154.7 ms, System: 1.7 ms]
Range (min … max): 151.6 ms … 164.7 ms 19 runs
Benchmark 2: ./sapi/cli/php_old pack2.php
Time (mean ± σ): 174.6 ms ± 3.3 ms [User: 171.9 ms, System: 2.3 ms]
Range (min … max): 170.7 ms … 180.4 ms 17 runs
Summary
./sapi/cli/php pack2.php ran
1.11 ± 0.03 times faster than ./sapi/cli/php_old pack2.php
```
Closes GH-18524.
Co-authored-by: divinity76 <divinity76@gmail.com>
Have each of the specialized methods for registering a constant return a
pointer to the registered constant the same way that the generic
`zend_register_constant()` function does, and use those in the generated
arginfo files to avoid needing to search for a constant that was just
registered in order to add attributes to it.
Since `ZSTR_LEN()` returns a `size_t` (unsigned integer), the value can only be either "not equal to 0" or "equal to 0". The third `else` branch was unreachable, making the `*handled_output = NULL;` assignment dead code.
The `defaultMemoryManager` is only available via a non-public
header and is not supposed to be used by users of the library [1].
It also has a very generic name, further indicating that it is not
supposed to be used.
Instead pass the memory manager explicitly, which is how the library is
supposed to be used.
[1] https://github.com/uriparser/uriparser/issues/52#issuecomment-453853700
Relates to #14461 and https://wiki.php.net/rfc/url_parsing_api
Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Co-authored-by: Tim Düsterhus <tim@tideways-gmbh.com>
The code is already looking up the entry in the function table anyway,
so might as well use it directly.
This simplifies the code and avoids a redundant lookup.
This returns the usual `{closure:FILE_NAME/FUNCTION:LINE_NO}` for anonymous functions rather than `Closure::__invoke` this is visible for `is_callable()` and any Engine call that uses `zend_fcall_info_init()` to get the name of the callable.
Related to GH-18063.
* PHP-8.4:
Fix GH-18990, bug #81029, bug #47314: SOAP HTTP socket not closing on object destruction
Fix leak when path is too long in ZipArchive::extractTo()
curl: Remove incorrect string release on error
`zend_enum_new()` is not intended to be used “at runtime”, since it will create
a new object, breaking the singleton property. Instead
`zend_enum_get_case_cstr()` must be used.
* Clarify that placeholders with `RCn` are not just for release candidates
* Only PHP `X.Y.0` has pre-GA releases, no need to use `X.Y.Z`
* Before `PHP-X.Y` has been created, `master` needs to be pushed for NEWS
The ssize_t type is already used unconditionally in php-src code
everywhere except the main/s{n,p}printf.c files. On Windows ssize_t is
available as an alias to the SSIZE_T defined in BaseTsd.h (available in
affected files through the included windows.h in zend_config.w32.h).
This also makes the Autoconf macro PHP_CHECK_SIZEOF obsolete in favor of
the AC_CHECK_SIZEOF, which is more convenient to check for types without
the need to run the test program - omitting the cross-compilation
issues. AC_CHECK_SIZEOF once didn't provide including additional headers
(resolved in Autoconf versions after 2.13).
Update based on my training with Pierrick
* dates should correspond to when releases are released, not tagged
* qa.php.net is no longer used
* bugs.php.net is no longer used
* multiple commits to web-php can be combined
* PHP-8.4:
PHP-8.2 is now for PHP 8.2.30-dev
Update NEWS with entries for security fixes
Fix GHSA-453j-q27h-5p8x
Fix GHSA-hrwm-9436-5mv3: pgsql escaping no error checks
Fix GHSA-3cr5-j632-f35r: Null byte in hostnames
* zend_language_parser: Support every argument syntax for `clone()`
* zend_language_parser: Adjust `clone()` grammar to avoid conflicts
* zend_language_parser: Add explanatory comment for `clone_argument_list`
Registering the constant may happen under another name due to
lowercasing. This will cause the lookup to the constant to fail.
Instead of looking it up, just change the Zend API to return a pointer
instead.
Current minimum PCRE2 library in PHP is 10.30 (with bundled 10.45) and
none of these versions use PCRE_STATIC macro anymore in favor of
PCRE2_STATIC, which is defined in the generated config.w32.h on Windows.
The intmax_t is a C99 standard type defined in `<stdint.h>` and widely
available on current platforms. On Windows they are available as of
Visual Studio 2013. Using it conditionally as in these occurrences is
not needed anymore.
The ptrdiff_t is a C89 standard type defined in `<stddef.h>` and widely
available on current platforms. Using it conditionally as in these
occurrences is not needed anymore.
ParentNode::$children returns a HTMLCollection of all directly
descendant child elements of a container.
I had to move around some properties such that the ParentNode property
offsets are always at a fixed offset, to simplify the code.
This also adds the necessary code to deal with GC cycles in
HTMLCollections.
Furthermore, we also disable cloning a HTMLCollection as that never
worked and furthermore it also conflicts with the [[SameObject]] WebIDL
requirement of $children.
Only covers constants declared via stub files, others will be handled
separately in a later commit.
Does not include the intl extension, since that had some errors relating to the
cpp code; that extension will be updated separately.
This functionality is not part of the POSIX interface.
- On FreeBSD, the wait6 system call provides it
- On Linux, the raw waitid system call provides it (glibc does not)
close GH-15921
Like in other languages, and especially C where printf originates from,
a missing precision should be treated as a 0 precision.
Because the ADJ_PRECISION flag was not set, the double formatting code
resetted the precision to the default float precision of 6.
* php_gdb: Print `zend_string*`’s `h` field as hexadecimal
A decimal representation of a hash value is not particularly meaningful and
makes it harder to compare hash values.
* php_gdb: Print `HashTable*`’s `nTableMask` field as hexadecimal
Prior to this commit the exit code of the sendmail command, called by
the mail function was lost, since the mail function only returns true or
false. Add additional logging to the mail function to capture the exit
code when the sendmail command fails.
Prior to this commit the return code of the pclose function was assumed
to be the exit code of the process. However, the returned value as
specified in wait(2) is a bit packed integer and must be interpreted
with the provided macros. This has no effect in success cases as the
integer is still zero, but in failure cases the wrong value is used,
since the 8 least significant bits contain the status code. After this
commit we use the macros to obtain the status code, which fixes the
EX_TEMPFAIL conditional.
For WIN32 the TSRM popen_ex and pclose function are used. The return
value of TSRM's pclose is not bit packed so we only check if the return
value is non-zero, which should solve, #43327,
https://bugs.php.net/bug.php?id=43327
No need to manually init a `zend_string` to then intern it, we can directly
intern it while initializing, bypassing some of the safety checks that are
redundant in this case.
These Autoconf macros have been marked as obsolete in PHP-8.4 and now
also removed:
- PHP_AP_EXTRACT_VERSION
- PHP_BUILD_THREAD_SAFE
- PHP_DEF_HAVE
- PHP_OUTPUT
- PHP_TEST_BUILD
DL_LOAD now doesn't use RTLD_DEEPBIND deepbind anymore on platforms
where dlmopen with LM_ID_NEWLM is available:
this means shared library symbol isolation (if needed) must be enabled on
the user side when requiring libphp.so, by using dlmopen with LM_ID_NEWLM
instead of dlopen.
RTLD_DEEPBIND is still enabled when the Apache SAPI is in use.
Closes GH-10670.
similar to what have been done for pdo/sqlite as having statement
explain support to simulate how a query would operate or
for more advanced users, analysing the VM routines used
for possible optimisations.
close GH-18853
When global constants' or class constants' availability is based on some
preprocessor condition, the generated arginfo header files wrap the
declarations in the preprocessor `#if` conditional blocks, one per declaration,
even if they are in the same conditional block based on comments in the stub
file. Instead of having multiple conditional blocks one after the other with
the same condition, combine them into a single conditional block.
When system is detected as big endian this enables the TSRM Local
Storage static cache with the ZEND_ENABLE_STATIC_TSRMLS_CACHE
compilation flag. Previously it was enabled only on little endian
systems.
The /d2FuncCache1 compile option is already added by
toolset_setup_common_cflags() in confutils.js to all targets.
ZEND_DVAL_TO_LVAL_CAST_OK was removed in
3725717de1.
The code was really messy with lots of checks and inconsistencies.
This splits everything up into different functions and now everything is
relayed to a handler vtable.
- Use INI sections
- Use CGI sections
- Move data into a subfolder
- Remove ZPP tests
- Fix various bugs within tests
- Simplify some
Found while working on #18879
The pcre2 library still needs HAVE_MEMMOVE defined to use the system
(C99 standard) memmove() function, otherwise emulation is used. On
Windows, this is already enabled.
The PHP_ODBC_* defines are remains of the PHP 2 and 3 era where the ODBC
functionality was part of the PHP core and was later moved to an
extension. This moves these defines to a regular PHP configuration
header (php_config.h) as done in other extensions.
PHP once had getlogin() emulation implemented on Windows. This isn't the
case anymore since 2006 (dc34d34230),
neither Windows has getlogin() function.
This test breaks under file cache (because the opcodes are not dumped when ran
with a primed cache). run-tests.php --file-cache-* automatically skips all
ext/opcache tests, so move it there.
The strings we encounter are either interned in which case the
persistent bool doesn't matter; or they're temporary as the code already
assumes that anyway.
This patch shrinks the function from 3332 bytes to 3173 bytes on x86-64
with GCC 15.1.1.
If s is not NULL, the length can't be <= 0 because we at least append
`spkac` in the string, which is non-empty.
I noticed this condition because if it were actually possible to
execute, then it would leak memory.
We can avoid creating temporary strings, and then reparsing them into
numbers with zend_symtable_update() by using zend_hash_index_update()
directly.
For the following benchmark on an i7-4790:
```php
$file = str_repeat('A', 100000);
for ($i=0;$i<100;$i++) unpack('C*',$file);
```
I get:
```
Benchmark 1: ./sapi/cli/php y.php
Time (mean ± σ): 85.8 ms ± 1.8 ms [User: 74.5 ms, System: 10.4 ms]
Range (min … max): 83.8 ms … 92.4 ms 33 runs
Benchmark 2: ./sapi/cli/php_old y.php
Time (mean ± σ): 318.3 ms ± 2.7 ms [User: 306.7 ms, System: 9.9 ms]
Range (min … max): 314.9 ms … 321.6 ms 10 runs
Summary
./sapi/cli/php y.php ran
3.71 ± 0.08 times faster than ./sapi/cli/php_old y.php
```
On an i7-1185G7 I get:
```
Benchmark 1: ./sapi/cli/php test.php
Time (mean ± σ): 60.1 ms ± 0.7 ms [User: 47.8 ms, System: 12.0 ms]
Range (min … max): 59.2 ms … 63.8 ms 48 runs
Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
Benchmark 2: ./sapi/cli/php_old test.php
Time (mean ± σ): 220.8 ms ± 2.2 ms [User: 209.6 ms, System: 10.7 ms]
Range (min … max): 218.5 ms … 224.5 ms 13 runs
Summary
./sapi/cli/php test.php ran
3.67 ± 0.06 times faster than ./sapi/cli/php_old test.php
```
INTERNAL_FUNCTION_PARAMETERS is defined in zend.h, but not included in
zend_exceptions.h (and it shouldn't). Expand the macro to fix the
compile issue.
It's possible to return a reference from __toString(), but this is not
handled and results in a (confusing) error telling that the return value
must be a string.
Properly handle this by unwrapping the reference.
Closes GH-18810.
This allows a cheaper exception check and also does not need a release
call.
This shrinks concat_function() on x86-64 with GCC 15.1.1 from 3443 bytes
to 3332 bytes.
Relates to #14461 and https://wiki.php.net/rfc/url_parsing_api
Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Co-authored-by: Tim Düsterhus <tim@tideways-gmbh.com>
Co-authored-by: Gina Peter Banyard <girgias@php.net>
Co-authored-by: Arnaud Le Blanc <arnaud.lb@gmail.com>
Co-authored-by: Tim Düsterhus <tim@tideways-gmbh.com>
Currently, this fails because the type is IS_REFERENCE instead of
IS_ARRAY, but this could be confusing because a function return value is
normally dereferenced automatically in a lot of cases.
Closes GH-18762.
* PHP-8.4:
pdo_odbc: Fix memory leak if WideCharToMultiByte() fails
Fix memory leak on php_odbc_fetch_hash() failure
Do not delete main chunk in zend_gc
Update to PHP-Parser 5.5.0 and add support for attributes on constants in
stubs. For now, I have only migrated over E_STRICT, once the support is in
place I'll do a larger migration of the existing deprecated constants.
In the process, fix the logic in `copy_zend_constant()` for copying attributes
when a constant is copied; just increase the reference count for the attributes
table rather than trying to duplicate the contents.
This is in preparation for the possible future transformation of `clone` into a
function call, but also meaningful on its own, since the purpose of the tests
is not to test the stack trace generation, but rather that an exception was
thrown. It also cleans up some unreachable code in the tests.
Checking the non-exception path without arguments first, this avoids a redundant check in the case without arguments. The exception path may become more expensive, but we don't optimize for exception flow, rather we optimize for the happy flow. The other paths are unaffected.
The library requires the tags to be non-empty, and also requires the
ordering to be non-empty. For the tags, otherwise, assertion failures
can be observed.
Closes GH-18733.
- Property hooks may now throw exceptions, that seem to be forgotten to be handled by https://github.com/php/php-src/pull/18442
- The $previous and $trace properties are private, and they were not accessible from the constructor of a child class
This was originally introduced as a workaround for a libxml2 bug [1].
This bug has been fixed for more than a decade [2], and we can use the
libxml2 API again. We bumped our version requirement for libxml2 beyond
that in 7.4 [3].
[1] 7e53511ec8
[2] 3ffe90ea1c
[3] 74235ca5f3
Closes GH-18706.
* Deduplicate XML parsing code for SOAP
* Apply suggestions from code review
Co-authored-by: Gina Peter Banyard <girgias@php.net>
---------
Co-authored-by: Gina Peter Banyard <girgias@php.net>
`attr_is_equal_ex` makes no sense: attributes never inherit the
namespace of their element. Yet this is wrongly used as a combo for
checking both the node namespace and attribute namespace.
Furthermore, not all nodes have the proper namespace check.
Fix all of this by reworking the helpers and auditing the calls to the
namespace helpers.
Closes GH-16320.
Closes bug #68576.
Closes GH-18697.
This fixes checks when building shared ldap library, or when ldap
installation directory is passed as argument:
./configure --with-ldap=shared
./configure --with-ldap=/path/to/ldap
./configure --with-ldap=shared,/path/to/ldap
Starting with gcc 15 the warning `-Wunterminated-string-initialization`
is enabled by default. We make now use of the `nonstring` attribute to
silence the warning for the cases where this is intended.
Closes GH-18603.
An always enabled lexbor extension is added, containing the lexbor library that was separated from ext/dom extension in preparation of https://wiki.php.net/rfc/url_parsing_api. While at it, the lexbor library is upgraded to 2.5.0.
Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Co-authored-by: Gina Peter Banyard <girgias@php.net>
Introduces intl_convert_utf8_to_utf16_zstr() to convert a UTF-8 string
to a UTF-16 string zend_string* instance. This way we avoid a double
copy later from a UChar* into a zend_string*.
This aligns the behaviour with normal (non-intl) asort() by making the following changes:
- Use the same trailing whitespace logic as Zend's is_numeric_ex()
- Don't allow errors on trailing data
Targeting master because of the BC break.
Closes GH-18632.
UDP segmentation offload is an optimisation attempt by sending multiple
large enough datagrams over UDP which reduces syscalls as by default,
they have to be broke down in small UDP packets, it is better if the
hardware supports it, other handed down to the software implementation.
close GH-18213
This avoids temporary allocations and some copies.
For this benchmark:
```php
for ($i=0;$i<2000000;$i++) {
http_build_query([999999 => 'foo', 'aaab' => 'def', 'aaaaa'=>1, 'aaaaaaaa' => 'a']);
}
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php ../buildquery.php
Time (mean ± σ): 298.9 ms ± 7.3 ms [User: 295.6 ms, System: 2.3 ms]
Range (min … max): 293.6 ms … 314.0 ms 10 runs
Benchmark 2: ./sapi/cli/php_old ../buildquery.php
Time (mean ± σ): 594.8 ms ± 8.6 ms [User: 590.8 ms, System: 2.4 ms]
Range (min … max): 586.3 ms … 616.1 ms 10 runs
Summary
./sapi/cli/php ../buildquery.php ran
1.99 ± 0.06 times faster than ./sapi/cli/php_old ../buildquery.php
```
For this benchmark:
```php
for ($i=0;$i<2000000;$i++) {
http_build_query(['test' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']);
}
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php ../buildquery.php
Time (mean ± σ): 188.4 ms ± 6.7 ms [User: 184.6 ms, System: 2.9 ms]
Range (min … max): 182.0 ms … 205.4 ms 14 runs
Benchmark 2: ./sapi/cli/php_old ../buildquery.php
Time (mean ± σ): 323.9 ms ± 8.7 ms [User: 319.8 ms, System: 2.7 ms]
Range (min … max): 318.0 ms … 341.2 ms 10 runs
Summary
./sapi/cli/php ../buildquery.php ran
1.72 ± 0.08 times faster than ./sapi/cli/php_old ../buildquery.php
```
This allows us to avoid a call to `zend_ini_str` which took 6% of the
profile on my i7-4790 for a call to `http_build_query`. Now we can just
grab the value from the globals.
In other files this can avoid some length recomputations.
* Move glob to main/ from win32/
In preparation to make the Win32 reimplementation the standard
cross-platform one. Currently, it doesn't do that and just passes
through the original glob implementation. We could consider also having
an option to use the standard glob for systems that have a sufficient
one.
* Enable building with win32 glob on non-windows
Kind of broken. We're namespacing the function and struct, but not yet
the GLOB_* defines. There are a lot of places callers check if i.e.
NOMATCH is defined that would likely become redundant.
Currently it also has php_glob and #defines glob php_glob (etc.) - I
suspect doing the opposite and changing the callers would make more
sense, just doing MVP to geet it to build (even if it fails tests).
* Massive first pass at conversion to internal glob
Have not tested yet. the big things are:
- Should be invisible to userland PHP code.
- A lot of :%s/GLOB_/PHP_GLOB_/g; the diff can be noisy as a result,
especially in comments.
- Prefixes everything with PHP_ to avoid conflicts with system glob in
case it gets included transitively.
- A lot of weird shared definitions that were sprawled out to other
headers are now included in php_glob.h.
- A lot of (but not yet all cases) of HAVE_GLOB are removed, since we
can always fall back to php_glob.
- Using the system glob is not wired up yet; it'll need more shim
ifdefs for each flag type than just glob_t/glob/globfree defs.
* Fix inclusion of GLOB_ONLYDIR
This is a GNU extension, but we don't need to implement it, as the GNU
implementation is flawed enough that callers have to manually filter it
anyways; just provide a stub definition for the constant.
We could consideer implementing this properly later. For now, fixes the
basic glob constant tests.
* Remove HAVE_GLOBs
We now always have a glob implementation that works. HAVE_GLOB should
only be used to check if we have a system implementation, for if we
decide to wrap the system implementation instead.
* We don't need to care about being POSIXly correct for internal glob
* Check for reallocarray
Ideally temporary until GH-17433.
* Forgot to move this file from win32/ to main/
* Check for issetugid (BSD function)
* Allow using the system glob with --enable-system-glob
* Style fix after removing ifdef
* Remove empty case for system glob
The class structure is fixed, so it makes no sense to go through all the
logic of looking up property info etc if there are no hooks.
This patch introduces a local function `zend_update_property_num_checked()` to
help with that.
For this benchmark:
```php
for ($i = 0; $i < 1000000; $i++)
new Error;
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 141.6 ms ± 9.3 ms [User: 138.7 ms, System: 2.0 ms]
Range (min … max): 135.4 ms … 177.7 ms 20 runs
Benchmark 2: ../RELx64_old/sapi/cli/php x.php
Time (mean ± σ): 214.1 ms ± 7.0 ms [User: 207.6 ms, System: 5.0 ms]
Range (min … max): 206.6 ms … 230.9 ms 13 runs
Summary
./sapi/cli/php x.php ran
1.51 ± 0.11 times faster than ../RELx64_old/sapi/cli/php x.php
```
For this benchmark:
```php
for ($i = 0; $i < 1000000; $i++)
new Exception("message", 0, null);
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 184.3 ms ± 9.5 ms [User: 181.2 ms, System: 1.8 ms]
Range (min … max): 173.8 ms … 205.1 ms 15 runs
Benchmark 2: ../RELx64_old/sapi/cli/php x.php
Time (mean ± σ): 253.7 ms ± 7.0 ms [User: 247.6 ms, System: 4.6 ms]
Range (min … max): 245.7 ms … 263.7 ms 11 runs
Summary
./sapi/cli/php x.php ran
1.38 ± 0.08 times faster than ../RELx64_old/sapi/cli/php x.php
```
For this benchmark:
```php
for ($i = 0; $i < 1000000; $i++)
new ErrorException("message", 0, 0, "xyz", 0, null);
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 223.6 ms ± 7.7 ms [User: 220.1 ms, System: 2.4 ms]
Range (min … max): 216.9 ms … 242.5 ms 12 runs
Benchmark 2: ../RELx64_old/sapi/cli/php x.php
Time (mean ± σ): 343.5 ms ± 8.1 ms [User: 337.1 ms, System: 4.6 ms]
Range (min … max): 337.3 ms … 362.8 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.54 ± 0.06 times faster than ../RELx64_old/sapi/cli/php x.php
```
JIT'ed ASSIGN_OBJ expressions will exit to VM when the prop is undef. However,
in a constructor it's very likely the case. Therefore most traces with `new`
expressions will exit to VM.
Here I ensure that we don't need to exit to VM when it's likely that the
prop will be undef.
In the function JIT we compile a slow path to handle such properties,
but not in the tracing JIT, assumingly to reduce code size. Here I enable
compilation of the slow path in the tracing JIT when it's likely the prop
will be undef. Quite conveniently we already record the prop type during
tracing, so I use that to make the decision.
This results in a 1.20% wall time improvement on the symfony demo benchmark
with 20 warmup requests.
Closes GH-18576
Loops whose number of iterations + 1 is a factor of opcache.jit_hot_loop
will always be traced at the exact moment the loop condition evaluates
to false. As a result, these loops can never be JIT'ed successfully.
Here I adjust the default value of opcache.jit_hot_loop to a prime number,
so this can not happen (unless number of iterations+1 is opcache.jit_hot_loop).
Closes GH-18573
* zend_vm: Add OPcode specialization for `=== []`
Checking whether an array is empty with a strict comparison against the empty
array is a common pattern in PHP. A GitHub search for `"=== []" language:PHP`
reveals 44k hits. From the set of `!$a`, `count($a) === 0`, `empty($a)` and
`$a === []` it however is also the slowest option.
A test script:
<?php
$variable = array_fill(0, 10, random_int(1, 2));
$f = true;
for ($i = 0; $i < 50_000_000; $i++) {
$isEmpty = $variable === [];
$f = $f && $isEmpty;
}
var_dump($f);
with the `$isEmpty = …;` statement appropriately replaced results in:
Benchmark 1: sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 count.php
Time (mean ± σ): 467.6 ms ± 2.3 ms [User: 463.3 ms, System: 3.4 ms]
Range (min … max): 464.6 ms … 473.4 ms 10 runs
Benchmark 2: sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 empty.php
Time (mean ± σ): 305.3 ms ± 0.3 ms [User: 302.0 ms, System: 3.1 ms]
Range (min … max): 304.9 ms … 305.7 ms 10 runs
Benchmark 3: sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 identical.php
Time (mean ± σ): 630.3 ms ± 3.9 ms [User: 624.8 ms, System: 3.8 ms]
Range (min … max): 627.4 ms … 637.6 ms 10 runs
Benchmark 4: sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 not.php
Time (mean ± σ): 311.8 ms ± 3.4 ms [User: 307.9 ms, System: 3.6 ms]
Range (min … max): 308.7 ms … 320.7 ms 10 runs
Summary
sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 empty.php ran
1.02 ± 0.01 times faster than sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 not.php
1.53 ± 0.01 times faster than sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 count.php
2.06 ± 0.01 times faster than sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 identical.php
This patch adds another OPcode specialization for `ZEND_IS_IDENTICAL` that
specifically matches a comparison against the empty array. With this
specialization the `=== []` check becomes the fastest of them all, which is not
surprising given how specific it is:
Benchmark 1: sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 count.php
Time (mean ± σ): 384.1 ms ± 2.3 ms [User: 379.3 ms, System: 3.8 ms]
Range (min … max): 382.2 ms … 389.8 ms 10 runs
Benchmark 2: sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 empty.php
Time (mean ± σ): 305.8 ms ± 3.2 ms [User: 301.7 ms, System: 3.8 ms]
Range (min … max): 304.4 ms … 314.9 ms 10 runs
Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
Benchmark 3: sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 identical.php
Time (mean ± σ): 293.9 ms ± 2.9 ms [User: 289.7 ms, System: 3.3 ms]
Range (min … max): 291.5 ms … 299.4 ms 10 runs
Benchmark 4: sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 not.php
Time (mean ± σ): 306.8 ms ± 0.4 ms [User: 303.8 ms, System: 2.7 ms]
Range (min … max): 306.3 ms … 307.3 ms 10 runs
Summary
sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 identical.php ran
1.04 ± 0.01 times faster than sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 empty.php
1.04 ± 0.01 times faster than sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 not.php
1.31 ± 0.02 times faster than sapi/cli/php -d zend_extension=modules/opcache.so -d opcache.enable_cli=1 count.php
As a follow-up optimization it might be possible to transform the other
emptiness checks, such as `count($arr) === 0` into `$arr === []` if `$arr` is
known to be `MAY_BE_ARRAY` only.
* zend_vm: Add OPcode specialization for `!== []`
* UPGRADING
In #18527, I accidentally swapped the values. This is before my modification:
```
zend_printf("Configuration File (php.ini) Path: %s\n", PHP_CONFIG_FILE_PATH);
zend_printf("Loaded Configuration File: %s\n", php_ini_opened_path ? php_ini_opened_path : "(none)");
zend_printf("Scan for additional .ini files in: %s\n", php_ini_scanned_path ? php_ini_scanned_path : "(none)");
```
- "Loaded Configuration File" should be `php_ini_opened_path`
- "Scan for additional .ini files in" shoudl be `php_ini_scanned_path`
The parser accepted invalid code: consts are only valid at the top
level, but because GH-16952 changed the grammar it was incorrectly
allowed at all places that allowed attributed statements.
Fix this by introducing a variant of attributed_statement for the top
level.
This function is unused and trivially replaced by `php_format_date()` (which is
already used to format date headers in the CLI server and ext/session). Remove
it to slim down the codebase, allowing to remove an entire header (and a source
file once the deprecated `strptime()` userland function is removed).
When a config var has whitespace (especially trailing whitespace) it is hard to see. This commit wraps the values (if they exist) in double quotes, so the difference is visually observable:
Before:
```
$ export PHP_INI_SCAN_DIR="/opt/homebrew/etc/php/8.4/conf.d "
$ ./sapi/cli/php --ini
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File: /opt/homebrew/etc/php/8.4/conf.d
Scan for additional .ini files in: (none)
Additional .ini files parsed: (none)
```
> Note
> The above output has trailing whitespace that is not visible, you can see it if you copy it into an editor:
After:
```
$ ./sapi/cli/php --ini
Configuration File (php.ini) Path: "/usr/local/lib"
Loaded Configuration File: "/opt/homebrew/etc/php/8.4/conf.d "
Scan for additional .ini files in: (none)
Additional .ini files parsed: (none)
```
Above the whitespace is now visible `/opt/homebrew/etc/php/8.4/conf.d `.
Close#18390
Reduce the number of global functions by moving it to static method
`FileInfo::parseStubFile()`. Additionally, make `FileInfo::handleStatements()`
private now that the only caller is part of the class.
The following properties are made private:
* `ArgInfo::$phpDocType`
* `ClassInfo::$flags`, `::$attributes`, `::$extends`, `::$implements`
* `FileInfo::$isUndocumentable`
The following are made protected:
* `VariableLike::$flags`
Separate out the creation of a legacy version of a FileInfo object, which has
information for old versions of PHP discarded, from its subsequent use in
`processStubFile()`.
In the process, make `FileInfo::$legacyArginfoGeneration` private, and inline
the single use of `FileInfo::getAllClassInfos()`, removing that method.
For a lot of the structures, the parsing of doc comment tags is based on if a
specific tag is present, or the value that it has if it is. Add a new helper
method, `DocCommentTag::makeTagMap()`, that turns an array of tag instances
into a map from tag name to value (the last value, if there are multiple uses
of the same tag name). Then, for the simple cases where just a tag's presence
is all that is checked, or just the (last) value is used, check the map instead
of using a loop through all of the tags present.
Reduce the number of global functions by moving it to static method
`FileInfo::handlePreprocessorConditions()`. Since it is only used by
`FileInfo::handleStatements()`, also make it private.
* Use `@param` instead of `@var` for parameters
* Fix type of `$attributeGroups` in `AttributeInfo::createFromGroups()`
* Remove extra documentation of `$allConstInfo` for
`ClassInfo::getClassSynopsisDocument()`, it is already documented under the
correct name `$allConstInfos`
* Remove unneeded `@throws`
The following parameters were either unused before this commit or became unused
as part of updating callers to stop passing unused parameters to other
functions updated in this commit:
* `FuncInfo::getMethodSynopsisDocument()` - `$funcMap`, `$aliasMap`
* `FuncInfo::getMethodSynopsisElement()` - `$funcMap`, `$aliasMap`
* `ConstInfo::getGlobalConstDeclaration()` - `$allConstInfos`
* `generateMethodSynopses()` - `$aliasMap`
* `replaceMethodSynopses()` - `$aliasMap`
Reduce the number of global functions by moving it to instance method
`FuncInfo::toArgInfoCode()`.
In the process, make `FuncInfo::$numRequiredArgs` private.
The vast majority of the decisions about the use of `ZEND_BEGIN_ARG_INFO_EX` or
one of its variations are based on the return information of the function - is
the type builtin, is the return information tentative, does it include an
object mask, etc. Accordingly, move the logic into the `ReturnInfo` class.
The logic is actually moved into two methods, `ReturnInfo::beginArgInfo()`,
which needs to handle the case of tentative returns being used when PHP < 8.1
is supported, and `::beginArgInfoCompatible()`, which can assume that PHP 8.1+
is supported and thus make use of early returns and guard clauses. Further
improvements to the logic will be made in a subsequent commit.
In the process, make `ReturnInfo::$byRef` private.
There is no need to add special handling for the default value of `null`, since
it is not loosely-equals to any of the strings 'UNKNOWN', 'false', 'true', or
'null' it will just be returned directly anyway.
* Return a string rather than an array, all callers just immediately used
`implode()` to join the elements in the array with nothing between them
* In the callers, inline some single-use variables with the template for the
version-dependent code
* Remove the callback to `array_filter` specifying that only items that are not
`empty()` be removed - this is the default behavior
Deduplicates the setting up of the `zend_string_init_interned()` call, removes
the need for `ExposedDocComment::getLength()` and so that method is removed.
On x86-64 with GCC 14.2.1:
zim_Random_Randomizer_getBytes goes from 514 to 418 bytes
zim_Random_Randomizer_getBytesFromString goes from 750 to 676 bytes
This function can be static, and the error checks are pointless:
1. It's guaranteed that the return value is an array by now,
as it is always preceded by array_init(return_value).
2. The null check for g is pointless as every callee already
handles that in a better way.
This function can be static, and the error checks are pointless:
1. It's guaranteed that the return value is an array by now, as it is
always preceded by array_init(return_value).
2. The null check for pw is pointless as every callee already handles
that in a better way.
from a minimized locale, addLikelySubtags augments it with likely
subtags so no changes is the locale is already maximized e.g.
`en_Latn_US`, minimizeSubtags on the other hand does the opposite
operation.
it had been considered as boolean for years but since 8.13, it can
accept values beyond 1L, respectively CURLFOLLOW_OBEYCODE and
CURLFOLLOW_FIRSTONLY.
close GH-18444
* Optimizer: Optimize `IS_IDENTICAL` with true/false/null to `TYPE_CHECK`
This optimization is already happening in the compiler for explicit `===`
expressions, but not for `match()`, which also compiles to `IS_IDENTICAL`.
* Optimizer: Optimize `T = BOOL(X) + TYPE_CHECK(T, true)` to just `BOOL`
Resolvesphp/php-src#18411
* PHP-8.4:
Fix IntlDateFormatter::parseToCalendar() reference type system breaks
datefmt_parse/datefmt_localtime references type system fixes
Fix GH-18438: Handling of empty data and errors in ZipArchive::addPattern
There are two hot spots on my machines:
1. We copy the string because the internal PHP API works in-place.
2. The conversion of hex characters is slow due to going through the C
locale handling.
This patch resolves the first hot spots by introducing 2 new internal
APIs that avoid the redundant copy and allocate an empty string upfront.
The second hotspot is resolved by having a specialised htoi handler.
For the following benchmark:
```php
$encoded = "Hello%20World%21+This%20is%20a%20test%3A%20%40%23%24%25%5E%26*%28%29";
for ($i=0;$i<2000000;$i++) {
rawurldecode($encoded);
urldecode($encoded);
}
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 364.8 ms ± 3.7 ms [User: 359.9 ms, System: 3.3 ms]
Range (min … max): 359.9 ms … 372.0 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 565.5 ms ± 4.9 ms [User: 561.8 ms, System: 2.5 ms]
Range (min … max): 560.7 ms … 578.2 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.55 ± 0.02 times faster than ./sapi/cli/php_old x.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 708.8 ms ± 6.1 ms [User: 701.4 ms, System: 6.3 ms]
Range (min … max): 701.9 ms … 722.3 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 1.311 s ± 0.019 s [User: 1.300 s, System: 0.008 s]
Range (min … max): 1.281 s … 1.348 s 10 runs
Summary
./sapi/cli/php x.php ran
1.85 ± 0.03 times faster than ./sapi/cli/php_old x.php
```
Closes GH-18378.
* fileinfo: Remove `php_fileinfo` struct
This is just a needless layer of indirection and requires an additional
allocation.
* fileinfo: Remove options field from `finfo_object`
This was only required to restore the original options when options are given
for `finfo_file()` or `finfo_buffer()`. This can more reliably be achieved
using `magic_getflags()` and is therefore redundant.
* fileinfo: Preserve error for uninitialized `finfo` objects
Besides the fact that this is only used for DOM_NODESET and thus makes
no sense of being on the iterator itself, it's also redundant now that
we have the index member.
Checks is the locale is written left to right.
It makes sure all the needed likely subtags are included (maximization)
then determines the direction by known matches.
close GH-18351
These cause cache misses due to global access, in phpstan
(notably the array_map).
Initializing these isn't necessary because ZPP initializes it for us.
Only for optional arguments do we need to be careful; for `array_filter`
we still reset the `fci` but not `fci_cache` because `fci` is not
necessarily set by ZPP but is conditionally used to access `fci_cache`.
This changes the signature of opcode handlers in the CALL VM so that the opline
is passed directly via arguments. This reduces the number of memory operations
on EX(opline), and makes the CALL VM considerably faster.
Additionally, this unifies the CALL and HYBRID VMs a bit, as EX(opline) is now
handled in the same way in both VMs.
This is a part of GH-17849.
Currently we have two VMs:
* HYBRID: Used when compiling with GCC. execute_data and opline are global
register variables
* CALL: Used when compiling with something else. execute_data is passed as
opcode handler arg, but opline is passed via execute_data->opline
(EX(opline)).
The Call VM looks like this:
while (1) {
ret = execute_data->opline->handler(execute_data);
if (UNEXPECTED(ret != 0)) {
if (ret > 0) { // returned by ZEND_VM_ENTER() / ZEND_VM_LEAVE()
execute_data = EG(current_execute_data);
} else { // returned by ZEND_VM_RETURN()
return;
}
}
}
// example op handler
int ZEND_INIT_FCALL_SPEC_CONST_HANDLER(zend_execute_data *execute_data) {
// load opline
const zend_op *opline = execute_data->opline;
// instruction execution
// dispatch
// ZEND_VM_NEXT_OPCODE():
execute_data->opline++;
return 0; // ZEND_VM_CONTINUE()
}
Opcode handlers return a positive value to signal that the loop must load a
new execute_data from EG(current_execute_data), typically when entering
or leaving a function.
Here I make the following changes:
* Pass opline as opcode handler argument
* Return next opline from opcode handlers
* ZEND_VM_ENTER / ZEND_VM_LEAVE return opline|(1<<0) to signal that
execute_data must be reloaded from EG(current_execute_data)
This gives us:
while (1) {
opline = opline->handler(execute_data, opline);
if (UNEXPECTED((uintptr_t) opline & ZEND_VM_ENTER_BIT) {
opline = opline & ~ZEND_VM_ENTER_BIT;
if (opline != 0) { // ZEND_VM_ENTER() / ZEND_VM_LEAVE()
execute_data = EG(current_execute_data);
} else { // ZEND_VM_RETURN()
return;
}
}
}
// example op handler
const zend_op * ZEND_INIT_FCALL_SPEC_CONST_HANDLER(zend_execute_data *execute_data, const zend_op *opline) {
// opline already loaded
// instruction execution
// dispatch
// ZEND_VM_NEXT_OPCODE():
return ++opline;
}
bench.php is 23% faster on Linux / x86_64, 18% faster on MacOS / M1.
Symfony Demo is 2.8% faster.
When using the HYBRID VM, JIT'ed code stores execute_data/opline in two fixed
callee-saved registers and rarely touches EX(opline), just like the VM.
Since the registers are callee-saved, the JIT'ed code doesn't have to
save them before calling other functions, and can assume they always
contain execute_data/opline. The code also avoids saving/restoring them in
prologue/epilogue, as execute_ex takes care of that (JIT'ed code is called
exclusively from there).
The CALL VM can now use a fixed register for execute_data/opline as well, but
we can't rely on execute_ex to save the registers for us as it may use these
registers itself. So we have to save/restore the two registers in JIT'ed code
prologue/epilogue.
Closes GH-17952
When a test has an --STDIN-- or --PHPDBG-- section, save the section's content into a file, like we do for the other sections.
This makes it bit easier to reproduce these tests outside of run-tests.php.
This doesn't update the .sh file to pass the file as stdin to the program, yet.
When using gdb, we can pass the file as stdin like this:
gdb --args php
(gdb) r test.php < test.stdin
* zend_compile: Allow `(void)` in for’s initializer and loop expression
The initializer and loop expression of a `for()` loop only accept expressions,
but they act like statements in spirit - their results are completely ignored.
Allow `(void)` there to allow suppressing `#[\NoDiscard]`, since there is no
semantic ambiguity of what `(void)` returns anyways.
Fixesphp/php-src#18301
* zend_language_parser: Simplify `for()` grammar
* PHP-8.4:
Fix GH-18309: ipv6 filter integer overflow
Fix GH-18304: Changing the properties of a DateInterval through dynamic properties triggers a SegFault
The motivation for this is that types should be considered immutable.
The only times this is not valid is during compilation, optimizations (opcache), or destruction.
Therefore the "normal" type foreach macros are marked to take const arguments and we add mutable version that say so in the name.
Thus add various const qualifiers to communicate intent.
The only way this function returns -1 is if:
> magic_setflags() returns -1 on systems that don't support utime(3), or utimes(2) when MAGIC_PRESERVE_ATIME is set.
This is extremely unlikely and if this would happen we currently have a return type violation.
This test breaks with file cache, because the file isn't compiled. Tests
in ext/opcache/tests are automatically skipped with file cache, hence
circumventing this issue.
https://wiki.php.net/rfc/static-aviz
Optimally, this would be moved to zend_fetch_static_property_address(). However,
this isn't currently effective for opcache, because R and RW/W/UNSET cache slots
are merged. This will circumvent the visibility check if the cache is primed by
a R instruction.
Closes GH-16486
This more accurately matches the "copy & paste" semantics described in
the documentation. Abstract trait methods diverge from this behavior,
given that a parent method can satisfy trait methods used in the child.
In that case, the method is not copied, but the check is performed after
the parent has been bound.
Fixes GH-15753
Fixes GH-16198
Close GH-15878
The test doesn't test what it says it does. And depending on what it is
actually trying to test, it is redundant with either
Zend/tests/traits/error_009.phpt, Zend/tests/traits/error_010.phpt or
Zend/tests/traits/language015.phpt.
Debugging memory corruption issues in production can be difficult when it's not possible to use a debug build or ASAN/MSAN/Valgrind (e.g. for performance reasons).
This change makes it possible to enable some basic heap debugging helpers without rebuilding PHP. This is controlled by the environment variable ZEND_MM_DEBUG. The env var takes a comma-separated list of parameters:
- poison_free=byte: Override freed blocks with the specified byte value (represented as a number)
- poison_alloc=byte: Override newly allocated blocks with the specified byte value (represented as a number)
- padding=bytes: Pad allocated blocks with the specified amount of bytes (if non-zero, a value >= 16 is recommended to not break alignments)
- check_freelists_on_shutdown=0|1: Enable checking freelist consistency [1] on shutdown
Example:
ZEND_MM_DEBUG=poison_free=0xbe,poison_alloc=0xeb,padding=16,check_freelists_on_shutdown=1 php ...
This is implemented by installing custom handlers when ZEND_MM_DEBUG is set.
This has zero overhead when ZEND_MM_DEBUG is not set. When ZEND_MM_DEBUG is set, the overhead is about 8.5% on the Symfony Demo benchmark.
Goals:
- Crash earlier after a memory corruption, to extract a useful backtrace
- Be usable in production with reasonable overhead
- Having zero overhead when not enabled
Non-goals:
- Replace debug builds, valgrind, ASAN, MSAN or other sanitizers
[1] https://github.com/php/php-src/pull/14054
Co-authored-by: Tim Düsterhus <timwolla@googlemail.com>
This is intended to replace the few manual usages of zend_fetch_resource2_ex() to fetch a php_stream from a zval.
This will simplify the conversion from resource to object for streams when this actually happens.
If the array is packed, then we don't have to loop to get the highest
index.
For this script:
```php
$array = range(1, 100);
for ($i=0;$i<1000000;$i++) {
SplFixedArray::fromArray($array);
}
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php spl.php
Time (mean ± σ): 376.5 ms ± 2.0 ms [User: 372.1 ms, System: 2.6 ms]
Range (min … max): 373.7 ms … 379.5 ms 10 runs
Benchmark 2: ./sapi/cli/php_old spl.php
Time (mean ± σ): 511.6 ms ± 1.9 ms [User: 508.0 ms, System: 2.3 ms]
Range (min … max): 509.2 ms … 515.1 ms 10 runs
Summary
./sapi/cli/php spl.php ran
1.36 ± 0.01 times faster than ./sapi/cli/php_old spl.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php spl.php
Time (mean ± σ): 250.4 ms ± 3.5 ms [User: 246.6 ms, System: 2.6 ms]
Range (min … max): 247.0 ms … 258.5 ms 11 runs
Benchmark 2: ./sapi/cli/php_old spl.php
Time (mean ± σ): 328.4 ms ± 1.0 ms [User: 324.4 ms, System: 3.8 ms]
Range (min … max): 327.5 ms … 331.0 ms 10 runs
Summary
./sapi/cli/php spl.php ran
1.31 ± 0.02 times faster than ./sapi/cli/php_old spl.php
```
Bonus: this also decreases the code size of the function.
If there is not yet a dynamic property, and there are no class properties,
then we know that we don't have to build a properties table.
For this (micro-bench) script:
```php
function x() {
$fa = new SplFixedArray(1);
$fa[0] = $fa;
}
for ($i=0;$i<1000000;$i++)
x();
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php spl.php
Time (mean ± σ): 140.9 ms ± 1.2 ms [User: 137.5 ms, System: 2.7 ms]
Range (min … max): 138.9 ms … 144.9 ms 21 runs
Benchmark 2: ./sapi/cli/php_old spl.php
Time (mean ± σ): 162.0 ms ± 3.8 ms [User: 157.7 ms, System: 3.2 ms]
Range (min … max): 158.5 ms … 175.0 ms 17 runs
Summary
./sapi/cli/php spl.php ran
1.15 ± 0.03 times faster than ./sapi/cli/php_old spl.php
```
Since it's a new string we're returning we can use RETURN_NEW_STR() and
we can also use zend_string_efree() for the strings that we replace
because they have RC1.
We can use the optimized packed filling code instead of going through
all the logic of the zend_hash update APIs.
For this script:
```php
$test = new SplFixedArray(4);
$test[0] = 0;
$test[1] = 1;
$test[2] = 2;
$test[3] = 3;
for ($i = 0 ; $i< 5000000; $i++)
$test->toArray();
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php toarray.php
Time (mean ± σ): 170.0 ms ± 1.8 ms [User: 167.3 ms, System: 2.2 ms]
Range (min … max): 166.9 ms … 173.0 ms 17 runs
Benchmark 2: ./sapi/cli/php_old toarray.php
Time (mean ± σ): 215.7 ms ± 3.6 ms [User: 211.9 ms, System: 3.0 ms]
Range (min … max): 211.3 ms … 222.0 ms 13 runs
Summary
./sapi/cli/php toarray.php ran
1.27 ± 0.02 times faster than ./sapi/cli/php_old toarray.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php toarray.php
Time (mean ± σ): 112.6 ms ± 1.4 ms [User: 109.6 ms, System: 2.9 ms]
Range (min … max): 111.1 ms … 116.4 ms 25 runs
Benchmark 2: ./sapi/cli/php_old toarray.php
Time (mean ± σ): 145.3 ms ± 2.8 ms [User: 141.8 ms, System: 3.4 ms]
Range (min … max): 142.6 ms … 151.8 ms 20 runs
Summary
./sapi/cli/php toarray.php ran
1.29 ± 0.03 times faster than ./sapi/cli/php_old toarray.php
```
This patch optimizes reading and writing from SplFixedArray with the
dimension operators. It accomplishes this due to the following
optimizations:
* Fast-path for long keys (inlined).
* Optimization hints (UNEXPECTED + assertion)
* Using an unsigned index so we can do a single length comparison
For the following script:
```php
$test = new SplFixedArray(4);
for ($i = 0 ; $i< 5000000; $i++)
$test[1] += $i;
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 95.4 ms ± 1.6 ms [User: 91.5 ms, System: 3.2 ms]
Range (min … max): 93.7 ms … 100.8 ms 31 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 119.1 ms ± 1.3 ms [User: 114.7 ms, System: 3.6 ms]
Range (min … max): 117.6 ms … 123.1 ms 24 runs
Summary
./sapi/cli/php x.php ran
1.25 ± 0.03 times faster than ./sapi/cli/php_old x.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 67.9 ms ± 1.1 ms [User: 64.8 ms, System: 3.2 ms]
Range (min … max): 66.6 ms … 72.8 ms 43 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 84.8 ms ± 1.1 ms [User: 81.0 ms, System: 3.9 ms]
Range (min … max): 82.6 ms … 88.0 ms 34 runs
Summary
./sapi/cli/php x.php ran
1.25 ± 0.03 times faster than ./sapi/cli/php_old x.php
```
For this script:
```php
for ($i=0;$i < 100; $i++)
array_reduce(range(1, 100000), fn ($a,$b)=>$a+$b,1);
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php reduce_bench.php
Time (mean ± σ): 272.0 ms ± 3.7 ms [User: 268.9 ms, System: 2.1 ms]
Range (min … max): 268.9 ms … 281.3 ms 11 runs
Benchmark 2: ./sapi/cli/php_old reduce_bench.php
Time (mean ± σ): 288.2 ms ± 3.5 ms [User: 284.5 ms, System: 2.7 ms]
Range (min … max): 285.0 ms … 295.9 ms 10 runs
Summary
./sapi/cli/php reduce_bench.php ran
1.06 ± 0.02 times faster than ./sapi/cli/php_old reduce_bench.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php test.php
Time (mean ± σ): 189.6 ms ± 3.5 ms [User: 178.5 ms, System: 10.7 ms]
Range (min … max): 187.3 ms … 201.6 ms 15 runs
Benchmark 2: ./sapi/cli/php_old test.php
Time (mean ± σ): 204.2 ms ± 2.9 ms [User: 190.1 ms, System: 13.6 ms]
Range (min … max): 200.6 ms … 210.2 ms 14 runs
Summary
./sapi/cli/php test.php ran
1.08 ± 0.02 times faster than ./sapi/cli/php_old test.php
```
The refcounting and destruction is not necessary because zend_call_function
will make a copy anyway. And zend_call_function only returns FAILURE if
EG(active) is false in which case array_map shouldn't have been called
in the first place.
This avoids destruction logic for the common case, avoids some copy, and
adds an optimization hint.
For this script:
```php
$array = range(1, 10000);
$result = 0;
for ($i = 0; $i < 5000; $i++) {
$result += array_find($array, static function ($item) {
return $item === 5000;
});
}
var_dump($result);
```
On an intel i7 1185G7:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 543.7 ms ± 3.8 ms [User: 538.9 ms, System: 4.4 ms]
Range (min … max): 538.4 ms … 552.9 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 583.0 ms ± 4.2 ms [User: 578.4 ms, System: 3.4 ms]
Range (min … max): 579.3 ms … 593.9 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.07 ± 0.01 times faster than ./sapi/cli/php_old x.php
```
On an intel i7 4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 828.6 ms ± 4.8 ms [User: 824.4 ms, System: 1.6 ms]
Range (min … max): 822.8 ms … 839.0 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 940.1 ms ± 26.4 ms [User: 934.4 ms, System: 2.5 ms]
Range (min … max): 918.0 ms … 981.1 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.13 ± 0.03 times faster than ./sapi/cli/php_old x.php
```
- When appending a single character to the string, use `smart_str_appendc()`
- When appending a C-string without printf use, use `smart_str_appends()`
- When appending just a `zend_string`, use `smart_str_append()`
While internally enums are mostly the same as classes, their output in
`ReflectionClass::__toString()` should show the enum as the developer wrote it,
rather than as the engine stored it. Accordingly
- Say that the enum is an enum, not a final class
- Include the backing type, if any, in the declaration line
- List enum cases separately from constants, and show the underlying values, if
any
GH-15766
This changes make FPM always decode SCRIPT_FILENAME when Apache
ProxyPass or ProxyPassMatch is used. It also introduces a new INI
option fastcgi.script_path_encoded that allows using the previous
behavior of not decoding the path. The INI is introduced because
there is a chance that some users could use encoded file paths in
their file system as a workaround for the previous behavior.
Close GH-17896
Since 0537968, the properties are no longer initialized.
So we call object_properties_init to handle that correctly.
Lower branches have a memory leak, but that requires a separate fix.
This avoids repeated lookups in the function table for the same
function name.
Although this optimization is observable, i.e. defining a function via
an include in between 2 JMP_FRAMELESS for the same function, this cannot
be relied on already as far as I know if the optimizer runs.
Reduce the number of global functions by moving it to
`AttributeInfo::createFromGroups()`. In the process, fix the documentation for
the return type, the result is an array of `AttributeInfo` objects, not
`Attribute` objects.
Move the logic from `parseStubFile()` to `FileInfo::__construct()`, and in the
process inline and remove `FileInfo::setMinimumPhpVersionIdCompatibility()`.
The problem is that `php_request_shutdown` calls `php_deactivate_ticks` prior
to running destructors and the shutdown functions and finalizing output
handlers.
So if a destructor or shutdown function re-registers a tick function,
then the user tick functions handler will be added back to `PG(tick_functions)`.
When the next request happens, the list `PG(tick_functions)` still contains an
entry to call the user tick functions (added in the previous request
during shutdown). This causes a NULL deref eventually because
`run_user_tick_functions` assumes that if it is called then
`BG(user_tick_functions)` must be non-NULL.
Fix this by moving the tick handler deactivation.
Closes GH-18047.
We were already handling NULL as a case, but seem to have forgotten to
pass the ZEND_FETCH_CLASS_EXCEPTION flag.
Also make "is not a trait" error recoverable, there's no reason why it
can't be.
Fixes GH-17959
Closes GH-17960
To possibly reduce the latency when polling packets by activating it
from the network interface for N microseconds.
The kernel by doing so, increase the CPU(s) activity bound to
the socket significantly.
Note that not only the kernel needs to have support enabled for it
(which the average distribution usually does) but the network
interface itself needs to support it too. If not, it is just a no-op.
By returning something more semantically meaningful that SUCCESS/FAILURE
we can avoid refcounting for array_all() and array_any().
Also we can avoid resetting the input values to UNDEF.
This functionality didn't actually work.
This was discussed on the mailing list [1] and no one objected.
[1] https://externals.io/message/126368
Closes GH-17883.
* Use pkg-config for ext/ldap without a directory
The existing check is not very good. OpenLDAP has been shipping a
pkg-config file for a while now, and that's preferable over trying to
manually find it.
Note that for older OpenLDAP or non-OpenLDAP implementations, a
directory can still be passed to use the old logic. Note that Oracle
LDAP is busted and going away soon; I'm not sure for other LDAP
implementations.
Tested on macOS 14.
* Convert added ifs to AS_IF
Add directories for tests relating to
- halting the compiler
- `declare()` usage
- exception handlers
- `get_class_methods()`
- `get_class_vars()`
- `isset()`
- name collisions
As well as organizing a couple of tests into existing sub directories along the
way
Work towards GH-15631
The `ZendAstPrettyPrinter` had logic to handle the various structures that are
based on `zend_ast`, like `zend_ast_decl`, but the printer was only installed
when the value was a `zend_ast`, meaning that for the specialized structures
the details wouldn't be shown unless they were cast (in GDB) to `zend_ast`.
Instead, just register the printer for the specialized structures too.
Calling the constructor twice has no real world benefit.
Block it to fix these two issues.
We also clean up the constructor code a bit:
- `in_ctor` implies `object` exist.
- We surround the instance check with ZEND_DEBUG to avoid a runtime
penalty.
Closes GH-17900.
Closes GH-8084.
Closes GH-17908.
Add directories for tests relating to
- calling user functions (`call_user_func()` and `call_user_func_array()`)
- using `::class` to access class names
- null coalescing with `??`
- concatenation with `.`
- indirect function calls (e.g. by calling a variable with a function name)
- reporting of line numbers
- static variables in functions
- type casts
As well as organizing a couple of tests into existing sub directories along the
way
Work towards GH-15631
Create new sub directories for tests related to backtraces and for tests
related to `$this` being reserved in different places and not being usable or
reassignable.
Work towards GH-15631
While reviewing the existing tests in the `constexpr` directory, I found that
some of the names were not updated to reflect the contents when the contents
were changed in #9301.
Follow-up to #15638
A previous fix to be able to build C++ extensions with MSVC[1], was
based on the assumption that `max_align_t` would be defined in stddef.h
on Windows. That was plain wrong; there is no such typedef (or macro).
Thus we revert that fix, and instead make an exception for Windows,
where we always use the fallback definition, which should work fine on
Windows.
[1] <ab449a7e46>
This became visible after GH-17056 was merged, but technically the lack
of setting the opline is also present on lower branches.
We set the opline to mirror the SAVE_OPLINE() from
ZEND_INIT_STATIC_METHOD_CALL().
Closes GH-17732.
Apply the following changes to ReflectionProperty::getValue(), ::getRawValue(), ::isInitialized(), ::setValue(), ::setRawValue():
- Pass a cache slot to the property handler
- Inline the simple case of fetching a declared property
- Use the new parameter parsing API
This results in run time decrease of 12% to 59% in [micro benchmarks](https://gist.github.com/arnaud-lb/2de08142dcd0c7b49caed21398f44656), when executed with `hyperfine -L version base,opt "/tmp/{version}/sapi/cli/php -d opcache.enable_cli=1 $script"`:
```
get-raw-value.php: -58%
get-value-dyn.php: -50%
get-value-hook.php: -47%
get-value.php: -59%
is-initialized.php: -59%
set-value.php: -11%
```
And a 1.8% decrease in this Doctrine benchmark: 505825290d...reflection-property-get-value-opt
Adds support for `curl_getinfo()` info keys and additional array keys:
- [`CURLINFO_USED_PROXY`](https://curl.se/libcurl/c/CURLINFO_USED_PROXY.html) - `libcurl` >= 8.7.9 -
Zero if no proxy was used in the previous transfer or a non-zero value if a proxy was used.
- [`CURLINFO_HTTPAUTH_USED`](https://github.com/curl/curl/blob/curl-8_12_0/docs/libcurl/opts/CURLINFO_HTTPAUTH_USED.md) - `libcurl` >= 8.7.9 -
Bitmask indicating the authentication method that was used in the previous HTTP request.
- [`CURLINFO_PROXYAUTH_USED`](https://github.com/curl/curl/blob/curl-8_12_0/docs/libcurl/opts/CURLINFO_PROXYAUTH_USED.md) - `libcurl` >= 8.12.0 -
Bitmask indicating the authentication method that was used in the previous request done over an HTTP proxy.
```php
curl_getinfo($ch);
```
```php
[
// ...
"used_proxy" => 0,
"httpauth_used" => 0,
"proxyauth_used" => 0,
]
```
This also updates the `Caddyfile` for curl tests to add a new route
that supports HTTP basic auth.
Sending to a TCP/IP address is not an option anymore, and it hasn't been since
before the file was created in this repo in 1999 (257de2b). Based on
php/doc-en@d522d135a1 it appears that this
feature was part of PHP 3 and removed before PHP 4. I tried to track down the
original code to find when it was actually removed but wasn't able to find a
PHP 3 repository.
We don't need to duplicate these strings from the resource, we can just
use them with an offset.
To prove this was safe, I had to make the arguments const and then
propagate that everywhere, so this patch also introduces some more
constness.
These were introduced in 6747068c, but they don't seem to be in upstream
(anymore). For the entry in rpm it may have even been a mixup with the
two sections in the rpm file: there's a "10 string" entry but only in
the delta part.
The `$module_name` of `com::__construct()` can be a ProgID, ClassID or
moniker. We first try `CLSIDFromString()`, and if that fails, we go
ahead and try to treat the `$module_name` as a moniker. If that also
fails, we throw an exception with the result of `MkParseDisplayName()`
what would just be `MK_E_SYNTAX` if given a ProgID. This result is
highly confusing for the common case where a ProgID is given, which is
not registered (e.g. due to a typo). In this case, we use the original
`HRESULT` (`CO_E_CLASSSTRING`) instead.
The 32bit implementation seems to be okay, but we rather should avoid
falling back to the double (pun intended) calculation for non `__GNUC__`
systems. We use the intsafe.h intrinsics instead for MSVC and
compatible compilers.
- Removed unused variable from getHeaders function.
- Simplified regex by removing unnecessary lazy quantifiers ().
- Removed unnecessary flag from regex patterns.
This improves readability and reduces redundant code without altering functionality.
When the `zend_class_entry` has a `zend_function` entry for `clone`, the logic
is the same regardless of if the `reflection_object` entry has an object or
not; the determination is based solely on the flags of the `zend_function`.
Second pass through `Zend/tests/bug*` to organize the tests.
Move tests to existing sub directories, and create some new sub directories:
* `ArrayAccess`
* `autoload`
* `clone`
* `serialize` (also covers `unserialize()`)
* `switch`
Work towards GH-15631
* Fix GH-17658: COMPersistHelper::LoadFromStream() can segfault
The actual fix is trivial, but to be able to test the behavior we have
to introduce an own COM object, since existing persistable objects
likely implement `IPersistInit`, not only `IPersist`. We also want to
avoid further test dependencies on possibly unavailable objects, such
as `Word.Application`.
To this purposes, we add a small COM in-process server, which may be
extended for other testing purposes. We keep it simple by implementing
it in C++, but without using any more sophisticated frameworks like ATL.
This component needs to be built explicitly (`nmake comtest.dll`), and
also needs to be explicitly registered (`nmake register_comtest`).
When no longer needed, it is possible to unregister the component
(`nmake unregister_comtest`).
The multiplication of `ZSTR_LEN(bufz)` with the `factor` can easily
overflow on LLP64 architectures, causing a smaller `buf` to be
allocated than expected. While there are no security implications,
calling `uncompress()` with the small buffer cannot be successful
(`Z_BUF_ERROR`). We avoid such superfluous calls by bailing out of
the loop early in case of an overflow condition.
Note that `safe_emalloc()` would not help here, since that will not
prevent 32bit unsigned overflow on 64bit architectures.
The main purpose of this is to better handle the API difference and add
an inital work to separate PHP and OpenSSL logic. This is really just
the first step and further changes are coming after that.
Closes GH-16918
These warnings are about conversion from `size_t` to a smaller type[1],
and in this case because `gdIOCtx` works with `int` lengths. Two of
these warnings are harmless, and we resolve them by using `size_t` in
the first place, and adding a cast (plus an assertion), respectively.
The others actually hint at potential issues when reading image data
with more than `INT_MAX` bytes; we catch that upfront, and throw a
`ValueError` and a warning, respectively.
[1] <https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4267>
sendmail.h is not only included by sendmail.c, but also by
php_win32_globals.h, because that header uses some of the defined
macros. However, the forward declarations of the static functions are
not needed anywhere else than in sendmail.c, and Clang warns about the
unused functions elsewhere (`-Wunused-function`). Thus we move the
forward declarations to sendmail.c.
This selection of suppressed warnings is pretty arbitrary, and
apparently disabling it does not raise any more warning for whole
php-src (except for `-Wno-deprecated-declarations`). As such it
appears to be pretty useless, and it seems to be more appropriate to
let users select which warnings to suppress via manually set `CFLAGS`.
Since we already apply `/wd4996`[1] when building with MSVC, and there
are indeed plenty of deprecation warnings, for now, we apply
`-Wno-deprecated-declarations` for Clang builds unconditionally.
[1] <https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4996>
Closes GH-17554.
On Windows, the cli and phpdbg SAPIs have variants (cli-win32 and
phpdbgs, respectively) which are build by default. However, the
variants share some files, what leads to duplicate build rules in the
generated Makefile. NMake throws warning U4004[1], but proceeds
happily, ignoring the second build rule. That means that different
flags for duplicate rules are ignored, hinting at a potential problem.
We solve this by introducing an additional (optional) argument to
`SAPI()` and `ADD_SOURCES()` which can be used to avoid such duplicate
build rules. It's left to the SAPI maintainers to make sure that
appropriate rules are created. We fix this for phpdbgs right away,
which currently couldn't be build without phpdbg due to the missing
define; we remove the unused `PHP_PHPDBG_EXPORTS` flag altogether.
[1] <https://learn.microsoft.com/en-us/cpp/error-messages/tool-errors/nmake-warning-u4004>
Closes GH-17545.
To call the constructor we now only store the CE and a HashTable for the arguments.
This reduces the size of the _pdo_stmt_t struct from 320 bytes to 232 bytes.
Moreover, this now means that the constructor argument array follows the usual CUFA semantics.
This change is a BC break, as string keys now act like named arguments.
Moreover, the automatic wrapping of by-value arguments for by-ref parameters has been dropped, and the usual E_WARNING is now emitted in those cases.
The do_fetch() is heavily refactored to simplify the execution flow, which also makes it easier to understand.
Additionally we add a new bitflag in_fetch to prevent modification of the fetch flags by userland when PDO is fetching from the DB.
* Support IS_INDIRECT, IS_PTR, IS_ALIAS_PTR when printing zvals
* Pretty print the ce_flags field when pretty printing a zend_class_entry
* Pretty print the const flags when pretty printing a zend_class_constant
* Added a minimal zend_property_info pretty printer to pretty print the flags field
* Added minimal zend_function, zend_op_array, and zend_internal_function pretty printers: The string value is the function/method name, function type (user/internal), and location (when possible). The fn_flags field is pretty printed
* Added a minimal zend_op pretty printer to pretty print the opcode
* Added a zend_refcounted_h pretty printer to pretty print the type_info
* Added minimal pretty printers for zend_object and zend_array
* Print the type and address of pretty-printed structs
* Added gdb commands: print_fn_flags, print_ce_flags, print_prop_flags, print_const_flags, print_ref_type_info, print_opcode, dump_op_array
* Fields of type zend_string, zend_class_entry, zend_array are printed by default in all our pretty printers, using short representation
* Increased the maximum length of printed strings to 200 chars before truncation (was 50)
Caused by GH-15492. While the parent might contain callable, it may also
contain other types. zend_is_class_subtype_of_type() may be checking a
member that is not callable itself. Fall back to the normal class
subtype check.
Discovered by a failing Laravel test in nightly.
The whole point of using `proc_open()` to execute `openssl s_client` is
that we can terminate the process when we're done. However, when going
through the shell on Windows, we get a handle to the shell process, and
if we terminate that, the grandchild will stay open. Since the pipes
of the grandchild will stay open, the PHP process will not terminate
either, so the test stalls.
We solve this by simply bypassing the shell.
* Drop superfluous php_com_dotnet_object.ce
This is readily available via the `zend_object` (i.e. `zo.ce`), so
there is no need to duplicate it.
There is also no need to assign the ce to the std object,
since this is done be `zend_object_std_init()` anyway.
There is no undefined behavior here. If `BitScan*()` returns zero, the
value written to the first parameter is undefined, but we return a
reasonable value.
* Use type declarations instead of doc-block annotations
* Inline the terrible get_rgb() function
* Always traverse pixels in Z order
libgd stores the pixel as an array of rows, so we should use row-major-
order traversal to improve caching.
* Add assertions to avoid misuse of the functions
The assertion regarding the image dimensions won't break any tests, and
we had it already as a comment.
However, asserting that the images are truecolor images is important
for `calc_image_dissimilarity()` which otherwise would calculate
nonsense, and not unreasonable for `test_image_equals_image()` which
otherwise is overspecified (for our purposes, it doesn't matter which
palette entry a pixel refers to, but rather whether the actual colors
referred by a palette color match).
Since the truecolor assertions break two tests, we fix these by
converting to truecolor. That should likely be backported to lower
branches.
* Drop implicit conversion to truecolor
Conversion to truecolor is a relatively expensive operation, and as
such should not be implicit; instead test authors are encouraged to use
truecolor images in the first place where possible, or to even find
better ways to verify expectations than doing a full image comparison.
* Merge similarity.inc into func.inc
There is no particular reason to have a separate file for similarity
comparisons.
* Simplify bug43475.phpt and bug64641.phpt
`calc_image_dissimilarity()` calculates the sum of the euclidean
distance of the RGB channels of all pixels. The euclidean distance is
either zero or greater than or equal to one (but never in ]0, 1[). The
sum of these values also has this property, so it doesn't make sense to
check for less than 1e-5. Thus we just call `test_image_equals_file()`
instead.
* Replace calc_image_dissimilarity() with the well-known mse()
`calc_image_dissimilarity()` has the drawback that it did sum up the
pixel differences, so for large images the result could be way larger
than for small images. It also has the drawback that it likely is not
as well understood as the mean squared error. Thus we replace it with
the latter, and calculate the mean squared error of the individual RGB
channels (to be precise). The result is always in range 0..255**2 what
makes reasoning about thresholds easier.
First, the `$fontfile` parameter actually supports a semicolon
delimited list of fonts (as documented[1]); thus passing the full
string to `VCWD_REALPATH()` or `php_check_open_basedir()` makes no
sense; we could pass the individual parts, but …
Second, libgd uses an elaborate font detection. There is a hard-
coded `DEFAULT_PATH` which can be overridden by the environment
variable `GDFONTPATH`. Semantics are like the `PATH` environment
variable. If `DEFAULT_PATH` was still exposed (it is no longer as of
libgd 2.1.0[2]), we could take that into account, but …
External libgd can be configured with font-config support, so font
aliases and even lookup patterns are supported. There is no way to
cater to that upfront.
Thus, we no longer interfere with libgd's font lookup. Checking the
realpath was already doubtful (we didn't even use the resolved path).
Lifting the open_basedir restriction is a bit more delicate, but the
manual still states that open_basedir would not apply, and more
relevant, not much harm can be done, because libgd only passes the
found font to `FT_New_Face()` which likely fails for any non font files
without any error which could reveal sensitive information. And the
font file is never written.
It should be noted that this solves lookup of system fonts, does not
change the behavior for absolute font paths, but still does not resolve
issues with relative paths to font files in ZTS environments using
external libgd (our bundled libgd has a workaround for that). This
particular issue cannot be solved, so users of ZTS builds still need to
add `realpath(.)` to the `GDFONTPATH` as documented in the manual (or
pass absolute paths as `$fontfile`).
[1] <https://www.php.net/imagettftext>
[2] <2a921c80fb>
Closes GH-17366.
This build becomes less relevant as all currently sold Apple computers
contain Apple Silicon CPUs. This build rarely fails in isolation anyway.
For the time being, we'll keep the nightly builds in all configurations.
We prefer clean solutions (such as declaring the proper type in the
first place, or introducing a portable format specifier) where easily
possible, but resort to casts otherwise.
We also port f1480ab14b.
This syncs the implementation with the updated implementation of `array_find()`
in php/php-src#17536. For the following test script:
<?php
$array = range(1, 8000);
$result = 0;
for ($i = 0; $i < 4000; $i++) {
$result += count(array_filter($array, static function ($item) {
return $item <= 4000;
}));
}
var_dump($result);
This change results in:
Benchmark 1: /tmp/before array_filter.php
Time (mean ± σ): 696.9 ms ± 16.3 ms [User: 692.9 ms, System: 3.5 ms]
Range (min … max): 681.6 ms … 731.5 ms 10 runs
Benchmark 2: /tmp/after array_filter.php
Time (mean ± σ): 637.5 ms ± 5.6 ms [User: 633.6 ms, System: 3.8 ms]
Range (min … max): 630.2 ms … 648.6 ms 10 runs
Summary
/tmp/after array_filter.php ran
1.09 ± 0.03 times faster than /tmp/before array_filter.php
Or as reported by perf:
# Samples: 2K of event 'cpu_core/cycles/'
# Event count (approx.): 2567197440
#
# Overhead Command Shared Object Symbol
# ........ ....... .................... ........................................................
#
37.02% before before [.] zend_call_function
15.50% before before [.] execute_ex
10.60% before before [.] zif_array_filter
9.43% before before [.] zend_hash_index_add_new
9.13% before before [.] ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVARCV_CONST_HANDLER
8.46% before before [.] zend_init_func_execute_data
3.78% before before [.] zval_add_ref
3.47% before before [.] zval_ptr_dtor
1.17% before before [.] zend_is_true
vs
# Samples: 2K of event 'cpu_core/cycles/'
# Event count (approx.): 2390202140
#
# Overhead Command Shared Object Symbol
# ........ ....... .................... ........................................................
#
36.87% after after [.] zend_call_function
20.46% after after [.] execute_ex
8.22% after after [.] zend_init_func_execute_data
7.94% after after [.] zend_hash_index_add_new
7.89% after after [.] zif_array_filter
6.28% after after [.] ZEND_IS_SMALLER_OR_EQUAL_SPEC_TMPVARCV_CONST_HANDLER
3.95% after after [.] zval_add_ref
2.23% after after [.] zend_is_true
* array_find: Fix data type for `retval_true`
* array_find: Remove unnecessary refcounting
In a post on LinkedIn [1], Bohuslav Šimek reported that the native
implementation of `array_find()` was about 3× slower than the equivalent
userland implementation. While I was not able to verify this claim, due to a
lack of reproducer provided, I could confirm that the native `array_find()` was
indeed slower than the equivalent userland implementation. For the following
example script:
<?php
function my_array_find(array $array, callable $callback): mixed {
foreach ($array as $key => $value) {
if ($callback($value, $key)) {
return $value;
}
}
return null;
}
$array = range(1, 10000);
$result = 0;
for ($i = 0; $i < 5000; $i++) {
$result += array_find($array, static function ($item) {
return $item === 5000;
});
}
var_dump($result);
with the `array_find()` call appropriately replaced for each case, a PHP-8.4
release build provided the following results:
Benchmark 1: /tmp/before native.php
Time (mean ± σ): 765.9 ms ± 7.9 ms [User: 761.1 ms, System: 4.4 ms]
Range (min … max): 753.2 ms … 774.7 ms 10 runs
Benchmark 2: /tmp/before userland.php
Time (mean ± σ): 588.0 ms ± 17.9 ms [User: 583.6 ms, System: 4.1 ms]
Range (min … max): 576.0 ms … 633.3 ms 10 runs
Summary
/tmp/before userland.php ran
1.30 ± 0.04 times faster than /tmp/before native.php
Running `native.php` with perf reports that a third of the time is spent in
`zend_call_function()` and another 20% in `execute_ex()`, however
`php_array_find()` comes next at 14%:
# Samples: 3K of event 'cpu_core/cycles/'
# Event count (approx.): 2895247444
#
# Overhead Command Shared Object Symbol
# ........ ....... ................. ...........................................
#
32.47% before before [.] zend_call_function
20.63% before before [.] execute_ex
14.06% before before [.] php_array_find
7.89% before before [.] ZEND_IS_IDENTICAL_SPEC_CV_CONST_HANDLER
7.31% before before [.] zend_init_func_execute_data
6.50% before before [.] zend_copy_extra_args
which was surprising, because the function doesn’t too all that much. Looking
at the implementation, the refcounting stood out and it turns out that it is
not actually necessary. The `array` is passed by value to `array_find()` and
thus cannot magically change within the callback. This also means that the
array will continue to hold a reference to string keys and values, preventing
these values from being collected. The refcounting inside of `php_array_find()`
thus will never do anything useful.
Comparing the updated implementation against the original implementation shows
that this change results in a 1.14× improvement:
Benchmark 1: /tmp/before native.php
Time (mean ± σ): 775.4 ms ± 29.6 ms [User: 771.6 ms, System: 3.5 ms]
Range (min … max): 740.2 ms … 844.4 ms 10 runs
Benchmark 2: /tmp/after native.php
Time (mean ± σ): 677.3 ms ± 16.7 ms [User: 673.9 ms, System: 3.1 ms]
Range (min … max): 655.9 ms … 705.0 ms 10 runs
Summary
/tmp/after native.php ran
1.14 ± 0.05 times faster than /tmp/before native.php
Comparing the native implementation against the userland implementation with
the new implementation shows that while the native implementation still is
slower, the difference reduced to 15% (down from 30%):
Benchmark 1: /tmp/after native.php
Time (mean ± σ): 670.4 ms ± 9.3 ms [User: 666.7 ms, System: 3.4 ms]
Range (min … max): 657.1 ms … 689.0 ms 10 runs
Benchmark 2: /tmp/after userland.php
Time (mean ± σ): 576.7 ms ± 7.6 ms [User: 572.5 ms, System: 3.7 ms]
Range (min … max): 563.9 ms … 588.1 ms 10 runs
Summary
/tmp/after userland.php ran
1.16 ± 0.02 times faster than /tmp/after native.php
Looking at the updated perf results shows that `php_array_find()` now only
takes up 8% of the time:
# Samples: 2K of event 'cpu_core/cycles/'
# Event count (approx.): 2540947159
#
# Overhead Command Shared Object Symbol
# ........ ....... .................... ...........................................
#
34.77% after after [.] zend_call_function
18.57% after after [.] execute_ex
12.28% after after [.] zend_copy_extra_args
10.91% after after [.] zend_init_func_execute_data
8.77% after after [.] php_array_find
6.70% after after [.] ZEND_IS_IDENTICAL_SPEC_CV_CONST_HANDLER
4.68% after after [.] zend_is_identical
[1] https://www.linkedin.com/posts/bohuslav-%C5%A1imek-kambo_the-surprising-performance-of-php-84-activity-7287044532280414209-6WnA
* array_find: Clean up exception handling
This change has no effect on performance, but greatly improves readability of
the implementation.
While MSVC is apparently fine using `_AddressOfReturnAddress()` without
including intrin.h, Clang complains that the function is undefined. So
we include the header, if `_MSC_VER` is defined, what is the case for
MSVC and clang-cl, but not for some other compilers on Windows (e.g.
GCC).
Updates the `CURLOPT_PREREQFUNCTION` test to validate that
connections failed when the PREREQFUNC returns abort returns
CURLE_ABORTED_BY_CALLBACK as the error number.
Previously, it only checked against a hardcoded value. Now, it
checks against the `CURLE_ABORTED_BY_CALLBACK` constant as well.
First, more recent versions of Clang do no longer have trailing info in
parentheses, so the detection would fail. Since we're not interested
in this information, we just ignore it.
Then we should not rely on Clang being installed in the default program
folder. Instead we look up where the first clang.exe can be found, and
assume that it is located in a bin/ folder in the installation path.
From there we construct the library path, which is
`lib\clang\<ver>\lib\windows` where `<ver>` is either the full version
(older Clang) or only the major version. Note that this is the case
for stand-alone LLVM installations as well as Visual Studio supplied
ones.
Finally, we clean up by improving the error messages, and removing the
duplicate clang version detection in `add_asan_opts()`.
While we're at it, we also apply a cosmetic improvement to avoid
(trailing) whitespace in the compiler name (e.g. shown by `-v`).
A while ago, the cast has been changed from `u_char *` to `uint8_t *`,
but neither makes sense, and causes Clang to complain with
`-Wcompare-distinct-pointer-types`.
Clang supports `__builtin_expect()` at least as of 4.0.0, which is the
(theoretical) minimum required on Windows, so we define it
unconditionally. This also solves some macro redefinition warnings in
JIT-IR.
Besides that it is not needed, it is not proper C, and Clang warns that
"forward references to 'enum' types are a Microsoft extension"
(`-Wmicrosoft-enum-forward-reference`).
grapheme_extract should slide properly past error bytes.
Adds a test to assert that the `$next` parameter of `grapheme_extract()`
points to the next byte offset in the input `$haystack` after accounting
for the moved offset, according to the docs:
> If offset does not point to the first byte of a UTF-8 character,
> the start position is moved to the next character boundary.
It seems that the existing behavior is to find the next grapheme
boundary from the original provided offset, but if the offset doesn’t
point to a valid starting byte, the assigned `$next` value will point
to the byte that was immediately decoded in the same call, leading to
possible infinite loops in user-space code.
```
while ( $at < strlen( $s ) ) {
$grapheme = grapheme_extract( "\x85PHP", 1, GRAPHEME_EXTR_COUNT, $at, $at );
// never moves past the second byte, always returns 'P'
}
```
`__forceinline` is MSVC specific (and also understood by Clang on
Windows), but the code in win32/ should not be constrained to these
compilers. Since we already have `zend_always_inline`, we use this
instead.
* ext/soap: Add some SoapServer tests
* ext/soap: Don't call readfile() userland function
We can perform the operation directly, moreover there is no risk of a user disabling the readfile function and defining their own messing up what we are doing.
* ext/soap: Actually throw a SOAP Fault if the WSDL has disappeared
For Clang, we just need to define the respective macros, since these
built-ins are available in all supported Clang versions (>= 4.0.0,
currently)[1].
For MSVC (and possibly other compilers) we use the respective APIs of
intsafe.h[2] which are available as of Windows 7/Server 2008 R2.
This avoids the UB due to signed integer overflow that may happen with
our fallback implementations.
We also drop the superfluous SHORT_MAX definition from pdo_firebird.
This shouldn't be defined unconditionally, but since it is apparently
unused, we remove it altogether.
[1] <https://releases.llvm.org/4.0.0/tools/clang/docs/LanguageExtensions.html>
[2] <https://learn.microsoft.com/en-us/windows/win32/api/intsafe/>
This is apparently not supported there; the VS supplied clang version
18.1.8, reports:
`clang-cl: warning: unknown argument ignored in clang-cl: '-fwrapv' [-Wunknown-argument]`
`GetProcAddress()` returns a `FARPROC` (aka. `long long (*)()`) which
is not compatible with `void *` per the specs. However, on Windows
they are, so we silence the warning with a cast.
The phpdbg issue is a real issue, although it's unlikely that harm can
be done due to stack alignment and little-endianess. The others seem
to be more cosmetic.
We're considering making this used as a glob implementation on POSIX as
well, but first, we should rebase it from the latest version of OpenBSD.
This also adds a new internal header (charclass.h) for glob.
See conversation in GH-15564.
Co-authored-by: Christoph M. Becker <cmbecker69@gmx.de>
As per the discussion in GH-17120, we are printing a placeholder value only.
The commit history of that PR also includes alternative implementations, should
a different decision be desirable.
Fixes GH-17096
Closes GH-17120
* PHP-8.4:
Fix GH-17307: Internal closure causes JIT failure
Generate inline frameless icall handlers only if the optimization level is set to inline
Fix GH-15981: Segfault with frameless jumps and minimal JIT
Fix GH-15833: Segmentation fault (access null pointer) in ext/spl/spl_array.c
We port the respective upstream fix[1], which dropped the special cased
implementations of fixed-point arithmetic rotation in favor of the
generic implementation.
We also port follow-up upstream fixes[2][3].
[1] <bd6d2e101f>
[2] <6d21d30429>
[3] <9df878a400>
Closes GH-17375.
* ext/pcre: Refactor php_pcre_replace_func_impl() to not rely on an FCI
* ext/pcre: Refactor populate_subpat_array() to take subject as a HashTable*
This makes the assumption the zval is always an array explicit
* ext/pcre: Refactor php_pcre_replace_func_impl()
We don't need the FCI any more, and we always have the subject as a zend_string.
* ext/pcre: Refactor php_pcre_replace_func()
We don't need the FCI any more
* ext/pcre: Refactor php_replace_in_subject_func()
We don't need the FCI any more
Make the Hashtable param const
Throw exception on non string entries
* ext/pcre: Refactor preg_replace_func_impl()
We don't need the FCI anymore
Make the Hashtable params const
Rename function to indicate it is a PHP pcre function
* ext/pcre: Add trampoline tests for preg_replace_callback(_array)()
* ext/pcre: Handle trampolines properly for preg_replace_callback(_array)()
* Revert FCI passing removal
Given that the `ZEND_AST_OP_ARRAY` type already needed special handling in
various places, it makes sense to give it its own struct to avoid some of the
casts. As a side benefit, it is a little smaller than the `zend_ast_zval`
struct.
* zend_compile: Do not traverse children of ZEND_AST_CLOSURE in zend_compile_const_expr()
* Add assertions verifying that zend_ast_decl AST nodes are not treated as regular zend_ast nodes
This also refactors the internal do_fetch() function to stop doing wonky stuff to handle grouping, which is a feature of fetchAll
Handle PDO_FETCH_KEY_PAIR on its own as GROUP and UNIQUE flags can interfere with it
This improvement was done for libgd 2.1.0[1], and the erroneous
calculation has been fixed as of libgd 2.2.0[2].
While we're at it we also add the overflow checks of external libgd;
these are not really necessary, since `.sx * .sy` overflow was already
prevented when the image has been created, and since we're using
`safe_emalloc()` the `struct seg` overflow is also prevented. It
should be noted that `overflow2()` prevents `int` overflow, while
`safe_emalloc()` prevents `size_t` overflow, so the former is more
restrictive. For parity with external libgd, this still appears to be
a good thing.
[1] <86a5debede>
[2] <e87ec88e1c>
Internal function won't need their refcount increased as they outlive
the debugger session, and userland functions won't be unloaded either.
So no refcount management is necessary for registered functions.
This commit[1] and the related part of the Netware removal[2] move the
related definitions out of gd.h, and bring some updates.
[1] <2a921c80fb>
[2] <e6bb110663>
- socket_addrinfo_lookup throws when hints is an indexed array.
- socket_get_option hardcoding size outputs to user when data
size known.
close GH-17363
At one point this served a purpose as it contained the cleanup code that
now lives in dtor, but now it just calls the standard handler so we can
just get rid of it.
This is not a functional change, but rather a performance improvement,
to avoid unnecessary calls of `gdImageSetPixel()` which would be no-ops
due to positions outside of the clipping bounds.
The description of PHP_STRLCPY says that this is a fast version of strlcpy that should be used if we *know* the size of both the source and destination buffers.
This is clearly not the case as we use strlen() to compute it.
Moreover if the result cannot fit in the destination buffer something seriously strange has happened and we should return a failure state rather than truncating.
This is basically a port of the "Small code cleanup" commit[1].
We can now drop the superfluous checks for zero width/height. These
have been introduced as fix for bug 72337[2], while the same issue had
a simpler fix for upstream[3], because the helper functions already
were internal.
[1] <e054be7d82>
[2] <https://bugs.php.net/72337>
[3] <77309c419c>
That bug has been potentially exploitable[1], but the GD extension was
not affected by that, because `gdImageBmpPtr()` is never called. Still
it seems to be reasonable to port the fix; if only to keep bundled and
external libgd synced.
[1] <https://github.com/advisories/GHSA-hc3p-jvff-jfw5>
Improve range array overflow error message
Added info about "how much it exceeded" and the maximum allowable array size.
Makes debugging easier when encountering this specific issue.
* ext/socket: Reduce scope of variables
* ext/socket: Throw TypeErrors when not passing a string for options requiring one
* ext/sockets: Throw ValueError when string has null bytes for options not passing string length
* ext/sockets: Throw ValueError when string is too long
And replace calls to strlcpy to memcpy
In the hopes that it will be clearer that some of the custom clone handling can
be removed the way it was for `ExposedDocComment`, instances of which were
immutable, document a bunch of properties of other classes as read-only.
The objects are immutable, and thus can be safely reused when held by an object
that gets cloned. Remove the unneeded cloning, and document this fact about the
class, noting that the property should be considered `readonly`.
Not actually using `readonly` to maintain PHP 7.4 support.
Instead of using integers that then need to be converted to the string
representation via `::getSendByString()`, just always store a string,
eliminating the conversion method and replacing it with property access.
`Type::tryToSimpleType()` tries to convert a type holding multiple simple types
into a single simple type, with the following logic
- if all of the inner types represent `null`, return the first of those
- if all but one of the inner types represent `null`, return the non-null type
- otherwise, return `null`
Previously, it did this with a helper method `::getWithoutNull()`, that
constructed a new `Type` containing only the inner types that did not represent
`null`. However, the only thing the newly created object was used for was
extracting the types it contains, so the actual object creation just adds
overhead. Merge `Type::getWithoutNull()` into `Type::tryToSimpleType()` and
clean up to avoid creating an unneeded object.
Protected method not overridden in any subclasses, so could be made private,
but the method is short enough and simple enough that it can just be inlined.
Both `ArgInfo::setTypes()` and `ReturnInfo::setTypes()` were private methods
only called in the applicable class's constructor. They had no special logic
that benefited from existing as a separate method, and just added a level of
indirection. Inline the uses and remove the methods.
The following one-line methods, only used in `SimpleType::fromValue()`, were
inlined:
* `SimpleType::bool()`
* `SimpleType::int()`
* `SimpleType::float()`
* `SimpleType::string()`
* `SimpleType::array()`
* `SimpleType::object()`
Doing so removes an unneeded level of indirection and helps simplify the class.
The two calls that MySQLnd does to this handler all pass a buffer the same size as the error_msg field
Thus, we know that we can just memcpy the error message into the buffer.
See https://nrk.neocities.org/articles/not-a-fan-of-strlcpy for a rationale against the usage of `strlcpy()`
We relax the constraint that the array must be a list. What really
matters is that it only has numeric keys. As shown in the example code,
it's really easy to accidentally create a non-list array, so it makes
sense to relax the constraint.
There are 3 cases left where the array is checked to be a list,
in php_ldap_do_search, but I believe this makes sense to keep because
the indices of those arrays have a meaning because they should match
between different arrays. In that case it will prevent programmer
errors.
Even when tests are not run in parallel, shuffling can help discover tests that
unintentionally depend on other tests being run before them.
Closes GH-17149.
Replaces GH-15730 as that PR became stale.
But instead of introducing a new helper, reuse
smart_str_append_escaped(), this also removes the dependency on
ext/standard.
Closes GH-15730.
Closes GH-17277.
- `TCP_FUNCTION_ALIAS`: fetches the function pointer name alias (>= 14.0
only tough).
- `TCP_BBR_ALGORITHM`: set/get the underlying algorithm (0: netflix, 1:
google) when the BBR's TCP stack is used.
- `TCP_REUSPORT_LB_NUMA`: set/get a NUMA domain filter on the socket.
close GH-16923
Checking for the exact output of most image formats is brittle; even an
otherwise change to some header field causes the output to change, even
if the image would be visually identical.
Checking for an (MD5) hash is even worse, since if the tests fails, we
have no clue for what reason.
Thus we compare the generated image against an pre-generated PNG, using
a test helper which will output a simple image diff in case of test
failure.
The main intent of the test was to show the changed behavior on
Windows; previously, `stream_select()` would return immediately there,
reporting all pipes as ready; now, it only returns if at least one pipe
is actually ready.
The original test case was overspecified; of course, we cannot assume
that the pipes are ready one after the other; depending on the concrete
`select(2)` implementation and the system scheduler, minor differences
are to be expected.
Thus we relax the test expectations, and now require that not all pipes
are reported ready after a single `stream_select()` call, and that the
output contains all strings. We also ensure that `stream_select()`
doesn't fail (for whatever reason). And in case of the test
expectations not being met, we also output some diagnostics (most
notably the output that has already been read).
A label should be followed by a statement and not a declaration, else old gcc gives the following error: a label can only be part of a statement and a declaration is not a statement
To fix this we wrap the code in the switch case block in braces.
* PHP-8.4:
NEWS for GH-17168
ext/gettext/config.m4: symlink en_US.UTF-8 test bits to en_US for musl
ext/gettext/tests: fix libintl return values under musl
ext/gettext/gettext.c: handle NULLs from bindtextdomain()
Adding strings to the worklist is useless, because they never contribute to
cycles. The assembly size on x86_64 does not change. This significantly improves
performance in this synthetic benchmark by 33%.
function test($a) {}
$a = new stdClass();
$a->self = $a;
$a->prop1 = str_repeat('a', 10);
$a->prop2 = str_repeat('a', 10);
$a->prop3 = str_repeat('a', 10);
$a->prop4 = str_repeat('a', 10);
$a->prop5 = str_repeat('a', 10);
$a->prop6 = str_repeat('a', 10);
$a->prop7 = str_repeat('a', 10);
$a->prop8 = str_repeat('a', 10);
$a->prop9 = str_repeat('a', 10);
$a->prop10 = str_repeat('a', 10);
for ($i = 0; $i < 10_000_000; $i++) {
test($a);
gc_collect_cycles();
}
This requires adding IS_TYPE_COLLECTABLE to IS_REFERENCE_EX to ensure these
values continue to be pushed onto the stack. Luckily, IS_TYPE_COLLECTABLE is
currently only used in gc_check_possible_root(), where the checked value cannot
be a reference.
Note that this changes the output of gc_collect_cycles(). Non-cyclic, refcounted
values no longer count towards the total reported values collected.
Also, there is some obvious overlap with GH-17130. This change should be good
nonetheless, especially if we can remove the GC_COLLECTABLE(Z_COUNTED_P(zv))
condition in PHP 9 and rely on Z_COLLECTABLE_P() exclusively, given we can
assume an object doesn't become cyclic at runtime anymore.
Closes GH-17194
* Refactor usage of strlcpy
As we allocate the buffer, we know the string will fit inside the buffer.
* Throw ValueErrors when strings contain null bytes
The underlying C calls work with C strings, which are NULL terminated.
* exec_pcntl() always return false
Thus, update stubs to formally have a return type of `false`.
The original patch[1] cared only about pipe handles in the rset, but
would be problematic if there are other handles (e.g. files in the
rset, or pipes/files in the other sets), because `php_select()` would
return immediately, reporting all non read-pipe handles as ready, but
possibly never reporting read-pipe handles.
We fix this by applying different logic for the case where only pipe
handles are supplied in the rset, but no handles in the wset or eset.
In this case `php_select()` only returns when actually one of the
handles is ready, or when the timeout expires. To avoid busy looping
in this case, we sleep for a short amount of time. This matches POSIX
behavior.
In all other cases, `php_select()` behaves as before (i.e. prior to the
original fix), that is it returns immediately, reporting all handles as
ready.
We also add a test case that demonstrates multiplexing the output of a
couple of child processes.
See also the discussion on <https://github.com/php/php-src/pull/16917>.
[1] <b614b4a69a>
Closes GH-17174.
* PHP-8.4:
Fix GH-17140 (Assertion failure in JIT trace exit with ZEND_FETCH_DIM_FUNC_ARG)
Fix GH-16255: Unexpected nan value in ext/gd/libgd/gd_filter.c
The `--EXTENSIONS--` section already ensures that ext/readline is
available, so there's no need to additionally check for unconditionally
available readline functions.
Closes GH-17170.
These test cases differ only in some details, so it doesn't make much
sense to have separate test cases, given that POSIX/Windows test pairs
are not unlikely to diverge over time (as can be seen here, where the
POSIX tests are skipped for repeat runs, but the Windows tests are
not).
For some reason the stack reserve of php.exe and php-cgi.exe is very
large on Windows (64MB)[1]. While this might not be bad for production
purposes, it causes stack_limit_014.phpt to be unbearably slow; the
test may easily run for a minute, and due to a recent `stream_select()`
improvement[2], that can cause a timeout, what triggers the test to be
run again. So this single test case may run for two minutes, and still
might fail (happened a couple of times).
Instead of skipping the test in CI, we reduce the stack reserve to 8MB,
what improves the performance of this test case (and maybe others), and
should still be good enough for CI.
[1] <54906c760f>
[2] <b614b4a69a>
On Windows, phpize happily builds configure even if there is no
config.w32, but running configure then error with "Must be run from the
root of the extension source". This is confusing.
We bring phpize's behavior on par with POSIX systems, where the missing
config.m4 is detected and reported right away.
As is, passing `2147484` as `$timeout`, throws a `ValueError` stating
the `$timeout` needs to be between 0 and 2147484, what is a confusing.
Thus we report the proper threshold as float.
While we're at it we also drop the superfluous `(double)` cast, and
rely on C's usual arithmetic conversions.
For some reason, terminating the child process by sending CTRL+C won't
work under ASan instrumentation. Since termination via CTRL+BREAK
works, there is apparently nothing fundamentally wrong, so we just
skip the test.
Closes GH-17086.
These are defined by the standard include headers we already use.
These cause conflicts which cause compiler warnings on some toolchains
(see GH-17112).
Closes GH-17114.
This code repetition is prone to errors and makes the code harder to
read than necessary. We simplify at the cost of making parsing of ints
slightly less performant (what should not really matter in practice).
As per the Apple developer documentation:
> Prefer to use the equivalent clock_gettime_nsec_np(CLOCK_UPTIME_RAW) in
> nanoseconds.
and also
> This API has the potential of being misused to access device signals to try
> to identify the device or user, also known as fingerprinting. Regardless of
> whether a user gives your app permission to track, fingerprinting is not
> allowed. When you use this API in your app or third-party SDK (an SDK not
> provided by Apple), declare your usage and the reason for using the API in
> your app or third-party SDK’s PrivacyInfo.xcprivacy file.
see https://developer.apple.com/documentation/kernel/1462446-mach_absolute_time
GCC produces exactly the same binary with and without this change (without
extensions), which demonstrates two things:
* There is no additional register pressure.
* All usages of the macros were correct in older branches, i.e. the expressions
did not have any side-effects.
The compiler compiles $value == true to ZEND_BOOL, which always returns true for
objects (with the default cast_object handler). However, when compared to a
statically unknown rhs $value == $true, the resulting opcode ZEND_IS_EQUAL would
call the objects compare handler.
The zend_objects_not_comparable() handler, which is installed for enums and
other internal classes, blanketly returns false. This does not match the
ZEND_BOOL semantics.
Object to boolean comparison is now handled directly in zend_compare(),
analogous to object to null comparison. It continuous to call the cast_object
handler, but guarantees consistent behavior across ZEND_BOOL and ZEND_IS_EQUAL.
Fixes GH-16954
Closes GH-17031
phpize builds on Windows ignore the paths of extension sources, and
build all object files in the same folder. This can't work if there
are multiple source files with the same base name stored in separate
folders and registered as such (e.g. cls/worker.c and src/worker.c).
While extension authors can work around by avoiding duplicate base
names, they may not even be aware of the problem because on POSIX
systems, the object files are usually placed right besides the sources.
Thus we take the relative path (from `configure_module_dirname`) of the
source files into account even for phpize builds. Since this may break
some extension builds (especially those which use Makefile fragments),
we do not apply this fix to stable branches.
Closes GH-17016.
It seems reasonable to have an ASan job on Windows, especially to be
able to check Windows specific code. Since the tests may take about
70 minutes, it doesn't make sense to add these for pushes, but for a
nightly job that should be okay.
Closes GH-17087.
Besides that is generally good practice to avoid macro redefinitions
(and symbol redeclarations), and we're doing this on POSIX platforms
anyway, there is a particular issue regarding phpize builds, where
config.w32.h actually includes config.pickle.h. The latter overrides
some macro definitions (e.g. `PHP_BUILD_SYSTEM`) to define the proper
values, but if config.w32.h is included multiple times, different macro
definitions eventually raise C4005 compiler warnings[1], which break
builds with `/WX /W1` enabled.
[1] <https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4005>
These tests execute php.exe without passing the PATH, what might be a
more general issues, but at least with ASan enabled, the required DLLs
could usually not be found, resulting in the tests stalling.
Closes GH-17079.
Pipes are blocking on Windows, but `php_select()` always returns them
as ready for read/write. This renders the `stream_select()` timeout
useless, what can cause a following read to block for a very long time.
While there is no general fix (and least not within reach for a stable
version), we can at least cater to the important case of read pipes by
peeking the pipe to check whether data is available. If there is none,
we do not add the handle to the read set.
We need to fix a couple of tests cases:
* bug60692.phpt and bug64770.phpt assume that at least the stdin and
stdout pipes are always selected as readable, and that the select
call will not change their order. We're being more defensive now.
* the potentials warnings of bug49936_win32.phpt need to be suppressed,
like it has been done earlier for the POSIX variant of this test
case[1]. Possibly this test case should be dropped altogether[2].
[1] <c884d3782c>
[2] <2c6b85f6fe>
Closes GH-16917.
While it is already possible to enable ASan for MSVC (assuming Visual
Studio 2019 16.10 or later) by passing `/fsanitizer=address` in the
`CFLAGS`, it is only usable if `ZEND_DEBUG` is also enabled; otherwise
there are `STATUS_BACK_STACK` errors all the time.
Since it makes some sense to combine ASan instrumentation with debug
assertions enabled anyway (typical for fuzzing), we support the
configure option `--enable-sanitizer`, which is already supported for
Clang builds, also for MSVC builds. Note that MSVC supports only ASan
for now; contrary to Clang which additionally supports UBSan on Windows.
Since ASan reports can be pretty useless without debug symbol
information, we require such builds to also produce PDBs (i.e.
`--enable-debug-pack`), but forbid actual debug builds (for performance
reasons, and because the way it is implemented it would not make sense;
that was already an issue with Clang builds with sanitizers enabled).
Closes GH-16999.
The only difference between `DateTime::__wakeup()` and
`DateTimeImmutable::__wakeup()` is which class name is included in the error
message if the initialization from the data fails. Factor out a helper method
that is given the class name, and use it for both methods.
There are edge cases where computations can cause an integer overflow,
which is undefined behaviour. Lately, some fuzzers seem to be hitting
these quite frequently. While this behaviour is undefined, it doesn't
actually matter in practice, the worst effect is having a wrong
computation result, but no sane person would do computations on e.g. the
year pow(2,63).
Still, undefined behaviour is bad.
Make the wrapping behaviour defined by using -fwrapv when possible.
The scope of this is limited to timelib and doesn't affect php_date.c.
The reason for this is that this may in theory prevent some
optimizations and it also seems bad to affect code that lives so close
to the PHP-native edge.
I tested all issues.
This fixes all but one issues, the remaining issue is in php_date.c.
Fixes GH-13881.
Fixes GH-14075.
Fixes GH-15150.
Fixes GH-16034.
Fixes GH-16035.
Fixes GH-16048.
Fixes GH-16050.
Fixes GH-16051.
Fixes GH-16052.
Fixes GH-16775.
Fixes GH-16864.
Fixes GH-16865.
Fixes GH-16975.
Fixes GH-17025.
Fixes GH-17059.
Closes GH-17060.
Co-authored-by: =?UTF-8?q?=E6=AD=A6=E7=94=B0=20=E6=86=B2=E5=A4=AA=E9=83=8E?= <takeda@youmind.jp>
Co-authored-by: Christoph M. Becker <cmbecker69@gmx.de>
- Really trim leading and trailing hyphens (single hyphens were not trimmed before)
- Create the necesary directories for even namespaced methods when generating methodsynopsis
* gen_stub: drop support for `@refcount 0` with scalar return
Currenty, if `@refcount` is omitted, it is assumed to be 0 for scalar return
types and "N" otherwise. On the other hand, if `@refcount` is provided, for a
scalar return type it *must* be 0, and for a non-scalar return type it
*must not* be 0. In other words, the ref count will be 0 if and only if the
return type is scalar, regardless of whether the `@refcount` tag is used.
In that case, adding `@refcount 0` does nothing, and since its presence
suggests it does something (why would a developer add code that does nothing?)
it is confusing and should be removed. As it happens, there are currently no
uses of `@refcount 0` in php-src, but why should we allow future uses?
Removing this support also allows simplifying the code a bit.
As is, methods of PHP can never be called, because we're first trying
to read the property with the name of the method.
We fix this by first checking for `DISPATCH_METHOD` and treat that as
method call, if the method would be callable. Only otherwise we try to
access the respective property.
It needs to be noted that this breaks code which accesses a property of
an object, which defines a method of the same name. However, instances
of such classes should never be wrapped in variants, because this can't
be distinguished by COM anyway.
Closes GH-16945.
* Document .rst file maximum line length of 100
In 19d2b84788 ("Create book for docs", 2024-01-30) the build of the
php-src documentation has been introduced.
It is based on reStructuredText (rst) [Docutils] for its source files,
this stems from the sphinx-build utility in use to build the static HTML
pages of the php-src documentation.
The maximum line length of these text files has been set to 100
characters in 19d2b84788 ("Create book for docs", 2024-01-30), the
rationale is unknown to the documenting author at time of writing this
message.
This formatting constraint is applied with the rstfmt utility [rstfmt]
via its invocation (documented in CI build instructions and README.md:)
rstfmt -w 100 source
The `-w, --width` option takes a WIDTH argument that is "the
target line length in characters" (cf. `rstfmt --help`.)
There is also an `--ext EXT` argument option, that is "the extension of
files to look at when passed a directory" ("source" is the name of
a directory in the invocation above) and defaults to "rst".
Henceforth, the editor configuration [EditorConfig] can benefit from
documenting this expectation in the repositories .editorconfig file,
which has been introduced already earlier in 5c38fbe543 ("Added
editorconfig file", 2016-06-26).
[Docutils]: https://docutils.sourceforge.io/index.html "Docutils: Documentation Utilities — Written in Python, for General- and Special-Purpose Use"
[rstfmt]: https://github.com/dzhu/rstfmt "A formatter for reStructuredText"
[EditorConfig]: https://editorconfig.org/ "EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs"
* Makefile for php-src docs build
In 19d2b84788 ("Create book for docs", 2024-01-30) the php-src
documentation (php-src docs) build has been introduced, yet the build
instructions, namely `make html`, did not yield the expected results
within the parenting setup of the php-src project on *nix systems.
The reason is that the `make html` build instruction does not execute
the make.bat file which contains the recipe to build the static HTML
pages.
It is an unused leftover file from initializing the project with
sphinx-quickstart. [1]
Removing it in and adding a Makefile suffices to recover the build of
php-src ./docs on a *nix system.
Formatting constraints checked in the docs workflow in CI update
use the make file to make sure the commands stay consistent and the
build is managed by the build manager.
[1]: https://www.sphinx-doc.org/en/master/man/sphinx-quickstart.html "sphinx-quickstart is an interactive tool that asks some questions about your project and then generates a complete documentation directory and sample Makefile to be used with sphinx-build(1)."
* Bind requirements.txt for php-src docs build
Define the required packages to install for the php-src docs build in
the docs/requirements.txt file:
1) Sphinx
2) sphinx-design
3) sphinxawesome-theme
4) rstfmt
This should also later on ease the use of a requirements_frozen.txt
file to pin the build dependencies if needed/wanted.
Additionally, some formatting corrections in README.md (based on the
profile in .editorconfig) as well as adding the recommendation to use
a Python virtual environment. Python3 and Pip were already named, and
with Python3 there is the venv module (Python 3.3; Sep 2012) to manage
these so-called python virtual environments [venv], which are commonly
a preferred way to install dependencies within development projects
and build systems.
[venv]: https://docs.python.org/3/library/venv.html "venv — Creation of virtual environments — Python documentation"
* Remove deprecated theme configuration
For the configured Awesome Sphinx Theme [1] highlighting extension, the
sphinx-build currently yields the following diagnostics:
WARNING: while setting up extension sphinxawesome_theme.highlighting: \
You no longer have to include the `sphinxawsome_theme.highlighting` \
extension. This extension will be removed in the next major release.
(via `make html`, the configuration file is `source/conf.py`.)
The diagnostic message was introduced by sphinxawesome-theme 5.2.0,
released May 31, 2024. [2], [3]
Removing the extension from the list of extensions in the configuration
file levitates.
No changes to requirements.txt, the extension was transitive as bundled
by the Awesome Sphinx Theme [1], and 5.2.0 deprecates it with the new
feature to "Support `pygments_style_dark` option that allows you to set
a different syntax highlighting scheme in light and dark modes." [3]
[1]: https://sphinxawesome.xyz/ "Awesome Sphinx Theme — Create functional and beautiful websites for your documentation with Sphinx."
[2]: https://pypi.org/project/sphinxawesome-theme/5.2.0/#history
[3]: https://github.com/kai687/sphinxawesome-theme/releases/tag/5.2.0
The only way for the do_operation object handler to be called for unary operations is when the zval is an object.
Therefore we know we have a zval of the correct type and there is no need to check for it.
Note that this function is similar to `SETUP_OPENSSL`, but since the
zlib headers are not necessarily required, we append `_LIB`.
We are also more liberal regarding zlib(_a).lib, because
extensions requiring zlib are looking only for zlib.lib if ext/zlib has
been built as shared extension. This is overly restrictive at best,
and actually makes no sense, since (a) we're not shipping shared zlib
builds for years, and (b) users could have a zlib.lib which is a static
build (they could even just rename zlib_a.lib to zlib.lib).
We define module globals to be used with ZPP, which also avoids excessive initializing and clearing of variables,
something recommended by the GMP documentation.
`configure --enable-opcache --disable-opcache-jit --enable-zts` won't
compile on Cygwin. We fix this, but that does not imply that OPcache
properly works in this environment, let alone that JIT would be
functional.
Closes GH-16920.
Allows to select an alternate TCP stack. For example with RACK,
a fast loss detection relying on timestamp per packet.
While it works system-wide, it can also apply in an individual socket level too.
close GH-16842
This information can be occasionally useful, and would otherwise need
to be parsed from `phpinfo()` output.
However, maybe more importantly we unify the build date between what is
given by `php -v` and `php -i`, since these compilation units are not
necessarily preprocessed within the same second.
Closes GH-16747.
* PHP-8.4:
Fix GH-16777: Calling the constructor again on a DOM object after it is in a document causes UAF
Fix GH-16808: Segmentation fault in RecursiveIteratorIterator->current() with a xml element input
There is no such dependency; only libxml2 depends on libiconv. So when
php_libxml.dll is built, it needs to be linked against libiconv, or,
when ext/iconv has been configured as static extension, against
php8.dll.
According to the WBMP specification[1], the first field (type) of a
WBMP is a multi-byte integer, but only type `0` is supported. Thus
there is no need to read a multi-byte integer. The second field (fix
header) is a single byte; reading a multi-byte integer is not really
wrong, since the fix header field is laid out in a way which allows it
to be treated as such, but the check whether the MBI is greater than
or equal to zero is pretty useless, because negative values could only
be returned if overflow occurs (MBIs are unsigned).
So the only useful assumption we can make is that the first byte is
zero; we let `gdImageCreateFromWBMPCtx()` figure out the rest.
[1] <https://www.wapforum.org/what/technical/SPEC-WAESpec-19990524.pdf> section 6
This was originally meant to distinguish between libcurl 7.59.0 and
earlier; only the latter would need to be linked against normalize.lib,
libssh2.lib and nghttp2.lib[1]. That would only have catered to our
builds, and might not have been correct anyway. However, the version
check was wrong (paren error), and has been removed in the meantime[2].
Given that cURL 7.59.0 is rather old, we do not reinstate the version
check, but rather drop the now superfluous (and improper) determination
of the cURL version. A nice bonus is that we get rid of some global
variables.
[1] <a1ba3007a4>
[2] <94a12d5b31>
This requirements bump should rarely affect anybody in practice. All
major distros already ship more recent ICU versions, and even for
Solaris 11, ICU 57.1 is available via OpenCSW. Note that ICU 57.1 has
been released on 2016-03-23[1].
[1] <https://icu.unicode.org/download/57>
Closes GH-16688.
Is to create socket for Internet Control Message Protocol context.
Due to their nature, they are meant to be used via
raw sockets rather than TCP/UDP.
close GH-16737
Since the return value is never used, the only difference between using this
method and using `object_init_ex()` directly is the flipped order of
parameters, and the added level of indirection - remove that level of
indirection by replacing its uses.
* PHP-8.4:
Fix memory leak in php_openssl_pkey_from_zval()
Fix various memory leaks related to openssl exports
Prevent unexpected array entry conversion when reading key
Musl's crypt() returns "*" to indicate failure in contrast with the
"*0" returned by PHP/libxcrypt. This causes test failures, but more
importantly, is a pretty silly thing to expect the user to know.
This commit catches the musl value and turns it into "*0".
Musl's crypt() implementation of DES tries to handle invalid salts and
can make this test fail because it returns an answer and not an
error. Even musl however will reject a salt with a ':' in it, so we
can make this test cross-platform by supplying an even less valid
salt.
Among other things, this test tries to run too few and too many rounds
of SHA256. In both cases, it is expecting an error, but that behavior
depends on the implementation:
* PHP's own implementation raises an error in either case
* libxcrypt raises an error in either case
* Older versions of glibc would clamp the number of rounds
to a valid amount (newer versions don't have libcrypt)
* Musl libc clamps values that are too low, but raises an error
for values that are too high
If PHP is built with --with-external-libcrypt, the musl implementation
above can be used. Even if libxcrypt is installed, PHP will notice
that no additional -lfoo flags are needed to use the crypt
implementation in musl. To pass on such a system, we must not test
for the "too few rounds" behavior.
We should only attempt to fetch the current filename for user constants. dl()
may attempt to register internal constants after execution has already started,
thus incorrectly linking the user file invoking dl().
See GH-16663
Relative paths are passed to the ioutils APIs, these are not properly
converted to long paths. If the path length already exceeds a given
threshold (usually 259 characters, but only 247 for `mkdir()`), the
long path prefix is prepended, resulting in an invalid path, since long
paths have to be absolute. If the path length does not exceed that
threshold, no conversion to a long path is done, although that may be
necessary.
Thus we take the path length of the current working directory into
account when checking the threshold, and prepend it to the filename if
necessary.
Since this is only relevant for NTS builds, and using the current
working directory of the process would be erroneous for ZTS builds, we
skip the new code for ZTS builds.
Closes GH-16687.
This list was initially introduced in 53a40386, but never included array or
callable. I suppose this is because int & friends are not actual tokens,
while array and callable are. This means it was never possible to do class
array, which is probably the reason this was overlooked.
Closes GH-16683.
* Some tests have this backwards, probably reading "skip for ICU …".
However, that is not how skip reasons are handled.
* Some test seems to have typos in the skip reason version.
* Some tests checked for a certain version, but reported the
*presumably* next version, which is confusing at best.
* Some tests checked versions in descending order, what is not wrong,
but confusing.
* Some tests had off by one errors.
For all tests, we assume that the skipif conditions are correct, and
fix the reasons.
returns the number of file descriptors that a process can handle.
e.g. useful after pcntl_fork() to close all the file descriptors up
to that boundary.
close GH-16681
Avoid dl() in bug77578.phpt
`dl()` has known issues regarding permanent strings[1], so we better
avoid it, even if that means that we need to spawn two sub-processes.
[1] <https://github.com/php/php-src/issues/9196>
Allow determining the name of the file that defined a constant, when the
constant was defined in userland code via const or define(). For constants
defined by PHP core or extensions, false is returned, matching the existing
getFileName() methods on other reflection classes.
Fixes GH-15723
Closes GH-15847
* PHP-8.4:
Fix GH-16594: Assertion failure in DOM -> before
Fix GH-16572: Incorrect result with reflection in low-trigger JIT
Fix GH-16577: EG(strtod_state).freelist leaks with opcache.preload
See GH-16286. The objective is to identify failed builds in security branches
semi-early. Previously, they would only be run when a fix was backported, which
would almost always result in a red build.
* Don't fiddle with NDEBUG in C code
It is way to late to do this in php.h, since assert.h has already been
included. Even pushing that down to zend_portability.h may not have
the desired effect. Instead we define or undefine NDEBUG as CFLAG, so
that it works in all circumstances.
As a last resort we fail at build time, if `NDEBUG` is defined when
`ZEND_DEBUG` is enabled.
We also remove the useless workaround in zend_test to include assert.h
again, since that usually won't have any effect anyway.
Co-authored-by: Arnaud Le Blanc <arnaud.lb@gmail.com>
`num_args > 0` implies that `arg_info != NULL`. We explicitly assert
that during compilation and execution to make it easier for developers
to not miss this[1].
[1] <https://github.com/php/php-src/issues/16266>
For classes that are not declared `abstract`, produce a compiler error for any
`abstract` methods. For anonymous classes, since they cannot be made abstract,
the error message is slightly different.
Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
A follow-up of 9ee9c0e674.
The mbstring extension is added as ZEND_MOD_OPTIONAL dependency at
runtime, so INI directives configuration order here is no longer
relevant and can be done in any way.
* Use a direct call for decoding the UTF-8 buffer
* Add fast path for UTF-8 HTML serialization
This patch adds a fast path to the HTML serialization encoding that has
to encode to UTF-8. Because the DOM internally represents all strings
using UTF-8, we only need to validate here.
Tested on Wikipedia English home page on an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 516.0 ms ± 6.4 ms [User: 511.2 ms, System: 3.5 ms]
Range (min … max): 506.0 ms … 527.1 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 682.8 ms ± 6.5 ms [User: 676.8 ms, System: 3.8 ms]
Range (min … max): 675.8 ms … 695.6 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.32 ± 0.02 times faster than ./sapi/cli/php_old x.php
```
(And if you're interested: it takes over a second on my machine using the old DOMDocument class)
Future optimizations are certainly possible, but let's start here.
If `opcache.file_cache_only` is enabled, `accel_shared_globals` is
allocated as true global, and we need to free that memory when we shut
down the accelerator.
PR #16351 introduced `EnumProcessModules()` calls, but this function is
undefined; thus, the compiler mangles the name according to the default
calling convention. This lets linking succeed for x64, but fail for
x86.
To properly fix this, we include <Psapi.h> where the function is
declared.
The respective code had been introduced 20 years ago, and we can assume
that the function is available at least of Firebird 3.0, what we
require anyway.
This works similar to `dlsym(RTLD_DEFAULT, …)` with the caveat that
symbols on Windows may not be unique, and are usually qualified by the
module they are exported from. That means that wrong symbols may be
fetched, potentially causing serious issues; therefore this usage is
not recommended for production purposes, but is a nice simplification
for quick experiments and the ext/ffi test suite.
Closes GH-16351.
While these "macros" work perfectly fine in confutils, it is somewhat
strange to have these two there, while all others are in config.w32
files.
In particular, there is no need for a `MODE_PHPIZE` guard, since there
are already config.w32 and config.w32.phpize.in.
However, we need to replace the semicolon in the helptext, because the
regex which parses ARG_(ENABLE|WITH) calls is restricted, and does not
accept semicolons.
* Unify headers already sent errors
Now whenever we need to check where headers were already sent in
ext/session, we call a single location that prints where, keeping it
consistent output wise.
* Unify session aready started errors
Similar to the one for headers.
* Also change session active checks too
This usually go hand in hand with the headers already sent checks, but
is in a separate commit because of the amount of tests it changes.
* Better trace coverage (JIT trampoline calls)
* clenup trampoline by zend_jit_free_trampoline()
* Fix ZEND_JIT_TRACE_INIT_CALL/ZEND_JIT_TRACE_DO_ICALL num_args mismatch
It may be caused by SEND_UNPACK/SEND_ARRAY
* cleanup
* cleanup
* Don't record function that may be temporary
* cleanup
* Prevent invalid run_time_cache allocation for "bad" internal functions
* Update zend_jit_trace_record_fake_init_call_ex() accordingly
* Better handling of "bad" functions and fake closures
We had previously improved where sessions were already started, and
where headers were already sent when setting headers, but not where a
header has been sent if we try to set the header cookie.
Fixes GH-16372
These are equivalent to `zend_hash_clean()` and `zend_hash_destroy()`
respectively, but take care of correctly unregistering the weak references to
the keys.
This addition rounds off the weakmap functionality added in
471102edcd by taking one possible footgun away
from the user.
Move more low-hanging fruit, creating new directories for the tests for:
* comparisons
* dynamic calls
* error messages
* `error_reporting()`
* exceptions
* `foreach()`
* garbage collection
* group `use` statements
* heredoc and nowdoc
* `goto` jumps
* late static binding
* magic methods
* namespaces
* numeric literal separators
* objects
* `settype()`
* cleaning of temporary values
* `unset()`
Additionally, move some tests into the existing subdirectory for `list()`
tests.
Drive-by fixes of some test numbers in the names of the `goto` tests.
Work towards GH-15631
`buildconf` (and `phpize`) have special treatment for these "macros".
When configure.js is built, all config.w32 are grepped, these "macros"
are appended to configure.js, and all config.w32 contents are appended
with the "macros" commented out. That means that for `configure` they
are in the toplevel anyway, so having them inside of `if` statements in
config.w32 is confusing.
Note that this matches autoconf behavior.
Move some low-hanging fruit, creating new directories for the tests for
* access modifiers
* `class_alias()`
* constant expressions
* constructor property promotion
* `__debugInfo()`
* dereferencing
* first class callable syntax
Additionally, move some tests into the existing subdirectory for
closure-related tests
Work towards GH-15631
The code block is guarded by `#if 0`, and even if it wasn't it is a switch that
only contains breaks, i.e. it wouldn't actually do anything if enabled.
While `php_escape_shell_cmd()` did indeed `emalloc` a string that needed to be
freed by the caller in the original implementation that was put in GitHub
(see commit 257de2bade) a few months ago the
return type was changed to use `zend_string`, see #14353.
Closes GH-16313
Whether we link with a debug runtime or a normal runtime is not really
related to `PHP_DEBUG`, but rather to `_DEBUG`[1].
We also stop defining that flag, since the compiler already does that.
[1] <https://learn.microsoft.com/en-us/cpp/c-runtime-library/debug>
* PHP-8.4:
Fix error message for newer libxml
Backport 061058a9: Test fixes for libxml2 2.12.0
Workaround deprecation warning in zend_test on 8.1
Backport 3ec5919e: Update error message for libxml 2.13
Backport f74f9b07: Update libxml test for the directory field behaviour change
Backport 4fe82131: Backport libxml2 2.13.2 fixes (#14816)
Backport e2d97314: Backport deprecation warning ignores to unbreak CI
Backport 0a39890c: Fix libxml2 2.12 build due to API breaks
GitHub FYP test case:
```
Benchmark 1: ./sapi/cli/php test.php
Time (mean ± σ): 502.8 ms ± 6.2 ms [User: 498.3 ms, System: 3.2 ms]
Range (min … max): 495.2 ms … 509.8 ms 10 runs
Benchmark 2: ./sapi/cli/php_old test.php
Time (mean ± σ): 518.4 ms ± 4.3 ms [User: 513.9 ms, System: 3.2 ms]
Range (min … max): 511.5 ms … 525.5 ms 10 runs
Summary
./sapi/cli/php test.php ran
1.03 ± 0.02 times faster than ./sapi/cli/php_old test.php
```
Wikipedia English homepage test case:
```
Benchmark 1: ./sapi/cli/php test.php
Time (mean ± σ): 301.1 ms ± 4.2 ms [User: 295.5 ms, System: 4.8 ms]
Range (min … max): 296.3 ms … 308.8 ms 10 runs
Benchmark 2: ./sapi/cli/php_old test.php
Time (mean ± σ): 308.2 ms ± 1.7 ms [User: 304.6 ms, System: 2.9 ms]
Range (min … max): 306.9 ms … 312.8 ms 10 runs
Summary
./sapi/cli/php test.php ran
1.02 ± 0.02 times faster than ./sapi/cli/php_old test.php
```
The type is enforced, and `TypeError`s are already thrown, but the
information about the required type is not provided to Reflection. Replace the
`@param` comment with a real typehint so that the information is also available
via Reflection.
First, we fix the long standing issue that property access throws a
`com_exception` ("0x80020003: member not found), because the `HRESULT`
was not properly set after accessing the property.
Next, we fix an issue introduced as of PHP 7.0.0, where the string
length for write access had been properly adapted, but the string
length for read access had been overlooked.
Then we fix an issue introduced as of PHP 8.0.0, where new `HashTable`s
no longer set `nNextFreeElement` to zero, but to `ZEND_LONG_MIN`. This
doesn't work well with the `DISPID` lookup, which is a `LONG`.
Finally we fix a potential double-free due to erroneously destroying
the return value of `zend_read_property()`.
Closes GH-16331.
This function is only available as of Windows 8 and Windows Server 2012,
respectively, and thus needed a fallback (albeit a non working one).
However, as of PHP 8.3.0 Windows 8/Server 2012 is required anyway, so
we can drop the fallback as well as the dynamic loading in favor of
linking to the import library.
- Instead of manually wrapping `assert()` statements with a `ZEND_DEBUG`
condition, use `ZEND_ASSERT()`, so that for non-debug builds the compiler is
told to assume that the assertion is correct.
- Update some return types for methods that return `zend_result`.
During the Doctrine Core Team Meetup 2024 the Doctrine team investigated the
performance overhead of using `setRawValueWithoutLazyInitialization()` instead
of `setValue()` and came to the surprising conclusion that
`setRawValueWithoutLazyInitialization()` outperformed `setValue()`, despite
doing more work.
These two scripts are used as the benchmark:
<?php
class Foo
{
public $id;
public $foo1;
public $foo2;
public $foo3;
public $foo4;
}
$reflection = new ReflectionClass(Foo::class);
$properties = $reflection->getProperties();
for ($i = 0; $i < 1000000; $i++) {
$foo = new Foo();
foreach ($properties as $property) {
$property->setValue($foo, 1);
}
}
and
<?php
class Foo
{
public $id;
public $foo1;
public $foo2;
public $foo3;
public $foo4;
}
$reflection = new ReflectionClass(Foo::class);
$properties = $reflection->getProperties();
for ($i = 0; $i < 1000000; $i++) {
$foo = new Foo();
foreach ($properties as $property) {
$property->setRawValueWithoutLazyInitialization($foo, 1);
}
}
Benchmarking these with a current git master shows that `setValue()` is 50%
slower:
$ hyperfine -L script setValue,setRawValueWithoutLazyInitialization '/tmp/php-before /tmp/test/{script}.php'
Benchmark 1: /tmp/php-before /tmp/test/setValue.php
Time (mean ± σ): 216.0 ms ± 5.8 ms [User: 212.0 ms, System: 3.7 ms]
Range (min … max): 208.2 ms … 225.3 ms 13 runs
Benchmark 2: /tmp/php-before /tmp/test/setRawValueWithoutLazyInitialization.php
Time (mean ± σ): 145.6 ms ± 3.6 ms [User: 141.6 ms, System: 3.8 ms]
Range (min … max): 140.4 ms … 152.8 ms 20 runs
Summary
/tmp/php-before /tmp/test/setRawValueWithoutLazyInitialization.php ran
1.48 ± 0.05 times faster than /tmp/php-before /tmp/test/setValue.php
Looking into the “why” revealed that the `setValue()` script spent quite some
time in `zend_parse_parameters()`.
A 50% overhead can be significant, given that `setValue()` is commonly called
several thousand times in a single request when using Doctrine.
This commit changes the non-static property case of `setValue()` to make use of
the fast parameter parsing API and adjusts `getValue()` for consistency.
The resulting comparison shows that both `setValue()` and
`setRawValueWithoutLazyInitialization()` are now (almost) equal:
$ hyperfine -L script setValue,setRawValueWithoutLazyInitialization 'sapi/cli/php /tmp/test/{script}.php'
Benchmark 1: sapi/cli/php /tmp/test/setValue.php
Time (mean ± σ): 143.0 ms ± 6.4 ms [User: 139.4 ms, System: 3.4 ms]
Range (min … max): 134.8 ms … 157.7 ms 18 runs
Benchmark 2: sapi/cli/php /tmp/test/setRawValueWithoutLazyInitialization.php
Time (mean ± σ): 147.0 ms ± 5.5 ms [User: 143.0 ms, System: 3.6 ms]
Range (min … max): 139.9 ms … 159.8 ms 19 runs
Summary
sapi/cli/php /tmp/test/setValue.php ran
1.03 ± 0.06 times faster than sapi/cli/php /tmp/test/setRawValueWithoutLazyInitialization.php
As is, for requested size which are already aligned, we over-allocate,
so we fix this. We also fix the allocation for chunk size 1.
This issue has been reported by @kkmuffme.
Thanks to @iluuu1994 for improving the fix!
Closes GH-16161.
For `zend_string` pointers in class entries, show the string contents (if not
`NULL`).
For class constants, the `ce` (class entry pointer) field is shown with the
name of the class, and the `doc_comment` field is shown with the string
contents if possible.
Given that the lifecycle of the `slist` HashTable exactly matches the lifecycle
of the `_php_curl_free` struct, we might as well embed the HashTable directly
and avoid a pointer indirection.
This reduces backtracking, which should improve performance and avoid hitting
the backtrack limit in tests with a large output.
See https://github.com/php/php-src/pull/16087
For `phpize` builds, all three version variables are numbers, but for
`buildconf` builds, all are strings. This can yield surprising results
when extensions create their `PHP_VERSION_ID` like
10000 * PHP_VERSION + 100 * PHP_MINOR_VERSION + PHP_RELEASE_VERSION
Since `phpize` builds are way more common for external extensions
nowadays, we change the types for `buildconf` builds.
Closes GH-16247.
* Prevent direct instantiation of com_safearray_proxy
The `com_safearray_proxy` class is meant for internal usage, but so far
it was possible to instantiate it from userland, although that made no
sense. However, a while ago there was a relevant change[1], namely
that its `default_object_handlers` are now assigned when the class is
registered, while previously they only have been assigned when an
instance had been created internally. So now when freeing a manually
created object, `free_obj()` is called, although the object never has
been properly initialized (causing segfaults).
We fix this by introducing a `create_object()` handler which properly
initializes the object with dummy values. Since a manually created
`com_safearray_proxy` still does not make sense, we disallow its
instantiation.
[1] <94ee4f9834>
Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
The bless_tests.patch had been introduced via PR #7204, but is no
longer available due to PR #11566. Since apparently the patch is not
that helpful, we remove the code which generates it.
A tentative return type is used to allow userland code that overrides a method
to not include a typehint without a fatal error; this is inapplicable to final
methods (including all methods of final classes), which cannot be overridden.
Remove the tentative return declarations, and update the build script to
complain about future additions.
* PHP-8.4:
[ci skip] NEWS for GH-15960
Deny resetting an object as lazy during property iteration
Ensure to initialize lazy object in foreach
Do not null out obj->properties when resetting object
Fix handling of undef property during foreach by ref on hooked class
The dl_test extension is not supposed to be loaded via php.ini
settings, so we exclude it from the typical case on Windows where
`--enable-test-ini` is enabled by `--enable-snapshot-build`.
Prior to running the tests, the test runner checks for all generally
available extensions; it does this by scanning the `extension_dir` for
files matching the typical extension pattern, but verifies that the
file is actually a PHP extension by calling `dl()`. However, `dl()`
has known issues[1]. On Windows CI we always get an ugly "zend_mm_heap
corrupted" message, and we even can't `dl()` ext/mysql when OPcache is
enabled[2]. So we better avoid the double-check with `dl()`, which is
unlikely to be necessary anyway.
[1] <https://github.com/php/php-src/issues/9196>
[2] <https://github.com/php/php-src/issues/8508>
The only issue that was left was due to the old build of net-snmp 5.7.3; since updating to net-snmp 5.9.4, this is resolved.
The patch has originally been provided by @mvorisek.
* Implement JIT for ZEND_FETCH_STATIC_PROP_* and improve interpretation
* Revert incorrect change
* Use FASTCALL calling convention
* Use EMPTY_SWITCH_DEFAULT_CASE
* Move the loading of the property info into zend_jit_uninit_static_prop()
This parameter never actually did anything and was forgotten about.
We solve this by detecting when we have a $namespace argument
(that won't conflict with the name argument) and creating a Clark
notation name out of it.
Closes GH-16123.
We're currently using a libxml buffer, which requires copying the buffer
to zend_strings every time we want to output the string. Furthermore,
its use of the system allocator instead of ZendMM makes it not count
towards the memory_limit and hinders performance.
This patch adds a custom writer such that the strings are written to a
smart_str instance, using ZendMM for improved performance, and giving
the ability to not copy the string in the common case where flush has
empty set to true.
Closes GH-16120.
Although the original reproducer no longer exists, I was able to cook up
something similar.
The problem is that there are two ways ext-soap currently looks up
functions:
1) By matching the exact function name; but this doesn't work if the
function name is not in the body.
2) By matching the parameter names.
Neither of these work when we don't have the function name in the body,
and when the parameter names are not unique. That's where we can use the
"SOAPAction" header to distinguish between different actions. This header
should be checked first and be matched against the "soapAction"
attribute in the WSDL. We keep the existing fallbacks such that the
chance of a BC break is minimized.
Note that since #49169 a potential target namespace is ignored right
now.
Closes GH-15970.
Instead of allocating, using, and then releasing a zend_string for every
property name unconditionally, only do so when the minimum supported version of
PHP does not have that string in its known strings (ZEND_KNOWN_STRINGS). If the
string is already known, just use the known version directly. This is already
done for some non-generated class registrations, e.g. in
`zend_enum_register_props()`.
up to postgresql 17, when done with a prepared statement, we could
release it with DEALLOCATE sql command which is fine ; until we want
to implement a cache solution based on statement ids.
Since PostgreSQL 17, PQclosePrepared uses internally the `close` protocol
allowing to reuse the statement name while still freeing it.
Since the close protocol implementation had been added on libpq within
this release, no way to reimplement it.
close GH-14584
Make Pdo\PgSql accept Pdo::setAttribute(PDO::ATTR_PREFETCH, 0) to enter libpq's single row mode.
This avoids storing the whole result set in memory before being able to call the first fetch().
close GH-15750
This is a feature copied from the CGI SAPI, but since cgi is always 0 in
fpm, this code is dead. Similarly, the INI settings related to this are
no longer used after removing this dead code.
PHP Internals Book says:
> The ZVAL_DUP macro is similar to ZVAL_COPY, but will duplicate arrays, rather
> than just incrementing their refcount. If you are using this macro, you are
> almost certainly doing something very wrong.
Replace this by an explicit call to `zend_array_dup()`, as done in
`php_array_diff()`. Besides being more explicit in what is happening, this
likely also results in better assembly.
Both macros are supposed to be defined in limits.h (C99) and as such it
is superfluous to provide fallback definitions. Even worse, because
these fallback definitions didn't cater to LP64, ILP64 and SILP64 data
models (and maybe some rather uncommon ones), but just assumed ILP32,
they are confusing.
When decoding multibyte data in EXIF tags, the mbstring extension needs
to be enabled. In Autotools this is now synced with ZEND_MOD_OPTIONAL
in the C code, and on Windows it is now also optional.
The required dependency on mbstring extension was removed via
755c2cd0d8 which made the mbstring
extension optional dependency.
In the process, remove the (incorrect) assumption that any abstract method that
needs to be implemented by a class that cannot itself be made abstract must be
a private method - the existing test for an enum already showed that this was
not the case.
This PR integrates https://github.com/kocsismate/php-version-benchmarks/ into the CI as a nightly job running every day at 12:30 AM UTC. Roughly, the following happens: the benchmark suite spins up an AWS EC2 instance via Terraform, runs the tests according to the configuration, and then the results are committed to the https://github.com/kocsismate/php-version-benchmark-results repository.
In order to have as stable results as possible, the CPU, kernel and other settings of the AWS instance are fine-tuned:
- Hyper-threading is disabled
- Turbo boost is disabled
- C states of the CPU are limited: https://docs.aws.amazon.com/linux/al2/ug/processor_state_control.html#baseline-perf
- The workload is dedicated to a single core by using taskset according to Intel's recommendations (https://web.archive.org/web/20210614053522/https://01.org/node/3774)
- An io2 SSD volume is attached to the instance which has a provisioned IOPS (https://docs.aws.amazon.com/ebs/latest/userguide/provisioned-iops.html#io2-block-express) so that IO performance is nearly constant
- The instance is dedicated so that the noisy neighbor effect is eliminated: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/dedicated-instance.html
- ASLR is disabled (Disable ASLR for benchmark #13769)
Customizing the CPU is only supported by metal instances among recent instance types according to https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/processor_state_control.html, so at last, a c7i.metal-24xl instance is used in the eu-west-1 region.
The benchmark suite compares the performance of the latest commit of the master branch in the time when the benchmark runs with the last commit of master from the day before yesterday. I.e. if the benchmark runs tomorrow morning at 2 AM, then the performance of the latest commit will be benchmarked against the last commit pushed yesterday. This makes it possible to spot outstanding regressions (or progressions) in time. Actually, the end goal is to send notifications in case of any significant changes for further analyzation. The reason why the benchmark is run for previous commits as well (while they may have already been measured the day before) is to make the results less sensitive for changes in the environment or the benchmark suite itself. I.e.: if AWS upgrades the OS, or if the code under test is modified, then the numbers will likely be affected, and the previous results will be invalidated).
Cirrus CI supports a `<job>.skip` key that skips the build if the expression
evaluates to true. This adds the same list of `on.pull_request.paths-ignore`
patterns from GitHub Actions workflows.
This should save several minutes of CI times on PRs when the changes are
only in the README/doc files.
[Cirrus CI Docs](https://cirrus-ci.org/guide/writing-tasks/#supported-functions)
description:"The used PHP version. Make sure it is [supported](https://www.php.net/supported-versions.php)."
placeholder:"PHP 8.0.12"
description:|
Please run PHP with the `-v` flag (e.g. `php -v`, `php8.3 -v`, `php-fpm -v` or similar) and provide the full output of that command. If executing that command is not possible, please provide the full version number as given in PHPInfo.
Please make sure that the used PHP version [is a supported version](https://www.php.net/supported-versions.php).
ESCAPED_DOCKER_REGISTRY=$(printf '%s\n' "${{ secrets.PHP_VERSION_BENCHMARK_DOCKER_REGISTRY }}" | sed -e 's/[\/&]/\\&/g')
sed -i "s/INFRA_DOCKER_REGISTRY=public.ecr.aws\/abcdefgh/INFRA_DOCKER_REGISTRY=$ESCAPED_DOCKER_REGISTRY/g" ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini
sed -i "s/INFRA_MEASURE_INSTRUCTION_COUNT=0/INFRA_MEASURE_INSTRUCTION_COUNT=${{ env.INSTRUCTION_COUNT }}/g" ./php-version-benchmarks/config/infra/aws/x86_64-metal.ini