Add recursion protection when emitting deprecation warnings for class
constants, since the deprecation message can come from an attribute that is
using the same constant for the message, or otherwise result in recursion.
But, internal constants are persisted, and thus cannot have recursion
protection. Otherwise, if a user error handler triggers bailout before the
recursion flag is removed then a subsequent request (e.g. with `--repeat 2`)
would start with that flag already applied. Internal constants can presumably
be trusted not to use deprecation messages that come from recursive attributes.
Fixes GH-18463
Fixes GH-17711
The check for `!fbc || (fbc->common.fn_flags & ZEND_ACC_VARIADIC)` is
performed after `fbc` is set to NULL, so this always returns true.
This results in `ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS` always being
set for unpack sends. Fix it by moving the flag updates to the point
before setting `fbc` to NULL.
Closes GH-17534.
The current code expects the property name to be a string, but it can
also be a number via the {} syntax. Handle this consistently to a string
by using zval_get_string which will do the type coercion and refcount
update (instead of assuming string and doing an explicit string copy).
Closes GH-17236.
Only on Windows `IS_SLASH_P()` may read the previous byte, and so may
in unlikely cases read one byte out of bounds. Since `IS_SLASH_P()` is
in a public header (albeit not likely to be used by external extensions
or SAPIs), we introduce `IS_SLASH_P_EX()` which accepts a second
argument to prevent that OOB read.
It should be noted that the PHP userland function `dirname()` is not
affected by this issue, since it does not call `zend_dirname()` on
Windows.
Closes GH-16995.
Reproducer: https://github.com/php/php-src/issues/16727#issuecomment-2466256317
The root cause is a data race between two different threads:
1) We allocate a lower cased name for an anonymous class here:
f97353f228/Zend/zend_compile.c (L8109)
2) This gets looked up as an interned string here:
f97353f228/Zend/zend_compile.c (L8112)
Assuming that there are uppercase symbols in the string and therefore
`lcname != name` and that `lcname` is not yet in the interned string table,
the pointer value of `lcname` won't change.
3) Here we add the string into the interned string table:
f97353f228/Zend/zend_compile.c (L8223)
However, in the meantime another thread could've added the string into the interned string table.
This means that the following code will run, indirectly called via the `LITERAL_STR` macro,
freeing `lcname`: 62e53e6f49/ext/opcache/ZendAccelerator.c (L572-L575)
4) In the reproducer we then access the freed `lcname` string here:
f97353f228/Zend/zend_compile.c (L8229)
This is solved in my patch by retrieving the interned string pointer
and putting it in `lcname`.
Closes GH-16748.
This check was forgotten in the original implementation. Relaxing this
restriction shouldn't be hard, but needs some work. We either need to prevent
merging of cache slots for R/RW/W, or we need to introduce an additional check
when writing to the property indirectly. This check is currently present only
for direct writes.
Closes GH-16462
Instead of always saying that a name is reserved or deprecated and
cannot/should not be used as a class name, take the usage into account and say
the name cannot be used as an enum name, trait name, etc. In the process, for
class names add a missing "a".
Previously, seen symbols were never cleaned during the compilation of a single
file. This makes it impossible to use a class or function from a different
namespace if such a symbol is also declared within the same file. This is
inconsistent with how it would work when split into different files.
This flag was never necessary. We know a static variable is uninitialized (i.e.
the initializer has never been called) iff the zval in the static variable array
does not contain a reference.
Prompted by a related issue in ext-uopz reported by Christoph.
This flag is longer set since the merge of property hooks in
780a8280d2. This patch removes it completely,
because the corresponding error messages are unreachable.
Increase the reserved stack size in ASAN builds, as instrumentation use more stack.
Increase the max allowed stack size in some tests, and enable these tests under ASAN.
Use __builtin_frame_address(0), instead of some stack variable, when we need a stack address, as ASAN may store local variables outside of the real stack.
You cannot return or yield a reference to a nullsafe chain. This was
checked already in zend_compile_return but not yet in
zend_compile_yield.
Closes GH-14716.
* zend_compile: Rename `string_placeholder_count` to `placeholder_count` in `zend_compile_func_sprintf()`
This is intended to make the diff of a follow-up commit smaller.
* zend_compile: Add support for `%d` to `sprintf()` optimization
This extends the existing `sprintf()` optimization by support for the `%d`
placeholder, which effectively equivalent to an `(int)` cast followed by a
`(string)` cast.
For a synthetic test using:
<?php
$a = 'foo';
$b = 42;
for ($i = 0; $i < 100_000_000; $i++) {
sprintf("%s-%d", $a, $b);
}
This optimization yields a 1.3× performance improvement:
$ hyperfine 'sapi/cli/php -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php' \
'/tmp/unoptimized -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php'
Benchmark 1: sapi/cli/php -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php
Time (mean ± σ): 3.296 s ± 0.094 s [User: 3.287 s, System: 0.005 s]
Range (min … max): 3.213 s … 3.527 s 10 runs
Benchmark 2: /tmp/unoptimized -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php
Time (mean ± σ): 4.300 s ± 0.025 s [User: 4.290 s, System: 0.007 s]
Range (min … max): 4.266 s … 4.334 s 10 runs
Summary
sapi/cli/php -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php ran
1.30 ± 0.04 times faster than /tmp/unoptimized -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php
* Fix sprintf_rope_optimization_003.phpt test expecation for 32-bit integers
* zend_compile: Indent switch-case labels in zend_compile_func_sprintf()
* Add GMP test to sprintf() rope optimization
* Add `%s` test case to sprintf() GMP test