Addref to relevant fields before allocating any memory. Also only set/remove the
ZEND_ACC_HEAP_RT_CACHE flag after allocating memory.
Fixes GH-12073
Closes GH-12074
Closure::call() makes a temporary copy of original closure function, modifies its
scope, resets ZEND_ACC_CLOSURE flag and call it through zend_call_function().
As result the same function may be called with and without
ZEND_ACC_CLOSURE flag, that confuses JIT and may lead to memory leak or
even worse memory errors.
The patch allocates "fake" closure object and keep ZEND_ACC_CLOSURE flag
to always behave in the same way.
Object handlers being separate from class entries is a legacy inherited from PHP 5. Today it has little benefit to keep them separate: in fact, accessing object handlers usually requires not-so-safe hacks.
While it is possible to swap handlers in a custom installed create_object handler, this mostly is tedious, as well as it requires allocating the object handlers struct at runtime, possibly caching it etc..
This allows extensions, which intend to observe other classes to install their own class handlers.
The life cycle of internal classes may now be simply observed by swapping the class handlers in post_startup stage.
The life cycle of userland classes may be observed by iterating over the new classes in zend_compile_file and zend_compile_string and then swapping their handlers.
In general, this would also be a first step in directly tying the object handlers to classes. Especially given that I am not aware of any case where the object handlers would be different between various instances of a given class.
Signed-off-by: Bob Weinand <bobwei9@hotmail.com>
Having a stack allocated zend_function may cause crashes if the stack is polluted between bailout and the actual unwinding in zend_observer_fcall_end_all.
Signed-off-by: Bob Weinand <bobwei9@hotmail.com>
- for packed arrays we store just an array of zvals without keys.
- the elements of packed array are accessible throuf as ht->arPacked[i]
instead of ht->arData[i]
- in addition to general ZEND_HASH_FOREACH_* macros, we introduced similar
familied for packed (ZEND_HASH_PACKED_FORECH_*) and real hashes
(ZEND_HASH_MAP_FOREACH_*)
- introduced an additional family of macros to access elements of array
(packed or real hashes) ZEND_ARRAY_ELEMET_SIZE, ZEND_ARRAY_ELEMET_EX,
ZEND_ARRAY_ELEMET, ZEND_ARRAY_NEXT_ELEMENT, ZEND_ARRAY_PREV_ELEMENT
- zend_hash_minmax() prototype was changed to compare only values
Because of smaller data set, this patch may show performance improvement
on some apps and benchmarks that use packed arrays. (~1% on PHP-Parser)
TODO:
- sapi/phpdbg needs special support for packed arrays (WATCH_ON_BUCKET).
- zend_hash_sort_ex() may require converting packed arrays to hash.
In this case we should use the original internal handler. Otherwise
the trampoline will attempt to free the closure, but the function
being used is not actually part of a closure anymore.
We would end up freeing the function name twice here, once for
the original closure, and once for the rebound one.
Rather than further special casing the zend_closure_call_magic
case, always addref the function_name for internal functions,
the same we do for userland functions. To compensate, we need to
release the original function name when creating from callable
or call frame.
Fixes oss-fuzz #37695.
This prevents serialization and unserialization of a class and its
children in a way that does not depend on the zend_class_serialize_deny
and zend_class_unserialize_deny handlers that will be going away
in PHP 9 together with the Serializable interface.
In stubs, `@not-serializable` can be used to set this flag.
This patch only uses the new flag for a handful of Zend classes,
converting the remainder is left for later.
Closes GH-7249.
Fixes bug #81111.
Support acquiring a Closure to a callable using the syntax
func(...), $obj->method(...), etc. This is essentially a
shortcut for Closure::fromCallable().
RFC: https://wiki.php.net/rfc/first_class_callable_syntax
Closes GH-7019.
Co-Authored-By: Nikita Popov <nikita.ppv@gmail.com>
Instead of manually implementing this, use the standard mechanism.
This has minor behavior changes (e.g. doing an isset() will now
return false instead of throwing) which are more in line with
typical behavior.
The function name should be kept if Closure was created from the function which is marked as ZEND_ACC_CALL_VIA_TRAMPOLINE, because it is not a one-time thing and it may be called multiple times.
Closes GH-6867.
Currently, dynamically declared functions and closures are inserted
into the function table under a runtime definition key, and then later
possibly renamed. When opcache is not used and a file containing a
closure is repeatedly included, this leads to a very large memory leak,
as the no longer needed closure declarations will never be freed
(https://bugs.php.net/bug.php?id=76982).
With this patch, dynamic functions are instead stored in a
dynamic_func_defs member on the op_array, which opcodes reference
by index. When the parent op_array is destroyed, the dynamic_func_defs
it contains are also destroyed (unless they are stilled used elsewhere,
e.g. because they have been bound, or are used by a live closure). This
resolves the fundamental part of the leak, though doesn't completely
fix it yet due to some arena allocations.
The main non-obvious change here is to static variable handling:
We can't destroy static_variables_ptr in destroy_op_array, as e.g.
that would clear the static variables in a dynamic function when
the op_array containing it is destroyed. Static variable destruction
is separated out for this reason (we already do static variable
destruction separately for normal functions, so we only need to
handle main scripts).
Closes GH-5595.
For fake closures, we need to share static variables with the
original function, not work on a separate copy. Calling a function
through Closure::fromCallable() should have the same behavior as
calling it directly.
We're starting to see a mix between uses of zend_bool and bool.
Replace all usages with the standard bool type everywhere.
Of course, zend_bool is retained as an alias.
In some cases, like spl_object_id, the code is simpler but equally efficient
after optimizations.
In other cases, like get_mangled_object_vars(), the compiler can't infer that
the object in the zval won't change.
Closes GH-6567
Failure to rebind such closures is not necessarily related to them
being created by `ReflectionFunctionAbstract::getClosure()`, so we fix
the error message.
Closes GH-6424.
Closure::bind() and Closure::bindTo() are currently reported as aliases in stubs because they have a single implementation. They are not aliases in fact though, they just use zend_parse_method_parameters() cleverly.
Thus, let's separate their implementation so that we don't have to alias Closure::bindTo() anymore. This will also have the advantage that the two ZPP implementations become more clear.
Closes GH-6169
Voidification of Zend API which always succeeded
Use bool argument types instead of int for boolean arguments
Use bool return type for functions which return true/false (1/0)
Use zend_result return type for functions which return SUCCESS/FAILURE as they don't follow normal boolean semantics
Closes GH-6002
Refactor the zend_is_callable implementation to check callability
at a particular frame (this is an implementation detail for now,
but could be exposed in the API if useful). Pick the first parent
user frame as the one to check.
From an engine perspective, named parameters mainly add three
concepts:
* The SEND_* opcodes now accept a CONST op2, which is the
argument name. For now, it is looked up by linear scan and
runtime cached.
* This may leave UNDEF arguments on the stack. To avoid having
to deal with them in other places, a CHECK_UNDEF_ARGS opcode
is used to either replace them with defaults, or error.
* For variadic functions, EX(extra_named_params) are collected
and need to be freed based on ZEND_CALL_HAS_EXTRA_NAMED_PARAMS.
RFC: https://wiki.php.net/rfc/named_params
Closes GH-5357.