* Fix ReflectionMethod::invoke() crash with internal closures
The closure identity check added in GH-21366 accessed op_array.opcodes
unconditionally, but internal closures (e.g. var_dump(...)) use
internal_function, not op_array. This caused undefined behavior when
comparing closures created via first-class callable syntax on internal
functions.
Check the function type first: compare op_array.opcodes for user
closures, compare the function pointer directly for internal closures.
* Fix internal closure comparison and expand test coverage
The previous comparison (orig_func == given_func) could never match for
internal closures since zend_get_closure_method_def() returns a pointer
to each closure's embedded copy. Compare function_name and scope instead.
Also handle the mixed user/internal type case explicitly.
Add tests for: userland first-class callables, cloned internal closures,
and cross-type (user vs internal) closure rejection.
* php_reflection: Simplify the Closure::__invoke() check
---------
Co-authored-by: Tim Düsterhus <tim@bastelstu.be>
ReflectionMethod::invoke() (and invokeArgs()) for Closure::__invoke()
incorrectly accepted any Closure object, not just the one the
ReflectionMethod was created from. This happened because all Closures
share a single zend_ce_closure class entry, so the instanceof_function()
check always passed.
Fix: store the original Closure object in intern->obj during
ReflectionMethod construction, then compare object identity in
reflection_method_invoke() to reject different Closure instances.
Closes GH-21362
Update gen_stubs.php to generate C enums from internal enums, when the stub is annotated with @generate-c-enums. Enum values can be compared to the result of zend_enum_fetch_case_id(zend_object*).
The generated enums are added to separate files named {$extensionName}_decl.h, so that it's possible to include these from anywhere. _arginfo.h files would generate warnings if we tried to include them in a compilation unit that doesn't call the register_{$class} functions, for instance.
Introduce Z_PARAM_ENUM().
* Make ZEND_AST_CONST_ENUM_INIT a 4-children node
* Store enum case id in ZEND_AST_CONST_ENUM_INIT
* Store enum case id in instance
* Expose enum case_id internally
* Generate C enum for internal enums
* Introduce Z_PARAM_ENUM()
* Port extensions
Attributes may themselves contain elements which can have a doc comment on
their own (namely Closures). A doc comment before the attribute list is
generally understood as belonging to the symbol having the attributes.
Fixesphp/php-src#20895.
The arg_info member of zend_function is now always a zend_arg_info*. Before,
it was a zend_internal_arg_info* on internal functions, unless the
ZEND_ACC_USER_ARG_INFO flag was set.
Closes GH-19022
Since the executor needs to be active at this point, the only way you
could get an UNDEF return value is by having an exception.
Therefore, `!EG(exception)` is always false.
The check doesn't make sense, remove it.
* Reduce code bloat in arginfo by using specialised string releases
Comparing this patch to master (c7da728574),
with a plain configure command without any options:
```
text data bss dec hex filename
20683738 1592400 137712 22413850 156021a sapi/cli/php
20688522 1592400 137712 22418634 15614ca sapi/cli/php_old
```
We see a minor reduction of 0.023% in code size.
* Also use true for the other initialization line
* Also use specialized code for consts
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.
This function always returned SUCCESS unconditionally; removing the return type
revealed some impossible code for handling FAILURE that could also be removed.
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
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.