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.
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
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 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.
`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>
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.