php-src/Zend/zend_execute_API.c

1961 lines
53 KiB
C
Raw Normal View History

1999-04-08 02:10:10 +08:00
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
2019-01-30 17:23:29 +08:00
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
2001-12-11 23:16:21 +08:00
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
2001-12-11 23:16:21 +08:00
| http://www.zend.com/license/2_00.txt. |
1999-07-16 22:58:16 +08:00
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Dmitry Stogov <dmitry@php.net> |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
*/
#include <stdio.h>
#include <signal.h>
#include "zend.h"
#include "zend_compile.h"
#include "zend_execute.h"
1999-04-08 02:10:10 +08:00
#include "zend_API.h"
#include "zend_stack.h"
1999-04-08 02:10:10 +08:00
#include "zend_constants.h"
#include "zend_extensions.h"
#include "zend_exceptions.h"
#include "zend_closures.h"
#include "zend_generators.h"
#include "zend_vm.h"
#include "zend_float.h"
#include "zend_fibers.h"
2018-05-10 20:58:10 +08:00
#include "zend_weakrefs.h"
#include "zend_inheritance.h"
#include "zend_observer.h"
#include "zend_call_stack.h"
#include "zend_frameless_function.h"
2001-05-30 16:23:15 +08:00
#ifdef HAVE_SYS_TIME_H
2000-06-16 10:49:21 +08:00
#include <sys/time.h>
#endif
2016-04-20 18:52:21 +08:00
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef ZEND_MAX_EXECUTION_TIMERS
#include <sys/syscall.h>
#endif
1999-04-08 02:10:10 +08:00
2014-12-14 06:06:14 +08:00
ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data);
ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value);
ZEND_API zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_name);
1999-04-08 02:10:10 +08:00
2003-08-06 15:38:56 +08:00
/* true globals */
ZEND_API const zend_fcall_info empty_fcall_info = {0};
ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = {0};
2003-08-06 07:50:59 +08:00
#ifdef ZEND_WIN32
ZEND_TLS HANDLE tq_timer = NULL;
#endif
#if 0&&ZEND_DEBUG
1999-04-08 02:10:10 +08:00
static void (*original_sigsegv_handler)(int);
static void zend_handle_sigsegv(void) /* {{{ */
1999-04-08 02:10:10 +08:00
{
fflush(stdout);
fflush(stderr);
if (original_sigsegv_handler == zend_handle_sigsegv) {
signal(SIGSEGV, original_sigsegv_handler);
} else {
signal(SIGSEGV, SIG_DFL);
}
{
2015-01-03 17:22:58 +08:00
fprintf(stderr, "SIGSEGV caught on opcode %d on opline %d of %s() at %s:%d\n\n",
active_opline->opcode,
active_opline-EG(active_op_array)->opcodes,
2014-12-14 06:06:14 +08:00
get_active_function_name(),
zend_get_executed_filename(),
zend_get_executed_lineno());
/* See http://support.microsoft.com/kb/190351 */
#ifdef ZEND_WIN32
fflush(stderr);
#endif
}
if (original_sigsegv_handler!=zend_handle_sigsegv) {
original_sigsegv_handler(dummy);
}
1999-04-08 02:10:10 +08:00
}
/* }}} */
#endif
1999-04-08 02:10:10 +08:00
2014-12-14 06:06:14 +08:00
static void zend_extension_activator(zend_extension *extension) /* {{{ */
1999-04-08 02:10:10 +08:00
{
if (extension->activate) {
extension->activate();
}
}
/* }}} */
1999-04-08 02:10:10 +08:00
2014-12-14 06:06:14 +08:00
static void zend_extension_deactivator(zend_extension *extension) /* {{{ */
1999-04-08 02:10:10 +08:00
{
if (extension->deactivate) {
extension->deactivate();
}
}
/* }}} */
1999-04-08 02:10:10 +08:00
static int clean_non_persistent_constant_full(zval *zv) /* {{{ */
{
zend_constant *c = Z_PTR_P(zv);
return (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
}
/* }}} */
static int clean_non_persistent_function_full(zval *zv) /* {{{ */
{
2014-03-18 18:52:54 +08:00
zend_function *function = Z_PTR_P(zv);
return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
}
/* }}} */
static int clean_non_persistent_class_full(zval *zv) /* {{{ */
{
2014-03-18 18:52:54 +08:00
zend_class_entry *ce = Z_PTR_P(zv);
return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
}
/* }}} */
2014-12-14 06:06:14 +08:00
void init_executor(void) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-12-14 06:06:14 +08:00
zend_init_fpu();
ZVAL_NULL(&EG(uninitialized_zval));
ZVAL_ERROR(&EG(error_zval));
1999-07-15 20:17:34 +08:00
/* destroys stack frame, therefore makes core dumps worthless */
#if 0&&ZEND_DEBUG
1999-04-08 02:10:10 +08:00
original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
1999-07-15 20:17:34 +08:00
#endif
EG(symtable_cache_ptr) = EG(symtable_cache);
EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE;
EG(no_extensions) = 0;
1999-04-08 02:10:10 +08:00
EG(function_table) = CG(function_table);
EG(class_table) = CG(class_table);
EG(in_autoload) = NULL;
EG(error_handling) = EH_NORMAL;
2018-06-22 22:22:04 +08:00
EG(flags) = EG_FLAGS_INITIAL;
2014-12-14 06:06:14 +08:00
zend_vm_stack_init();
zend_hash_init(&EG(symbol_table), 64, NULL, ZVAL_PTR_DTOR, 0);
2014-12-14 06:06:14 +08:00
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_activator);
zend_hash_init(&EG(included_files), 8, NULL, NULL, 0);
EG(ticks_count) = 0;
ZVAL_UNDEF(&EG(user_error_handler));
ZVAL_UNDEF(&EG(user_exception_handler));
EG(current_execute_data) = NULL;
zend_stack_init(&EG(user_error_handlers_error_reporting), sizeof(int));
zend_stack_init(&EG(user_error_handlers), sizeof(zval));
zend_stack_init(&EG(user_exception_handlers), sizeof(zval));
zend_objects_store_init(&EG(objects_store), 1024);
2001-10-26 22:13:42 +08:00
EG(full_tables_cleanup) = 0;
ZEND_ATOMIC_BOOL_INIT(&EG(vm_interrupt), false);
ZEND_ATOMIC_BOOL_INIT(&EG(timed_out), false);
2001-08-30 23:26:30 +08:00
EG(exception) = NULL;
2008-08-14 18:24:52 +08:00
EG(prev_exception) = NULL;
EG(fake_scope) = NULL;
EG(trampoline).common.function_name = NULL;
Fix "forech" statemt behaviour according to https://wiki.php.net/rfc/php7_foreach Squashed commit of the following: commit 1e41295097576dbce6c197ddb7507c07ccae3cbe Author: Dmitry Stogov <dmitry@zend.com> Date: Sat Jan 31 07:28:58 2015 +0300 Generalize HashTableIterator API to allows its usage without involvement of HashTable.nInternalPonter commit 5406f21b11e563069d64045e599693b51c444b63 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:43 2015 +0300 Reduced alghorithms complexity commit b37f1d58d2a141b6e1d980a461ccb588d4317d2e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:30 2015 +0300 Fixed test name commit fb2d079645829b12ed4e55a461034df6400bc430 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:05 2015 +0300 API cleanup commit 08302c0d6d1cab279b9f2129df03a057baddf2ff Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 14:20:46 2015 +0300 Make array_splice() to preserve foreach hash position commit cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 12:24:31 2015 +0300 Make internal function, operation on array passed by reference, to preserve foreach hash position commit 5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 09:49:35 2015 +0300 Implement consistent behavior for foreach by value over plain object commit 4c5b385ff53ae9f0b52572e98c4db801f56603b0 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 07:56:37 2015 +0300 More careful iterators update. commit 721fc9e80d2ee8f2cd79c8c3cdceffae2c72de92 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:43:28 2015 +0300 Added new test commit 15a23b1218b3e38630d677751a975907daa2cd54 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:05:02 2015 +0300 Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc/php7_foreach#implementation_details) commit 10a3260b1f16b6075fd8140f673dfef4d5efea91 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:04:44 2015 +0300 New test commit eef80c583762d1e98d177cdbb27e3a8a6b0c4539 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 16:52:21 2015 +0300 Fixed foreach by reference iteration over constant array commit 61e739187391661e2d541947bec25d7dcc4479f3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 14:59:54 2015 +0300 Fixed temporary variable re-allocation pass commit 92e90c09f085c22707ff4a59201f016f56e0ef8b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 12:44:57 2015 +0300 Fixed operand destruction in case of exceptions in iterator commit dd2a36a2074bbb0cb31de00b66dcf2812d6d753f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 10:02:34 2015 +0300 Use GET_OP1_ZVAL_PTR_DEREF() (IS_TMP_VAR and IS_CONST can't be IS_REFERENCE) commit 4638f7b91407c48710007af82a68da0007c820f2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 07:43:28 2015 +0300 Change "foreach" statement behavior (this is just a PoC yet) - "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented)
2015-02-12 18:57:12 +08:00
EG(ht_iterators_count) = sizeof(EG(ht_iterators_slots)) / sizeof(HashTableIterator);
EG(ht_iterators_used) = 0;
EG(ht_iterators) = EG(ht_iterators_slots);
memset(EG(ht_iterators), 0, sizeof(EG(ht_iterators_slots)));
2018-07-19 14:41:15 +08:00
EG(persistent_constants_count) = EG(zend_constants)->nNumUsed;
2018-07-17 22:31:04 +08:00
EG(persistent_functions_count) = EG(function_table)->nNumUsed;
EG(persistent_classes_count) = EG(class_table)->nNumUsed;
EG(get_gc_buffer).start = EG(get_gc_buffer).end = EG(get_gc_buffer).cur = NULL;
EG(record_errors) = false;
EG(num_errors) = 0;
EG(errors) = NULL;
EG(filename_override) = NULL;
EG(lineno_override) = -1;
zend_max_execution_timer_init();
zend_fiber_init();
2018-05-10 20:58:10 +08:00
zend_weakrefs_init();
EG(active) = 1;
1999-04-08 02:10:10 +08:00
}
/* }}} */
1999-04-08 02:10:10 +08:00
2014-12-14 06:06:14 +08:00
static int zval_call_destructor(zval *zv) /* {{{ */
{
if (Z_TYPE_P(zv) == IS_INDIRECT) {
zv = Z_INDIRECT_P(zv);
}
if (Z_TYPE_P(zv) == IS_OBJECT && Z_REFCOUNT_P(zv) == 1) {
return ZEND_HASH_APPLY_REMOVE;
} else {
return ZEND_HASH_APPLY_KEEP;
}
}
/* }}} */
static void zend_unclean_zval_ptr_dtor(zval *zv) /* {{{ */
{
if (Z_TYPE_P(zv) == IS_INDIRECT) {
zv = Z_INDIRECT_P(zv);
}
i_zval_ptr_dtor(zv);
}
/* }}} */
2019-05-29 16:31:46 +08:00
static ZEND_COLD void zend_throw_or_error(int fetch_type, zend_class_entry *exception_ce, const char *format, ...) /* {{{ */
{
va_list va;
char *message = NULL;
va_start(va, format);
zend_vspprintf(&message, 0, format, va);
if (fetch_type & ZEND_FETCH_CLASS_EXCEPTION) {
2015-12-13 10:45:11 +08:00
zend_throw_error(exception_ce, "%s", message);
} else {
zend_error_noreturn(E_ERROR, "%s", message);
}
efree(message);
va_end(va);
}
/* }}} */
2014-12-14 06:06:14 +08:00
void shutdown_destructors(void) /* {{{ */
{
if (CG(unclean_shutdown)) {
EG(symbol_table).pDestructor = zend_unclean_zval_ptr_dtor;
}
zend_try {
2014-12-13 02:57:34 +08:00
uint32_t symbols;
do {
symbols = zend_hash_num_elements(&EG(symbol_table));
zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t) zval_call_destructor);
} while (symbols != zend_hash_num_elements(&EG(symbol_table)));
2014-12-14 06:06:14 +08:00
zend_objects_store_call_destructors(&EG(objects_store));
} zend_catch {
/* if we couldn't destruct cleanly, mark all objects as destructed anyway */
2014-12-14 06:06:14 +08:00
zend_objects_store_mark_destructed(&EG(objects_store));
} zend_end_try();
}
/* }}} */
/* Free values held by the executor. */
ZEND_API void zend_shutdown_executor_values(bool fast_shutdown)
1999-04-08 02:10:10 +08:00
{
zend_string *key;
zval *zv;
2019-08-12 16:45:13 +08:00
EG(flags) |= EG_FLAGS_IN_RESOURCE_SHUTDOWN;
zend_try {
zend_close_rsrc_list(&EG(regular_list));
} zend_end_try();
/* No PHP callback functions should be called after this point. */
EG(active) = 0;
if (!fast_shutdown) {
zend_hash_graceful_reverse_destroy(&EG(symbol_table));
/* Constants may contain objects, destroy them before the object store. */
if (EG(full_tables_cleanup)) {
zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full);
} else {
ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) {
zend_constant *c = Z_PTR_P(zv);
if (_idx == EG(persistent_constants_count)) {
break;
}
zval_ptr_dtor_nogc(&c->value);
if (c->name) {
zend_string_release_ex(c->name, 0);
}
efree(c);
zend_string_release_ex(key, 0);
} ZEND_HASH_MAP_FOREACH_END_DEL();
}
/* Release static properties and static variables prior to the final GC run,
* as they may hold GC roots. */
ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(function_table), zv) {
zend_op_array *op_array = Z_PTR_P(zv);
if (op_array->type == ZEND_INTERNAL_FUNCTION) {
break;
}
if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
if (ht) {
zend_array_destroy(ht);
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
}
}
} ZEND_HASH_FOREACH_END();
ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
zend_class_entry *ce = Z_PTR_P(zv);
if (ce->default_static_members_count) {
zend_cleanup_internal_class_data(ce);
}
if (ZEND_MAP_PTR(ce->mutable_data)) {
if (ZEND_MAP_PTR_GET_IMM(ce->mutable_data)) {
zend_cleanup_mutable_class_data(ce);
}
} else if (ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
/* Constants may contain objects, destroy the values before the object store. */
zend_class_constant *c;
ZEND_HASH_MAP_FOREACH_PTR(&ce->constants_table, c) {
if (c->ce == ce) {
zval_ptr_dtor_nogc(&c->value);
ZVAL_UNDEF(&c->value);
}
} ZEND_HASH_FOREACH_END();
/* properties may contain objects as well */
if (ce->default_properties_table) {
zval *p = ce->default_properties_table;
zval *end = p + ce->default_properties_count;
while (p != end) {
i_zval_ptr_dtor(p);
ZVAL_UNDEF(p);
p++;
}
}
}
if (ce->type == ZEND_USER_CLASS && ce->backed_enum_table) {
ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
zend_hash_release(ce->backed_enum_table);
ce->backed_enum_table = NULL;
}
if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
zend_op_array *op_array;
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
if (op_array->type == ZEND_USER_FUNCTION) {
if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
if (ht) {
zend_array_destroy(ht);
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
}
}
}
} ZEND_HASH_FOREACH_END();
}
} ZEND_HASH_FOREACH_END();
/* Also release error and exception handlers, which may hold objects. */
if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
zval_ptr_dtor(&EG(user_error_handler));
ZVAL_UNDEF(&EG(user_error_handler));
}
if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
zval_ptr_dtor(&EG(user_exception_handler));
ZVAL_UNDEF(&EG(user_exception_handler));
}
zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1);
zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
#if ZEND_DEBUG
if (!CG(unclean_shutdown)) {
gc_collect_cycles();
}
#endif
} else {
zend_hash_discard(EG(zend_constants), EG(persistent_constants_count));
}
zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
}
void shutdown_executor(void) /* {{{ */
{
zend_string *key;
zval *zv;
#if ZEND_DEBUG
bool fast_shutdown = 0;
#else
bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup);
#endif
zend_try {
zend_stream_shutdown();
} zend_end_try();
zend_shutdown_executor_values(fast_shutdown);
2018-05-10 20:58:10 +08:00
zend_weakrefs_shutdown();
zend_max_execution_timer_shutdown();
zend_fiber_shutdown();
2018-05-10 20:58:10 +08:00
zend_try {
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
} zend_end_try();
if (fast_shutdown) {
/* Fast Request Shutdown
* =====================
* Zend Memory Manager frees memory by its own. We don't have to free
* each allocated block separately.
*/
2018-07-17 22:31:04 +08:00
zend_hash_discard(EG(function_table), EG(persistent_functions_count));
zend_hash_discard(EG(class_table), EG(persistent_classes_count));
} else {
zend_vm_stack_destroy();
if (EG(full_tables_cleanup)) {
zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
} else {
ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(EG(function_table), key, zv) {
zend_function *func = Z_PTR_P(zv);
if (_idx == EG(persistent_functions_count)) {
break;
}
destroy_op_array(&func->op_array);
zend_string_release_ex(key, 0);
} ZEND_HASH_MAP_FOREACH_END_DEL();
Implemented preloading RFC: https://wiki.php.net/rfc/preload. Squashed commit of the following: commit 106c815fffb8eb3efe00a27a5229cb1f8ffc9736 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Nov 14 16:36:44 2018 +0300 Added NEWS entry commit 1dacd5e20b7043368ef9e80db296d1781134b6fd Merge: d516139abf ba99aa133c Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Nov 14 16:33:37 2018 +0300 Merge branch 'master' into preload * master: Fixed issues related to optimization and persitence of classes linked with interfaces, traits or internal classes. Added possiblity to avoid signal handlers reinitialization on each request. commit d516139abf5ffbd495ee6037f1dc04a1cfe588a7 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Nov 14 16:13:15 2018 +0300 Override opcache.preload for testing commit 162b154d0bbfbaf8ef93975f7e56a1353236903d Merge: 45fdd034ce 8bda22592e Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Nov 14 15:38:09 2018 +0300 Merge branch 'master' into preload * master: (34 commits) Eliminate useless $this related check Eliminate useless $this related checks Replace zend_parse_method_parameters() by zend_parse_parameters() and avoid useless checks. Replace getThis() by EX(This), when additional check is not necessary. Fixed tests Validate length on socket_write Fix compilation on x32 Fix #77141: Signedness issue in SOAP when precision=-1 Support SQLite3 @name notation Remove lexer files generated by RE2C Update libmagic.patch [ci skip] Update libmagic.patch [ci skip] Fork test with pcre.jit=0 Rework magic data Fix regex Fix regex Rework magic data Sync one more upstream libmagic piece Suppress already used warning Ignore getaddrinfo failed message ... commit 45fdd034ceceb68e8fb23bd6e70d627f17dfd411 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Nov 9 13:07:03 2018 +0300 Properly resolve magic method of preloaded classes inherited from internal ones. commit 34645aeb4272b71a81a7e0d91f27eded557b78be Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Nov 8 15:29:17 2018 +0300 Don't preload constants defined during preload script excution. commit cef0d67c3e5aac89b3d606fbd8d445225c07c83f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Nov 7 15:56:54 2018 +0300 Support for class aliasses commit 08ffc9a552c7cf4fbff1a4b3d2de4e7c33f4120d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Nov 7 15:34:39 2018 +0300 Resolve constants only in linked classes commit 8d3429cda83c87646eef0006d5cda075f2400b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Nov 6 11:56:39 2018 +0300 Fixed preloading of references to internal classes. commit 7ae3a47d20e83f7d804506c6d50f6a392199260b Merge: 9b0a53ed1c 049f239cfc Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Nov 6 11:37:15 2018 +0300 Merge branch 'master' into preload * master: Update NEWS [ci skip] Update NEWS [ci skip] Update libmagic.patch [ci skip] Update libmagic.patch [ci skip] Declare function proto in header Declare function proto in header Fix #76825: Undefined symbols ___cpuid_count NEWS Fix: #77110 undefined symbol zend_string_equal_val in C++ build Fix #77105: Use position:sticky for <th> in `phpinfo()` Implement handling for JIT recognition when cross compiling Backport 7f5f4601 for 7.2 Fix #76348: WSDL_CACHE_MEMORY causes Segmentation fault Rework places in libmagic regarding previous CVE-2014-3538 fixes Change the way JIT availability is checked Fix a test for ldap extension Fixed bug #77092 Future-proof email addresses commit 9b0a53ed1cd5995efae0d71e1941d1db4ef6ba39 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Nov 2 14:54:44 2018 +0300 We don't need preload_restart() here commit 0bd17bd43890423e1e98a5925f11cea93da3df55 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Nov 2 14:44:30 2018 +0300 EG(*) may be not initializd at this point - use CG(*). commit b610467051d8a3687a60ffc2957bc353cb6b3bd4 Merge: 3a9d90f74a 67e0138c0d Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Nov 2 11:33:37 2018 +0300 Merge branch 'master' into preload * master: Future-proof email addresses... Update email addresses. We're still @Zend, but future proofing it... commit 3a9d90f74a3d890cb59658d604d5a202e3aee256 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Nov 1 15:19:48 2018 +0300 Fexed resolution of method clones commit aea85c65bd1795d0750dee6ac0e476acd2ac9dd7 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Nov 1 11:45:50 2018 +0300 Prevent inlining of method copied from trait commit 36b644fbb738e7548ccb436e5d04d653d93cce14 Merge: 7a20781d2e b91690c892 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Nov 1 10:56:02 2018 +0300 Merge branch 'master' into preload * master: Fix stray newline that caused this test to fail Fix session tests that fail if error_log is set This test needs to log to stdout Fix error condition Fixed bug #77081 ftruncate() changes seek pointer in c mode Fix and improve test case commit 7a20781d2ee694262f913a612d8b0b6a24ceff7b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 31 00:52:46 2018 +0300 Added test commit 4a57b5d563f9c9616f3c236f57ccd09d8a66f146 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 31 00:50:21 2018 +0300 Fixed preloading of classes linked with traits commit 68c4f99e23695e74eafa43097ecab62392bad3ee Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Oct 30 16:25:14 2018 +0300 Added test commit 38ab7ef4cf429dcfd5dfb18f844242cdf3a4d61f Merge: eb6e2c529f bf38e6c10a Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Oct 30 16:14:39 2018 +0300 Merge branch 'master' into preload * master: Keep original value of "prototype" commit eb6e2c529f8cedf6823346387dd8b0ba6a4f045b Merge: 562049510f 2fefa8c61e Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Oct 30 15:35:39 2018 +0300 Merge branch 'master' into preload * master: Call function_add_ref() in proper place Updated to version 2018.7 (2018g) Updated to version 2018.7 (2018g) Updated to version 2018.7 (2018g) Reslove inherited op_array references once afrer all optimizations. commit 562049510f605c21cd46fc3b6f97ed15bfe7b0dc Merge: e806cb732a 4828fb7b6b Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Oct 30 10:29:49 2018 +0300 Merge branch 'master' into preload * master: [ci skip] Update NEWS [ci skip] Update NEWS [ci skip] Update NEWS fix bug #77079 Add missing null initialization Remove redundant mbfl_string_init calls Use zend_string for mbstring last encoding cache commit e806cb732a2a3f1e409528988a0571421c541078 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 29 22:32:15 2018 +0300 Fixed double-free commit 2f697ef8af0e7b21c47707b2d688880e8c987a8b Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 29 22:07:32 2018 +0300 typo commit c559f22b3e61b38761831d9610889d28ba6875e0 Merge: 310631cc05 ea2e67876a Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 29 21:59:27 2018 +0300 Merge branch 'master' into preload * master: Stop Apache if PHP wasn't started successful. Execute zend_post_startup() with module_initialized flag set. Removed dead code Fix mb_strrpos() with encoding passed as 3rd param commit 310631cc0565ac87091c4f1a8a9f739a13e7e778 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 29 16:48:42 2018 +0300 Stop Apache if PHP wasn't started successful. commit 0a24d7ba8f3280507c9663b32e14030212cf8491 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 29 16:25:49 2018 +0300 Avoid use-after-free in main thread commit 17a3cb4a2ab271c2b2357c04e36efa64e02444ff Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 29 15:25:17 2018 +0300 Execute zend_post_startup() with module_initialized flag set. commit 6d4b22c518bec956e9632fad4329360304d17fd7 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 29 14:12:20 2018 +0300 Override SAPI.ub_write and SAPI.flush for preloading commit 386c9d3470168f70afe5d3b72a58ea0c0da1519c Merge: d7fbb4d402 359f19edc9 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 29 13:49:24 2018 +0300 Merge branch 'master' into preload * master: Optimize substr() edge-case conditions [ci skip] Update UPGRADING Fix #71592: External entity processing never fails Add TIDY_TAG_* constants supported by libtidy 5 Add is_iterable to opcache Optimizer commit d7fbb4d402a18c8fd1c49e0c92afd9f9e513bc7a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Oct 26 13:11:54 2018 +0300 Restore preload state if it was already loaded in another process. commit 0fe9ea1c07822b5d4672cece2c180bf9795e16e4 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Oct 26 12:29:06 2018 +0300 Removed dead code commit 3a2d1bcc1fd27b6983522c262931fc0187c0afef Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Oct 26 00:19:40 2018 +0300 Support for builds without ZEND_SIGNALS commit e6b76ecb4beea3b922bf7529050e3828f745dedb Merge: 4531fbf931 68694c9997 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Oct 25 23:43:25 2018 +0300 Merge branch 'master' into preload * master: Don't wrap php_module_shutdown() with zend_try. executor_globals are released in ZTS build, and this leads to crash. [ci skip] Fix indentation in UPGRADING. commit 4531fbf9310bfb7bb579134cc84e8c10c5d42059 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Oct 25 22:44:49 2018 +0300 Disable linking and preloading of classes those parent or one of interface or trait is an internal class. commit a594a618ce98242c1d273eb9ede75b4f6b4635d8 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Oct 25 22:30:51 2018 +0300 Cleanup - remove useless ZCSG(saved_map_ptr_last) - move preloaded classes/functions clean-up code back into better place commit ab9a40f63cfa1a205b8f853b7e0c2ce61edabb32 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Oct 25 20:52:51 2018 +0300 Added support for preloaded classes/functions in ZTS build commit e3c65db099517082b66dd20ea57e1bda649a7aa5 Merge: 4f57c1e029 33e777acbf Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Oct 25 20:52:26 2018 +0300 Merge branch 'master' into preload * master: Improved shared interned strings handling. The previous implementation worked incorrectly in ZTS build. It changed strings only in function/class tables of one thread. Now all threads gets the same shared interned strings. Also, on shutdown, we don't try to replace SHM interned strings back to process strings, but delay dettachment of SHM instead. Don't use request heap at shutdown Don't optimize function if inference failed Fixed bug #77058 Improve "narrowing" error message bump versions commit 4f57c1e029ce9c24bd699ea61b05973c4665bc32 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Oct 25 15:29:58 2018 +0300 Cleanup (move preload_shutdown() call to better place) commit 26587a95c071cf9dd098199eb3708fca8adae243 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Oct 25 14:30:51 2018 +0300 eol commit d70cb10480fdc7d814495150cd48e43d4147138f Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Oct 25 14:30:20 2018 +0300 cleanup commit aabe685dbb887e91c240b6c5553193889bcfc540 Merge: d9fc51bc3b 40808ac41e Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Oct 25 12:42:51 2018 +0300 Merge branch 'master' into preload * master: Remove unused var Remove ext/json parser files generated by bison Fix run-tests.php for running phpdbg and certain test sections Normalize .gitignore commit d9fc51bc3bdfbd7f4149a884b09e3c09a41f7a8d Merge: b5ffba0faf b6ef8998d5 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 24 15:59:24 2018 +0300 Merge branch 'master' into preload * master: Fixed reseting of interned strings buffer. commit b5ffba0fafb4d940336d5f5fe93950dad1d8d779 Merge: e4a7ef0c43 a404383118 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 24 12:46:28 2018 +0300 Merge branch 'master' into preload * master: Fixed build in directory different from source commit e4a7ef0c431ec97cdd00e44dfa0ef17887d1e5e3 Merge: 811f20aaa5 d1e14e2cc0 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 24 11:59:43 2018 +0300 Merge branch 'master' into preload * master: (29 commits) Make php_plain_files_wrapper to be writable (workaround for swoole) Remove phpdbg parser files generated by bison Fix conflicts in phpdbg parser Refetetch function name on exceptional path to allow better code on fast code path. fix typo in sysvsem.c Fixed bug #50675 bump to 7.2.13-dev [ci skip] Update NEWS wrt. php-7.3.0RC4 tagging Inlining in the most frequently used code paths Fixed test failurs introduced by 9c144e0d8217d1ef7a83c2498214308b21af749f Use persistent strings only for persistent connections Fix accessibility checks for dynamic properties Updated to version 2018.6 (2018f) Updated to version 2018.6 (2018f) Updated to version 2018.6 (2018f) Fix arginfo and clean up fpm_get_status Defragment two Zend related Makefile fragments together [ci skip] Remove automake and aclocal in comments Fix #75282: xmlrpc_encode_request() crashes Fix tests for ICU 63.1 ... commit 811f20aaa5030035666d9f325dd7c64632c70a50 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 22 14:10:49 2018 +0300 Added information about preloading to opcache_get_status() commit 093e8b1bbffdc07d217a543613ea14c3eeac710e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Oct 19 13:46:23 2018 +0300 Added warning message commit a2ba970ce3d0ac51ebfbe1bfc2dc7b99b9750a75 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Oct 19 13:35:40 2018 +0300 Added test commit b67e28367c11db50360e664a7ad6ac95b393f2e4 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Oct 19 13:33:12 2018 +0300 Don't preload functions declared at run-time. commit b0139dc22854ee000586ef83c149d7d25181da60 Merge: a609520adb 3fe698b904 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Oct 19 13:23:14 2018 +0300 Merge branch 'master' into preload * master: Mark "top-level" functions. Don't initialize static_member_tables during start-up, when inherit internal classes. [ci skip] Update NEWS [ci skip] Update NEWS [ci skip] Update NEWS Fix #77035: The phpize and ./configure create redundant .deps file Remove outdated PEAR artefacts Fix tests/output/bug74815.phpt generating errors.log Revert "Use C++ symbols, when C++11 or upper is compiled" Use C++ symbols, when C++11 or upper is compiled Added new line Remove stamp-h Move all testing docs to qa.php.net Fix a typo in UPGRADING.INTERNALS Fix test when it's run on another drive [ci skip] Update UPGRADING wrt. tidyp support Fixed incorrect reallocation Fix #77027: tidy::getOptDoc() not available on Windows Run CI tests under opcache.protect_memory=1 commit a609520adbc0bf12701d467bae4a016fde43231e Merge: ac8f45f61b b6ac50f9e6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 17:01:05 2018 +0300 Merge branch 'master' into preload * master: Fixed comment Micro optimizations Mark "top-level" classes commit ac8f45f61b561af9aee629232bc3705143ceaac3 Merge: 632b30b545 d57cd36e47 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 15:53:41 2018 +0300 Merge branch 'master' into preload * master: Immutable clases and op_arrays. commit 632b30b5451c8fdf0879a3ba4d937ff4ecfc8ce7 Merge: d33908a99a cd0c36c3f9 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 15:04:43 2018 +0300 Merge branch 'immutable' into preload * immutable: Remove the "auto" encoding Fixed bug #77025 Add vtbls for EUC-TW encoding commit cd0c36c3f943849e5b97a8dbe2dd029fbeab3df9 Merge: 4740dabb84 ad6738e886 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 14:43:38 2018 +0300 Merge branch 'master' into immutable * master: Remove the "auto" encoding Fixed bug #77025 Add vtbls for EUC-TW encoding commit d33908a99a3c746f188e268df3db541591f6fcc2 Merge: 21e0bebca3 4740dabb84 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 14:14:23 2018 +0300 Merge branch 'immutable' into preload * immutable: Reverted back ce->iterator_funcs_ptr. Initialize ce->iterator_funcs_ptr fields in immutable classes. commit 4740dabb843c6d4f7f866b4a2456073c9eaf4c77 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 14:12:28 2018 +0300 Reverted back ce->iterator_funcs_ptr. Initialize ce->iterator_funcs_ptr fields in immutable classes. commit 21e0bebca3e6fff3c3484ee46f9aa3ac4e98eaeb Merge: c78277ae84 ad7a78b253 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 12:29:59 2018 +0300 Merge branch 'immutable' into preload * immutable: Added comment Added type cast Moved static class members initialization into the proper place. Removed redundand assertion Removed duplicate code Hide offset encoding magic in ZEND_MAP_PTR_IS_OFFSET(), ZEND_MAP_PTR_OFFSET2PTR() and ZEND_MAP_PTR_PTR2OFFSET() macros. typo Remove unused variable makefile_am_files Classify object handlers are required/optional Add support for getting SKIP_TAGSTART and SKIP_WHITE options Remove some obsolete config_vars.mk occurrences Remove bsd_converted from .gitignore Remove configuration parser and scanners ignores Remove obsolete buildconf.stamp from .gitignore [ci skip] Add magicdata.patch exception to .gitignore Remove outdated ext/spl/examples items from .gitignore Remove unused test.inc in ext/iconv/tests commit ad7a78b253be970db70c2251e66f9297d8e7f829 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:46:30 2018 +0300 Added comment commit 0276ea51875bab37be01a4dc5e5a047c5698c571 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:42:43 2018 +0300 Added type cast commit c63fc5d5f19c58498108d1698055b2b442227eb3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:36:51 2018 +0300 Moved static class members initialization into the proper place. commit b945548e9306b1826c881918858b5e5aa3eb3002 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:21:03 2018 +0300 Removed redundand assertion commit d5a41088401814c829847db212488f8aae39bcd2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:19:13 2018 +0300 Removed duplicate code commit 8dadca8864e66de70a24bdf1181bcf7dd8fb27d7 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:05:43 2018 +0300 Hide offset encoding magic in ZEND_MAP_PTR_IS_OFFSET(), ZEND_MAP_PTR_OFFSET2PTR() and ZEND_MAP_PTR_PTR2OFFSET() macros. commit 9ef07c88bd76801e2d4fbfeab3ebfd6e6a67ac5f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 10:48:29 2018 +0300 typo commit a06f0f3d3aba53e766046221ee44fb9720389ecc Merge: 94099586ec 3412345ffe Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 10:47:07 2018 +0300 Merge branch 'master' into immutable * master: Remove unused variable makefile_am_files Classify object handlers are required/optional Add support for getting SKIP_TAGSTART and SKIP_WHITE options Remove some obsolete config_vars.mk occurrences Remove bsd_converted from .gitignore Remove configuration parser and scanners ignores Remove obsolete buildconf.stamp from .gitignore [ci skip] Add magicdata.patch exception to .gitignore Remove outdated ext/spl/examples items from .gitignore Remove unused test.inc in ext/iconv/tests commit c78277ae84b21067744d1701949e4e1fadd8872a Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Oct 16 17:25:35 2018 +0300 Preloadsing support for opcache restart commit f76a955c02f6a033d4656d5e0d9dad9a8e83cc86 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Oct 16 13:52:36 2018 +0300 Fixed incorrect signal handlers overriding commit 0810ce0d8165d4b752267f035f9fa0aaa1698ceb Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 15 23:38:48 2018 +0300 An attempt to implemnt "preloading" ability. commit 94099586ec599117581ca01c15b1f6c5f749e23a Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 15 23:34:01 2018 +0300 Immutable clases and op_arrays
2018-11-14 21:46:05 +08:00
ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
if (_idx == EG(persistent_classes_count)) {
break;
}
destroy_zend_class(zv);
zend_string_release_ex(key, 0);
} ZEND_HASH_MAP_FOREACH_END_DEL();
2001-10-23 09:23:36 +08:00
}
while (EG(symtable_cache_ptr) > EG(symtable_cache)) {
EG(symtable_cache_ptr)--;
zend_hash_destroy(*EG(symtable_cache_ptr));
2014-04-25 15:54:10 +08:00
FREE_HASHTABLE(*EG(symtable_cache_ptr));
}
zend_hash_destroy(&EG(included_files));
zend_stack_destroy(&EG(user_error_handlers_error_reporting));
zend_stack_destroy(&EG(user_error_handlers));
zend_stack_destroy(&EG(user_exception_handlers));
zend_objects_store_destroy(&EG(objects_store));
if (EG(in_autoload)) {
zend_hash_destroy(EG(in_autoload));
FREE_HASHTABLE(EG(in_autoload));
}
if (EG(ht_iterators) != EG(ht_iterators_slots)) {
efree(EG(ht_iterators));
}
}
2016-03-19 02:30:29 +08:00
#if ZEND_DEBUG
if (EG(ht_iterators_used) && !CG(unclean_shutdown)) {
zend_error(E_WARNING, "Leaked %" PRIu32 " hashtable iterators", EG(ht_iterators_used));
}
#endif
2020-08-31 16:14:39 +08:00
/* Check whether anyone is hogging the trampoline. */
ZEND_ASSERT(EG(trampoline).common.function_name == NULL || CG(unclean_shutdown));
Fix "forech" statemt behaviour according to https://wiki.php.net/rfc/php7_foreach Squashed commit of the following: commit 1e41295097576dbce6c197ddb7507c07ccae3cbe Author: Dmitry Stogov <dmitry@zend.com> Date: Sat Jan 31 07:28:58 2015 +0300 Generalize HashTableIterator API to allows its usage without involvement of HashTable.nInternalPonter commit 5406f21b11e563069d64045e599693b51c444b63 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:43 2015 +0300 Reduced alghorithms complexity commit b37f1d58d2a141b6e1d980a461ccb588d4317d2e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:30 2015 +0300 Fixed test name commit fb2d079645829b12ed4e55a461034df6400bc430 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:05 2015 +0300 API cleanup commit 08302c0d6d1cab279b9f2129df03a057baddf2ff Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 14:20:46 2015 +0300 Make array_splice() to preserve foreach hash position commit cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 12:24:31 2015 +0300 Make internal function, operation on array passed by reference, to preserve foreach hash position commit 5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 09:49:35 2015 +0300 Implement consistent behavior for foreach by value over plain object commit 4c5b385ff53ae9f0b52572e98c4db801f56603b0 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 07:56:37 2015 +0300 More careful iterators update. commit 721fc9e80d2ee8f2cd79c8c3cdceffae2c72de92 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:43:28 2015 +0300 Added new test commit 15a23b1218b3e38630d677751a975907daa2cd54 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:05:02 2015 +0300 Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc/php7_foreach#implementation_details) commit 10a3260b1f16b6075fd8140f673dfef4d5efea91 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:04:44 2015 +0300 New test commit eef80c583762d1e98d177cdbb27e3a8a6b0c4539 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 16:52:21 2015 +0300 Fixed foreach by reference iteration over constant array commit 61e739187391661e2d541947bec25d7dcc4479f3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 14:59:54 2015 +0300 Fixed temporary variable re-allocation pass commit 92e90c09f085c22707ff4a59201f016f56e0ef8b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 12:44:57 2015 +0300 Fixed operand destruction in case of exceptions in iterator commit dd2a36a2074bbb0cb31de00b66dcf2812d6d753f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 10:02:34 2015 +0300 Use GET_OP1_ZVAL_PTR_DEREF() (IS_TMP_VAR and IS_CONST can't be IS_REFERENCE) commit 4638f7b91407c48710007af82a68da0007c820f2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 07:43:28 2015 +0300 Change "foreach" statement behavior (this is just a PoC yet) - "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented)
2015-02-12 18:57:12 +08:00
EG(ht_iterators_used) = 0;
zend_shutdown_fpu();
1999-04-08 02:10:10 +08:00
}
/* }}} */
1999-04-08 02:10:10 +08:00
2004-03-16 18:14:57 +08:00
/* return class name and "::" or "". */
2014-12-14 06:06:14 +08:00
ZEND_API const char *get_active_class_name(const char **space) /* {{{ */
2004-03-16 18:14:57 +08:00
{
zend_function *func;
2014-12-14 06:06:14 +08:00
if (!zend_is_executing()) {
2004-03-16 18:14:57 +08:00
if (space) {
*space = "";
}
return "";
}
func = zend_active_function();
switch (func->type) {
2004-03-16 18:14:57 +08:00
case ZEND_USER_FUNCTION:
case ZEND_INTERNAL_FUNCTION:
{
zend_class_entry *ce = func->common.scope;
2004-03-16 18:14:57 +08:00
if (space) {
*space = ce ? "::" : "";
}
return ce ? ZSTR_VAL(ce->name) : "";
2004-03-16 18:14:57 +08:00
}
default:
if (space) {
*space = "";
}
return "";
}
}
/* }}} */
2004-03-16 18:14:57 +08:00
2014-12-14 06:06:14 +08:00
ZEND_API const char *get_active_function_name(void) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_function *func;
2014-12-14 06:06:14 +08:00
if (!zend_is_executing()) {
2002-04-21 04:14:14 +08:00
return NULL;
}
func = zend_active_function();
switch (func->type) {
1999-04-08 02:10:10 +08:00
case ZEND_USER_FUNCTION: {
zend_string *function_name = func->common.function_name;
1999-04-08 02:10:10 +08:00
if (function_name) {
return ZSTR_VAL(function_name);
1999-04-08 02:10:10 +08:00
} else {
return "main";
}
}
break;
case ZEND_INTERNAL_FUNCTION:
return ZSTR_VAL(func->common.function_name);
1999-04-08 02:10:10 +08:00
break;
default:
return NULL;
}
}
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API zend_function *zend_active_function_ex(zend_execute_data *execute_data)
{
zend_function *func = EX(func);
/* Resolve function if op is a frameless call. */
if (ZEND_USER_CODE(func->type)) {
const zend_op *op = EX(opline);
if (ZEND_OP_IS_FRAMELESS_ICALL(op->opcode)) {
func = ZEND_FLF_FUNC(op);
}
}
return func;
}
ZEND_API zend_string *get_active_function_or_method_name(void) /* {{{ */
{
ZEND_ASSERT(zend_is_executing());
return get_function_or_method_name(zend_active_function());
}
/* }}} */
ZEND_API zend_string *get_function_or_method_name(const zend_function *func) /* {{{ */
{
if (func->common.scope && func->common.function_name) {
return zend_create_member_string(func->common.scope->name, func->common.function_name);
}
return func->common.function_name ? zend_string_copy(func->common.function_name) : ZSTR_INIT_LITERAL("main", 0);
}
/* }}} */
ZEND_API const char *get_active_function_arg_name(uint32_t arg_num) /* {{{ */
{
if (!zend_is_executing()) {
return NULL;
}
zend_function *func = zend_active_function();
return get_function_arg_name(func, arg_num);
}
/* }}} */
ZEND_API const char *get_function_arg_name(const zend_function *func, uint32_t arg_num) /* {{{ */
{
if (!func || arg_num == 0 || func->common.num_args < arg_num) {
return NULL;
}
if (func->type == ZEND_USER_FUNCTION || (func->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
return ZSTR_VAL(func->common.arg_info[arg_num - 1].name);
} else {
return ((zend_internal_arg_info*) func->common.arg_info)[arg_num - 1].name;
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API const char *zend_get_executed_filename(void) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_string *filename = zend_get_executed_filename_ex();
return filename != NULL ? ZSTR_VAL(filename) : "[no active file]";
1999-04-08 02:10:10 +08:00
}
/* }}} */
1999-04-08 02:10:10 +08:00
2015-03-05 23:18:39 +08:00
ZEND_API zend_string *zend_get_executed_filename_ex(void) /* {{{ */
{
zend_string *filename_override = EG(filename_override);
if (filename_override != NULL) {
return filename_override;
}
2015-03-05 23:18:39 +08:00
zend_execute_data *ex = EG(current_execute_data);
while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
ex = ex->prev_execute_data;
}
if (ex) {
return ex->func->op_array.filename;
} else {
return NULL;
}
}
/* }}} */
ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_long lineno_override = EG(lineno_override);
if (lineno_override != -1) {
return lineno_override;
}
zend_execute_data *ex = EG(current_execute_data);
while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
ex = ex->prev_execute_data;
}
2014-07-07 19:50:44 +08:00
if (ex) {
if (!ex->opline) {
/* Missing SAVE_OPLINE()? Falling back to first line of function */
return ex->func->op_array.opcodes[0].lineno;
}
if (EG(exception) && ex->opline->opcode == ZEND_HANDLE_EXCEPTION &&
ex->opline->lineno == 0 && EG(opline_before_exception)) {
return EG(opline_before_exception)->lineno;
}
return ex->opline->lineno;
} else {
return 0;
}
1999-04-08 02:10:10 +08:00
}
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API zend_class_entry *zend_get_executed_scope(void) /* {{{ */
{
zend_execute_data *ex = EG(current_execute_data);
while (1) {
if (!ex) {
return NULL;
} else if (ex->func && (ZEND_USER_CODE(ex->func->type) || ex->func->common.scope)) {
return ex->func->common.scope;
}
ex = ex->prev_execute_data;
}
}
/* }}} */
ZEND_API bool zend_is_executing(void) /* {{{ */
{
return EG(current_execute_data) != 0;
}
/* }}} */
ZEND_API zend_result ZEND_FASTCALL zval_update_constant_with_ctx(zval *p, zend_class_entry *scope, zend_ast_evaluate_ctx *ctx)
{
if (Z_TYPE_P(p) == IS_CONSTANT_AST) {
zend_ast *ast = Z_ASTVAL_P(p);
if (ast->kind == ZEND_AST_CONSTANT) {
zend_string *name = zend_ast_get_constant_name(ast);
zval *zv = zend_get_constant_ex(name, scope, ast->attr);
if (UNEXPECTED(zv == NULL)) {
return FAILURE;
2013-11-07 02:21:07 +08:00
}
zval_ptr_dtor_nogc(p);
ZVAL_COPY_OR_DUP(p, zv);
2013-11-07 02:21:07 +08:00
} else {
zval tmp;
bool short_circuited;
// Increase the refcount during zend_ast_evaluate to avoid releasing the ast too early
// on nested calls to zval_update_constant_ex which can happen when retriggering ast
// evaluation during autoloading.
zend_ast_ref *ast_ref = Z_AST_P(p);
bool ast_is_refcounted = !(GC_FLAGS(ast_ref) & GC_IMMUTABLE);
if (ast_is_refcounted) {
GC_ADDREF(ast_ref);
}
zend_result result = zend_ast_evaluate_ex(&tmp, ast, scope, &short_circuited, ctx) != SUCCESS;
if (ast_is_refcounted && !GC_DELREF(ast_ref)) {
rc_dtor_func((zend_refcounted *)ast_ref);
}
if (UNEXPECTED(result != SUCCESS)) {
return FAILURE;
}
zval_ptr_dtor_nogc(p);
ZVAL_COPY_VALUE(p, &tmp);
2001-07-16 19:41:06 +08:00
}
1999-04-08 02:10:10 +08:00
}
return SUCCESS;
}
/* }}} */
ZEND_API zend_result ZEND_FASTCALL zval_update_constant_ex(zval *p, zend_class_entry *scope)
{
zend_ast_evaluate_ctx ctx = {0};
return zval_update_constant_with_ctx(p, scope, &ctx);
}
ZEND_API zend_result ZEND_FASTCALL zval_update_constant(zval *pp) /* {{{ */
{
return zval_update_constant_ex(pp, EG(current_execute_data) ? zend_get_executed_scope() : CG(active_class_entry));
}
/* }}} */
1999-08-06 23:24:10 +08:00
zend_result _call_user_function_impl(zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[], HashTable *named_params) /* {{{ */
2003-05-21 00:44:42 +08:00
{
zend_fcall_info fci;
fci.size = sizeof(fci);
if (object) {
ZEND_ASSERT(Z_TYPE_P(object) == IS_OBJECT);
fci.object = Z_OBJ_P(object);
} else {
fci.object = NULL;
}
ZVAL_COPY_VALUE(&fci.function_name, function_name);
fci.retval = retval_ptr;
fci.param_count = param_count;
fci.params = params;
fci.named_params = named_params;
2014-12-14 06:06:14 +08:00
return zend_call_function(&fci, NULL);
2003-05-21 00:44:42 +08:00
}
/* }}} */
2003-05-21 00:44:42 +08:00
zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-08-26 01:28:33 +08:00
uint32_t i;
zend_execute_data *call;
zend_fcall_info_cache fci_cache_local;
zend_function *func;
2019-04-11 07:08:32 +08:00
uint32_t call_info;
void *object_or_called_scope;
zend_class_entry *orig_fake_scope;
ZVAL_UNDEF(fci->retval);
if (!EG(active)) {
return FAILURE; /* executor is already inactive */
}
if (EG(exception)) {
if (fci_cache) {
zend_release_fcall_info_cache(fci_cache);
}
return SUCCESS; /* we would result in an instable executor otherwise */
}
ZEND_ASSERT(fci->size == sizeof(zend_fcall_info));
if (!fci_cache || !fci_cache->function_handler) {
char *error = NULL;
if (!fci_cache) {
fci_cache = &fci_cache_local;
}
if (!zend_is_callable_ex(&fci->function_name, fci->object, 0, NULL, fci_cache, &error)) {
ZEND_ASSERT(error && "Should have error if not callable");
zend_string *callable_name
= zend_get_callable_name_ex(&fci->function_name, fci->object);
zend_throw_error(NULL, "Invalid callback %s, %s", ZSTR_VAL(callable_name), error);
efree(error);
zend_string_release_ex(callable_name, 0);
return SUCCESS;
2003-05-21 00:44:42 +08:00
}
ZEND_ASSERT(!error);
}
func = fci_cache->function_handler;
2019-04-11 07:08:32 +08:00
if ((func->common.fn_flags & ZEND_ACC_STATIC) || !fci_cache->object) {
object_or_called_scope = fci_cache->called_scope;
call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC;
} else {
2021-04-15 20:31:45 +08:00
object_or_called_scope = fci_cache->object;
2019-04-11 07:08:32 +08:00
call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_HAS_THIS;
}
2019-04-11 07:08:32 +08:00
call = zend_vm_stack_push_call_frame(call_info,
func, fci->param_count, object_or_called_scope);
if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_DEPRECATED)) {
zend_deprecated_function(func);
if (UNEXPECTED(EG(exception))) {
zend_vm_stack_free_call_frame(call);
return SUCCESS;
2006-02-26 02:25:45 +08:00
}
}
for (i=0; i<fci->param_count; i++) {
zval *param = ZEND_CALL_ARG(call, i+1);
zval *arg = &fci->params[i];
bool must_wrap = 0;
if (UNEXPECTED(Z_ISUNDEF_P(arg))) {
/* Allow forwarding undef slots. This is only used by Closure::__invoke(). */
ZVAL_UNDEF(param);
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_MAY_HAVE_UNDEF);
continue;
}
1999-04-08 02:10:10 +08:00
if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
if (UNEXPECTED(!Z_ISREF_P(arg))) {
2020-07-07 15:30:24 +08:00
if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
/* By-value send is not allowed -- emit a warning,
* and perform the call with the value wrapped in a reference. */
2020-07-06 16:37:46 +08:00
zend_param_must_be_ref(func, i + 1);
must_wrap = 1;
if (UNEXPECTED(EG(exception))) {
ZEND_CALL_NUM_ARGS(call) = i;
cleanup_args:
zend_vm_stack_free_args(call);
zend_vm_stack_free_call_frame(call);
return SUCCESS;
}
1999-08-06 23:24:10 +08:00
}
}
} else {
if (Z_ISREF_P(arg) &&
Squashed commit of the following: commit 2399fc84c541da9c2176c5b7f6dd039a3c84dc64 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Apr 10 12:38:08 2015 +0300 Removed useless assignment commit 796b6338174348eee0d74a67706d77b7ce1a60c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Apr 10 12:35:31 2015 +0300 Fixed execution with overriden zend_execute_ex() commit 4a9fb125aa999059f8bc42ebb6ee573c7866b35b Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Apr 10 02:02:58 2015 +0300 Fixed executor without global registers commit d456c30e00589ccda35a4b57ae903ef2d3c07d95 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Apr 10 01:30:35 2015 +0300 Restored original behavior for tests/classes/__call_004.phpt commit 479646d37fef050536f1afb12b082618f1f1a3d0 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Apr 10 00:32:17 2015 +0300 Fixed test. We don't keep stack frame for fake function anymore. commit 9ae61e33e24b2c811d4ab1ca4ab22847c64a780e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Apr 10 00:30:09 2015 +0300 Use ZEND_ACC_CALL_VIA_TRAMPOLINE instead of ZEND_ACC_CALL_VIA_HANDLER. Keep ZEND_ACC_CALL_VIA_HANDLER for compatibility. commit 0a8403a2a0c27aa3db271774f8559739a6b8400e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Apr 10 00:05:43 2015 +0300 Rename PROXY_CALL into CALL_TRAMPLINE. Generalize API to allow reuse EG(trampline) for other purposes. commit 4ea0525c10554e36185a0b8b6303106813b6a1c2 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Apr 9 23:22:25 2015 +0300 Reuse EG(proxy_call_op) for all proxy. Move proxy related functions from zend_objects_API to zend_object_handlers. commit 529bf737ca388ad56fb4ae20ccb81e6276f25ec0 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Apr 9 21:42:23 2015 +0300 Accurate use of proxy_call commit 5d62837d5ba3855743fe1981786ebd65d9da0b63 Merge: 83e749f 690843f Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Apr 9 19:40:00 2015 +0300 Merge branch 'master' into opcodefy-call * master: Fixed GOTO executor Fixed typo Changed ArrayIterator implementation using zend_hash_iterator_... API. Allowed modification of itterated ArrayObject using the same behavior as proposed in `Fix "foreach" behavior`. Removed "Array was modified outside object and internal position is no longer valid" hack. commit 83e749ff3b6623e39b236a72e9b907d5b788ae5e Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Apr 9 19:39:10 2015 +0300 Improved ZEND_PROXY_CALL commit 0c829afc534e6d5ff27a0dea3a4815da303bd1ef Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Apr 9 15:14:49 2015 +0300 Reverted white-space changes commit df65144488afa3e9020d75e1ada5529b138afc5a Merge: 5fd2f97 97756d9 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Apr 9 14:37:07 2015 +0300 Merge branch 'opcodefy-call' of github.com:laruence/php-src into opcodefy-call * 'opcodefy-call' of github.com:laruence/php-src: Ready for PR Fixed static call Improve performance by using prealloated op_arrray Respect called_scope Support internal magical __call/__callStatic opcode-fy magical __callStatic Opcode-fy magical __call commit 97756d9190e07a072a7b48135304dc25a964845f Author: Xinchen Hui <laruence@gmail.com> Date: Thu Apr 9 19:07:59 2015 +0800 Ready for PR commit 74f993084627061e783645a866390b68e2981698 Author: Xinchen Hui <laruence@gmail.com> Date: Thu Apr 9 19:03:00 2015 +0800 Fixed static call commit ec1d9eb592db0c3b7b0e3d21e7f445ed8bccfd4d Author: Xinchen Hui <laruence@gmail.com> Date: Thu Apr 9 18:23:17 2015 +0800 Improve performance by using prealloated op_arrray commit df7fbbf949c99f2c5ae3da2a1199235651c7cc82 Author: Xinchen Hui <laruence@gmail.com> Date: Thu Apr 9 15:10:02 2015 +0800 Respect called_scope commit 769d1d59fb48b6f7f93d7412eefbf26135fa3e59 Author: Xinchen Hui <laruence@gmail.com> Date: Thu Apr 9 12:19:23 2015 +0800 Support internal magical __call/__callStatic commit a980fedd5b0e0683713dd4f6eaad62adf4b4732f Author: Xinchen Hui <laruence@gmail.com> Date: Wed Apr 8 18:35:41 2015 +0800 opcode-fy magical __callStatic commit 73855f7d53baa2efc2b8a88314f51c784c81b59d Author: Xinchen Hui <laruence@gmail.com> Date: Wed Apr 8 14:21:55 2015 +0800 Opcode-fy magical __call
2015-04-11 04:01:00 +08:00
!(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
/* don't separate references for __call */
arg = Z_REFVAL_P(arg);
}
1999-08-06 23:24:10 +08:00
}
if (EXPECTED(!must_wrap)) {
ZVAL_COPY(param, arg);
} else {
2020-08-24 22:23:19 +08:00
Z_TRY_ADDREF_P(arg);
ZVAL_NEW_REF(param, arg);
}
1999-04-08 02:10:10 +08:00
}
if (fci->named_params) {
zend_string *name;
zval *arg;
uint32_t arg_num = ZEND_CALL_NUM_ARGS(call) + 1;
bool have_named_params = 0;
ZEND_HASH_FOREACH_STR_KEY_VAL(fci->named_params, name, arg) {
bool must_wrap = 0;
zval *target;
if (name) {
void *cache_slot[2] = {NULL, NULL};
have_named_params = 1;
target = zend_handle_named_arg(&call, name, &arg_num, cache_slot);
if (!target) {
goto cleanup_args;
}
} else {
if (have_named_params) {
zend_throw_error(NULL,
"Cannot use positional argument after named argument");
goto cleanup_args;
}
zend_vm_stack_extend_call_frame(&call, arg_num - 1, 1);
target = ZEND_CALL_ARG(call, arg_num);
}
if (ARG_SHOULD_BE_SENT_BY_REF(func, arg_num)) {
if (UNEXPECTED(!Z_ISREF_P(arg))) {
if (!ARG_MAY_BE_SENT_BY_REF(func, arg_num)) {
/* By-value send is not allowed -- emit a warning,
* and perform the call with the value wrapped in a reference. */
zend_param_must_be_ref(func, arg_num);
must_wrap = 1;
if (UNEXPECTED(EG(exception))) {
goto cleanup_args;
}
}
}
} else {
if (Z_ISREF_P(arg) &&
!(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
/* don't separate references for __call */
arg = Z_REFVAL_P(arg);
}
}
if (EXPECTED(!must_wrap)) {
ZVAL_COPY(target, arg);
} else {
Z_TRY_ADDREF_P(arg);
ZVAL_NEW_REF(target, arg);
}
if (!name) {
ZEND_CALL_NUM_ARGS(call)++;
arg_num++;
}
} ZEND_HASH_FOREACH_END();
}
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_MAY_HAVE_UNDEF)) {
/* zend_handle_undef_args assumes prev_execute_data is initialized. */
call->prev_execute_data = NULL;
if (zend_handle_undef_args(call) == FAILURE) {
zend_vm_stack_free_args(call);
zend_vm_stack_free_call_frame(call);
return SUCCESS;
}
}
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
uint32_t call_info;
GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
call_info = ZEND_CALL_CLOSURE;
if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
call_info |= ZEND_CALL_FAKE_CLOSURE;
}
ZEND_ADD_CALL_FLAG(call, call_info);
}
if (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
fci_cache->function_handler = NULL;
}
orig_fake_scope = EG(fake_scope);
EG(fake_scope) = NULL;
if (func->type == ZEND_USER_FUNCTION) {
uint32_t orig_jit_trace_num = EG(jit_trace_num);
zend_init_func_execute_data(call, &func->op_array, fci->retval);
ZEND_OBSERVER_FCALL_BEGIN(call);
zend_execute_ex(call);
EG(jit_trace_num) = orig_jit_trace_num;
} else {
ZEND_ASSERT(func->type == ZEND_INTERNAL_FUNCTION);
ZVAL_NULL(fci->retval);
call->prev_execute_data = EG(current_execute_data);
EG(current_execute_data) = call;
#if ZEND_DEBUG
bool should_throw = zend_internal_call_should_throw(func, call);
#endif
ZEND_OBSERVER_FCALL_BEGIN(call);
if (EXPECTED(zend_execute_internal == NULL)) {
2012-07-23 05:25:00 +08:00
/* saves one function call if zend_execute_internal is not used */
2014-12-14 06:06:14 +08:00
func->internal_function.handler(call, fci->retval);
2012-07-23 05:25:00 +08:00
} else {
2014-12-14 06:06:14 +08:00
zend_execute_internal(call, fci->retval);
2012-07-23 05:25:00 +08:00
}
#if ZEND_DEBUG
if (!EG(exception) && call->func) {
if (should_throw) {
zend_internal_call_arginfo_violation(call->func);
}
ZEND_ASSERT(!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
zend_verify_internal_return_type(call->func, fci->retval));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(fci->retval) : !Z_ISREF_P(fci->retval));
}
#endif
ZEND_OBSERVER_FCALL_END(call, fci->retval);
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) {
zend_array_release(call->extra_named_params);
}
2014-05-24 21:37:15 +08:00
if (EG(exception)) {
zval_ptr_dtor(fci->retval);
ZVAL_UNDEF(fci->retval);
2008-01-15 02:13:12 +08:00
}
Honor script time limit when calling shutdown functions A time limit can be set on PHP script execution via `set_time_limit` (or .ini file). When the time limit is reached, the OS will notify PHP and `timed_out` and `vm_interrupt` flags are set. While these flags are regularly checked when executing PHP code, once the end of the script is reached, they are not checked while invoking shutdown functions (registered via `register_shutdown_function`). Of course, if the shutdown functions are implemented *in* PHP, then the interrupt flag will be checked while the VM is running PHP bytecode and the timeout will take effect. But if the shutdown functions are built-in (implemented in C), it will not. Since the shutdown functions are invoked through `zend_call_function`, add a check of the `vm_interrupt` flag there. Then, the script time limit will be respected when *entering* each shutdown function. The fact still remains that if a shutdown function is built-in and runs for a long time, script execution will not time out until it finishes and the interpreter tries to invoke the next one. Still, the behavior of scripts with execution time limits will be more consistent after this patch. To make the execution time-out feature work even more precisely, it would be necessary to scrutinize all the built-in functions and add checks of the `vm_interrupt` flag in any which can run for a long time. That might not be worth the effort, though. It should be mentioned that this patch does not solely affect shutdown functions, neither does it solely allow for interruption of running code due to script execution timeout. Anything else which causes `vm_interrupt` to be set, such as the PHP interpreter receiving a signal, will take effect when exiting from an internal function. And not just internal functions which are called because they were registered to run at shutdown; there are other cases where a series of internal functions might run in the midst of a script. In all such cases, it will be possible to interrupt the interpreter now. Closes GH-5543.
2020-05-07 04:02:57 +08:00
/* This flag is regularly checked while running user functions, but not internal
* So see whether interrupt flag was set while the function was running... */
if (zend_atomic_bool_exchange_ex(&EG(vm_interrupt), false)) {
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
Honor script time limit when calling shutdown functions A time limit can be set on PHP script execution via `set_time_limit` (or .ini file). When the time limit is reached, the OS will notify PHP and `timed_out` and `vm_interrupt` flags are set. While these flags are regularly checked when executing PHP code, once the end of the script is reached, they are not checked while invoking shutdown functions (registered via `register_shutdown_function`). Of course, if the shutdown functions are implemented *in* PHP, then the interrupt flag will be checked while the VM is running PHP bytecode and the timeout will take effect. But if the shutdown functions are built-in (implemented in C), it will not. Since the shutdown functions are invoked through `zend_call_function`, add a check of the `vm_interrupt` flag there. Then, the script time limit will be respected when *entering* each shutdown function. The fact still remains that if a shutdown function is built-in and runs for a long time, script execution will not time out until it finishes and the interpreter tries to invoke the next one. Still, the behavior of scripts with execution time limits will be more consistent after this patch. To make the execution time-out feature work even more precisely, it would be necessary to scrutinize all the built-in functions and add checks of the `vm_interrupt` flag in any which can run for a long time. That might not be worth the effort, though. It should be mentioned that this patch does not solely affect shutdown functions, neither does it solely allow for interruption of running code due to script execution timeout. Anything else which causes `vm_interrupt` to be set, such as the PHP interpreter receiving a signal, will take effect when exiting from an internal function. And not just internal functions which are called because they were registered to run at shutdown; there are other cases where a series of internal functions might run in the midst of a script. In all such cases, it will be possible to interrupt the interpreter now. Closes GH-5543.
2020-05-07 04:02:57 +08:00
zend_timeout();
} else if (zend_interrupt_function) {
zend_interrupt_function(EG(current_execute_data));
}
}
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
OBJ_RELEASE(Z_OBJ(call->This));
}
1999-04-08 02:10:10 +08:00
}
EG(fake_scope) = orig_fake_scope;
1999-04-08 02:10:10 +08:00
zend_vm_stack_free_call_frame(call);
if (UNEXPECTED(EG(exception))) {
if (UNEXPECTED(!EG(current_execute_data))) {
zend_throw_exception_internal(NULL);
} else if (EG(current_execute_data)->func &&
ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
zend_rethrow_exception(EG(current_execute_data));
}
}
return SUCCESS;
1999-04-08 02:10:10 +08:00
}
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API void zend_call_known_function(
zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr,
uint32_t param_count, zval *params, HashTable *named_params)
{
zval retval;
zend_fcall_info fci;
zend_fcall_info_cache fcic;
ZEND_ASSERT(fn && "zend_function must be passed!");
fci.size = sizeof(fci);
fci.object = object;
fci.retval = retval_ptr ? retval_ptr : &retval;
fci.param_count = param_count;
fci.params = params;
fci.named_params = named_params;
ZVAL_UNDEF(&fci.function_name); /* Unused */
fcic.function_handler = fn;
fcic.object = object;
fcic.called_scope = called_scope;
zend_result result = zend_call_function(&fci, &fcic);
if (UNEXPECTED(result == FAILURE)) {
if (!EG(exception)) {
zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s",
fn->common.scope ? ZSTR_VAL(fn->common.scope->name) : "",
fn->common.scope ? "::" : "", ZSTR_VAL(fn->common.function_name));
}
}
if (!retval_ptr) {
zval_ptr_dtor(&retval);
}
}
ZEND_API void zend_call_known_instance_method_with_2_params(
zend_function *fn, zend_object *object, zval *retval_ptr, zval *param1, zval *param2)
{
zval params[2];
ZVAL_COPY_VALUE(&params[0], param1);
ZVAL_COPY_VALUE(&params[1], param2);
zend_call_known_instance_method(fn, object, retval_ptr, 2, params);
}
ZEND_API zend_result zend_call_method_if_exists(
zend_object *object, zend_string *method_name, zval *retval,
uint32_t param_count, zval *params)
{
zend_fcall_info fci;
fci.size = sizeof(zend_fcall_info);
fci.object = object;
ZVAL_STR(&fci.function_name, method_name);
fci.retval = retval;
fci.param_count = param_count;
fci.params = params;
fci.named_params = NULL;
zend_fcall_info_cache fcc;
if (!zend_is_callable_ex(&fci.function_name, fci.object, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fcc, NULL)) {
ZVAL_UNDEF(retval);
return FAILURE;
}
return zend_call_function(&fci, &fcc);
}
/* 0-9 a-z A-Z _ \ 0x80-0xff */
static const uint32_t valid_chars[8] = {
0x00000000,
0x03ff0000,
0x97fffffe,
0x07fffffe,
0xffffffff,
0xffffffff,
0xffffffff,
0xffffffff,
};
ZEND_API bool zend_is_valid_class_name(zend_string *name) {
for (size_t i = 0; i < ZSTR_LEN(name); i++) {
unsigned char c = ZSTR_VAL(name)[i];
if (!ZEND_BIT_TEST(valid_chars, c)) {
return 0;
}
}
return 1;
}
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, uint32_t flags) /* {{{ */
{
zend_class_entry *ce = NULL;
zval *zv;
zend_string *lc_name;
zend_string *autoload_name;
uint32_t ce_cache = 0;
2004-11-17 20:06:27 +08:00
if (ZSTR_HAS_CE_CACHE(name) && ZSTR_VALID_CE_CACHE(name)) {
ce_cache = GC_REFCOUNT(name);
ce = GET_CE_CACHE(ce_cache);
if (EXPECTED(ce)) {
return ce;
}
}
if (key) {
lc_name = key;
} else {
if (!ZSTR_LEN(name)) {
return NULL;
}
if (ZSTR_VAL(name)[0] == '\\') {
lc_name = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
zend_str_tolower_copy(ZSTR_VAL(lc_name), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
} else {
lc_name = zend_string_tolower(name);
}
}
2009-04-08 21:17:58 +08:00
zv = zend_hash_find(EG(class_table), lc_name);
if (zv) {
if (!key) {
zend_string_release_ex(lc_name, 0);
}
2019-05-22 17:13:28 +08:00
ce = (zend_class_entry*)Z_PTR_P(zv);
if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED))) {
if ((flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED) ||
((flags & ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED) &&
(ce->ce_flags & ZEND_ACC_NEARLY_LINKED))) {
if (!CG(unlinked_uses)) {
ALLOC_HASHTABLE(CG(unlinked_uses));
zend_hash_init(CG(unlinked_uses), 0, NULL, NULL, 0);
}
zend_hash_index_add_empty_element(CG(unlinked_uses), (zend_long)(uintptr_t)ce);
return ce;
}
2019-05-22 17:13:28 +08:00
return NULL;
}
/* Don't populate CE_CACHE for mutable classes during compilation.
* The class may be freed while persisting. */
if (ce_cache &&
(!CG(in_compilation) || (ce->ce_flags & ZEND_ACC_IMMUTABLE))) {
SET_CE_CACHE(ce_cache, ce);
}
2019-05-22 17:13:28 +08:00
return ce;
}
/* The compiler is not-reentrant. Make sure we autoload only during run-time. */
if ((flags & ZEND_FETCH_CLASS_NO_AUTOLOAD) || zend_is_compiling()) {
if (!key) {
zend_string_release_ex(lc_name, 0);
}
return NULL;
}
if (!zend_autoload) {
if (!key) {
zend_string_release_ex(lc_name, 0);
2014-04-22 05:41:40 +08:00
}
return NULL;
2014-04-22 05:41:40 +08:00
}
2015-01-03 17:22:58 +08:00
/* Verify class name before passing it to the autoloader. */
if (!key && !ZSTR_HAS_CE_CACHE(name) && !zend_is_valid_class_name(name)) {
zend_string_release_ex(lc_name, 0);
return NULL;
}
2015-01-03 17:22:58 +08:00
if (EG(in_autoload) == NULL) {
ALLOC_HASHTABLE(EG(in_autoload));
zend_hash_init(EG(in_autoload), 8, NULL, NULL, 0);
}
if (zend_hash_add_empty_element(EG(in_autoload), lc_name) == NULL) {
if (!key) {
zend_string_release_ex(lc_name, 0);
}
return NULL;
}
if (ZSTR_VAL(name)[0] == '\\') {
autoload_name = zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
} else {
autoload_name = zend_string_copy(name);
}
zend_string *previous_filename = EG(filename_override);
zend_long previous_lineno = EG(lineno_override);
EG(filename_override) = NULL;
EG(lineno_override) = -1;
2014-12-14 06:06:14 +08:00
zend_exception_save();
ce = zend_autoload(autoload_name, lc_name);
2014-12-14 06:06:14 +08:00
zend_exception_restore();
EG(filename_override) = previous_filename;
EG(lineno_override) = previous_lineno;
zend_string_release_ex(autoload_name, 0);
zend_hash_del(EG(in_autoload), lc_name);
if (!key) {
zend_string_release_ex(lc_name, 0);
}
if (ce) {
ZEND_ASSERT(!CG(in_compilation));
if (ce_cache) {
SET_CE_CACHE(ce_cache, ce);
}
}
return ce;
}
/* }}} */
1999-04-08 02:10:10 +08:00
2014-12-14 06:06:14 +08:00
ZEND_API zend_class_entry *zend_lookup_class(zend_string *name) /* {{{ */
{
return zend_lookup_class_ex(name, NULL, 0);
}
/* }}} */
ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex) /* {{{ */
{
while (ex) {
if (Z_TYPE(ex->This) == IS_OBJECT) {
return Z_OBJCE(ex->This);
} else if (Z_CE(ex->This)) {
return Z_CE(ex->This);
} else if (ex->func) {
if (ex->func->type != ZEND_INTERNAL_FUNCTION || ex->func->common.scope) {
return NULL;
}
}
ex = ex->prev_execute_data;
}
return NULL;
}
/* }}} */
ZEND_API zend_object *zend_get_this_object(zend_execute_data *ex) /* {{{ */
{
while (ex) {
if (Z_TYPE(ex->This) == IS_OBJECT) {
return Z_OBJ(ex->This);
} else if (ex->func) {
if (ex->func->type != ZEND_INTERNAL_FUNCTION || ex->func->common.scope) {
return NULL;
}
}
ex = ex->prev_execute_data;
}
return NULL;
}
/* }}} */
ZEND_API zend_result zend_eval_stringl(const char *str, size_t str_len, zval *retval_ptr, const char *string_name) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_op_array *new_op_array;
2014-08-26 01:28:33 +08:00
uint32_t original_compiler_options;
zend_result retval;
zend_string *code_str;
1999-04-08 02:10:10 +08:00
if (retval_ptr) {
code_str = zend_string_concat3(
"return ", sizeof("return ")-1, str, str_len, ";", sizeof(";")-1);
1999-04-08 02:10:10 +08:00
} else {
code_str = zend_string_init(str, str_len, 0);
1999-04-08 02:10:10 +08:00
}
/*printf("Evaluating '%s'\n", pv.value.str.val);*/
original_compiler_options = CG(compiler_options);
CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL;
new_op_array = zend_compile_string(code_str, string_name, ZEND_COMPILE_POSITION_AFTER_OPEN_TAG);
CG(compiler_options) = original_compiler_options;
1999-04-08 02:10:10 +08:00
if (new_op_array) {
zval local_retval;
2015-01-03 17:22:58 +08:00
EG(no_extensions)=1;
2016-11-19 04:41:10 +08:00
new_op_array->scope = zend_get_executed_scope();
zend_try {
ZVAL_UNDEF(&local_retval);
2014-12-14 06:06:14 +08:00
zend_execute(new_op_array, &local_retval);
} zend_catch {
2014-12-14 06:06:14 +08:00
destroy_op_array(new_op_array);
efree_size(new_op_array, sizeof(zend_op_array));
zend_bailout();
} zend_end_try();
if (Z_TYPE(local_retval) != IS_UNDEF) {
if (retval_ptr) {
2014-04-15 19:40:40 +08:00
ZVAL_COPY_VALUE(retval_ptr, &local_retval);
} else {
zval_ptr_dtor(&local_retval);
}
} else {
if (retval_ptr) {
ZVAL_NULL(retval_ptr);
}
}
1999-04-08 02:10:10 +08:00
EG(no_extensions)=0;
zend_destroy_static_vars(new_op_array);
2014-12-14 06:06:14 +08:00
destroy_op_array(new_op_array);
efree_size(new_op_array, sizeof(zend_op_array));
retval = SUCCESS;
1999-04-08 02:10:10 +08:00
} else {
retval = FAILURE;
1999-04-08 02:10:10 +08:00
}
zend_string_release(code_str);
return retval;
1999-04-08 02:10:10 +08:00
}
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API zend_result zend_eval_string(const char *str, zval *retval_ptr, const char *string_name) /* {{{ */
{
2014-12-14 06:06:14 +08:00
return zend_eval_stringl(str, strlen(str), retval_ptr, string_name);
}
/* }}} */
ZEND_API zend_result zend_eval_stringl_ex(const char *str, size_t str_len, zval *retval_ptr, const char *string_name, bool handle_exceptions) /* {{{ */
{
zend_result result;
2014-12-14 06:06:14 +08:00
result = zend_eval_stringl(str, str_len, retval_ptr, string_name);
if (handle_exceptions && EG(exception)) {
result = zend_exception_error(EG(exception), E_ERROR);
}
return result;
}
/* }}} */
ZEND_API zend_result zend_eval_string_ex(const char *str, zval *retval_ptr, const char *string_name, bool handle_exceptions) /* {{{ */
{
2014-12-14 06:06:14 +08:00
return zend_eval_stringl_ex(str, strlen(str), retval_ptr, string_name, handle_exceptions);
}
/* }}} */
static void zend_set_timeout_ex(zend_long seconds, bool reset_signals);
2016-04-20 18:52:21 +08:00
ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */
{
#if defined(PHP_WIN32)
2016-06-06 06:22:04 +08:00
# ifndef ZTS
/* No action is needed if we're timed out because zero seconds are
just ignored. Also, the hard timeout needs to be respected. If the
timer is not restarted properly, it could hang in the shutdown
function. */
if (EG(hard_timeout) > 0) {
zend_atomic_bool_store_ex(&EG(timed_out), false);
zend_set_timeout_ex(EG(hard_timeout), 1);
/* XXX Abused, introduce an additional flag if the value needs to be kept. */
EG(hard_timeout) = 0;
}
2016-06-06 06:22:04 +08:00
# endif
#else
zend_atomic_bool_store_ex(&EG(timed_out), false);
2016-04-20 18:52:21 +08:00
zend_set_timeout_ex(0, 1);
#endif
zend_error_noreturn(E_ERROR, "Maximum execution time of " ZEND_LONG_FMT " second%s exceeded", EG(timeout_seconds), EG(timeout_seconds) == 1 ? "" : "s");
2016-04-20 18:52:21 +08:00
}
/* }}} */
#ifndef ZEND_WIN32
# ifdef ZEND_MAX_EXECUTION_TIMERS
static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */
{
#ifdef ZTS
if (!tsrm_is_managed_thread()) {
fprintf(stderr, "zend_timeout_handler() called in a thread not managed by PHP. The expected signal handler will not be called. This is probably a bug.\n");
return;
}
#endif
if (si->si_value.sival_ptr != &EG(max_execution_timer_timer)) {
#ifdef MAX_EXECUTION_TIMERS_DEBUG
fprintf(stderr, "Executing previous handler (if set) for unexpected signal SIGRTMIN received on thread %d\n", (pid_t) syscall(SYS_gettid));
#endif
if (EG(oldact).sa_sigaction) {
EG(oldact).sa_sigaction(dummy, si, uc);
return;
}
if (EG(oldact).sa_handler) EG(oldact).sa_handler(dummy);
return;
}
# else
2016-04-20 18:52:21 +08:00
static void zend_timeout_handler(int dummy) /* {{{ */
{
# endif
#ifdef ZTS
if (!tsrm_is_managed_thread()) {
fprintf(stderr, "zend_timeout_handler() called in a thread not managed by PHP. The expected signal handler will not be called. This is probably a bug.\n");
return;
}
#else
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
2016-04-20 18:52:21 +08:00
/* Die on hard timeout */
const char *error_filename = NULL;
uint32_t error_lineno = 0;
char log_buffer[2048];
int output_len = 0;
2016-04-20 18:52:21 +08:00
if (zend_is_compiling()) {
error_filename = ZSTR_VAL(zend_get_compiled_filename());
error_lineno = zend_get_compiled_lineno();
} else if (zend_is_executing()) {
error_filename = zend_get_executed_filename();
if (error_filename[0] == '[') { /* [no active file] */
error_filename = NULL;
error_lineno = 0;
} else {
error_lineno = zend_get_executed_lineno();
}
}
if (!error_filename) {
error_filename = "Unknown";
}
output_len = snprintf(log_buffer, sizeof(log_buffer), "\nFatal error: Maximum execution time of " ZEND_LONG_FMT "+" ZEND_LONG_FMT " seconds exceeded (terminated) in %s on line %d\n", EG(timeout_seconds), EG(hard_timeout), error_filename, error_lineno);
if (output_len > 0) {
zend_quiet_write(2, log_buffer, MIN(output_len, sizeof(log_buffer)));
}
_exit(124);
2021-06-29 16:04:10 +08:00
}
2016-04-20 18:52:21 +08:00
#endif
2002-09-19 23:58:01 +08:00
if (zend_on_timeout) {
2014-12-14 06:06:14 +08:00
zend_on_timeout(EG(timeout_seconds));
2002-09-19 23:58:01 +08:00
}
zend_atomic_bool_store_ex(&EG(timed_out), true);
zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
2016-04-20 18:52:21 +08:00
#ifndef ZTS
if (EG(hard_timeout) > 0) {
/* Set hard timeout */
zend_set_timeout_ex(EG(hard_timeout), 1);
}
#endif
}
/* }}} */
2016-04-20 18:52:21 +08:00
#endif
2000-06-16 10:49:21 +08:00
#ifdef ZEND_WIN32
VOID CALLBACK tq_timer_cb(PVOID arg, BOOLEAN timed_out)
{
zend_executor_globals *eg;
2014-11-17 15:47:48 +08:00
/* The doc states it'll be always true, however it theoretically
could be FALSE when the thread was signaled. */
if (!timed_out) {
return;
}
2016-06-23 20:22:08 +08:00
eg = (zend_executor_globals *)arg;
zend_atomic_bool_store_ex(&eg->timed_out, true);
zend_atomic_bool_store_ex(&eg->vm_interrupt, true);
}
#endif
/* This one doesn't exists on QNX */
#ifndef SIGPROF
#define SIGPROF 27
#endif
static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */
{
2016-06-24 21:15:00 +08:00
#ifdef ZEND_WIN32
zend_executor_globals *eg;
if (!seconds) {
return;
}
/* Don't use ChangeTimerQueueTimer() as it will not restart an expired
* timer, so we could end up with just an ignored timeout. Instead
* delete and recreate. */
if (NULL != tq_timer) {
if (!DeleteTimerQueueTimer(NULL, tq_timer, INVALID_HANDLE_VALUE)) {
tq_timer = NULL;
zend_error_noreturn(E_ERROR, "Could not delete queued timer");
return;
}
tq_timer = NULL;
}
/* XXX passing NULL means the default timer queue provided by the system is used */
eg = ZEND_MODULE_GLOBALS_BULK(executor);
if (!CreateTimerQueueTimer(&tq_timer, NULL, (WAITORTIMERCALLBACK)tq_timer_cb, (VOID*)eg, seconds*1000, 0, WT_EXECUTEONLYONCE)) {
tq_timer = NULL;
zend_error_noreturn(E_ERROR, "Could not queue new timer");
return;
}
#elif defined(ZEND_MAX_EXECUTION_TIMERS)
zend_max_execution_timer_settime(seconds);
if (reset_signals) {
sigset_t sigset;
struct sigaction act;
act.sa_sigaction = zend_timeout_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_ONSTACK | SA_SIGINFO;
sigaction(SIGRTMIN, &act, NULL);
sigemptyset(&sigset);
sigaddset(&sigset, SIGRTMIN);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
}
#elif defined(HAVE_SETITIMER)
2000-06-16 10:49:21 +08:00
{
struct itimerval t_r; /* timeout requested */
int signo;
// Prevent EINVAL error
if (seconds < 0 || seconds > 999999999) {
seconds = 0;
}
if(seconds) {
t_r.it_value.tv_sec = seconds;
t_r.it_value.tv_usec = t_r.it_interval.tv_sec = t_r.it_interval.tv_usec = 0;
# if defined(__CYGWIN__) || defined(__PASE__) || (defined(__aarch64__) && defined(__APPLE__))
// ITIMER_PROF is broken in Apple Silicon system with MacOS >= 14
// See https://openradar.appspot.com/radar?id=5583058442911744.
setitimer(ITIMER_REAL, &t_r, NULL);
}
signo = SIGALRM;
# else
setitimer(ITIMER_PROF, &t_r, NULL);
}
signo = SIGPROF;
# endif
if (reset_signals) {
# ifdef ZEND_SIGNALS
2016-04-20 18:52:21 +08:00
zend_signal(signo, zend_timeout_handler);
# else
sigset_t sigset;
# ifdef HAVE_SIGACTION
2016-04-20 18:52:21 +08:00
struct sigaction act;
act.sa_handler = zend_timeout_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_ONSTACK | SA_RESETHAND | SA_NODEFER;
2016-04-20 18:52:21 +08:00
sigaction(signo, &act, NULL);
# else
2016-04-20 18:52:21 +08:00
signal(signo, zend_timeout_handler);
# endif /* HAVE_SIGACTION */
sigemptyset(&sigset);
sigaddset(&sigset, signo);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
# endif /* ZEND_SIGNALS */
}
2000-06-16 10:49:21 +08:00
}
#endif /* HAVE_SETITIMER */
}
/* }}} */
void zend_set_timeout(zend_long seconds, bool reset_signals) /* {{{ */
2016-04-20 18:52:21 +08:00
{
EG(timeout_seconds) = seconds;
zend_set_timeout_ex(seconds, reset_signals);
zend_atomic_bool_store_ex(&EG(timed_out), false);
2016-04-20 18:52:21 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
void zend_unset_timeout(void) /* {{{ */
{
#ifdef ZEND_WIN32
if (NULL != tq_timer) {
if (!DeleteTimerQueueTimer(NULL, tq_timer, INVALID_HANDLE_VALUE)) {
zend_atomic_bool_store_ex(&EG(timed_out), false);
tq_timer = NULL;
zend_error_noreturn(E_ERROR, "Could not delete queued timer");
return;
}
tq_timer = NULL;
}
#elif defined(ZEND_MAX_EXECUTION_TIMERS)
zend_max_execution_timer_settime(0);
#elif defined(HAVE_SETITIMER)
if (EG(timeout_seconds)) {
2000-06-16 10:49:21 +08:00
struct itimerval no_timeout;
2000-06-16 10:49:21 +08:00
no_timeout.it_value.tv_sec = no_timeout.it_value.tv_usec = no_timeout.it_interval.tv_sec = no_timeout.it_interval.tv_usec = 0;
# if defined(__CYGWIN__) || defined(__PASE__) || (defined(__aarch64__) && defined(__APPLE__))
setitimer(ITIMER_REAL, &no_timeout, NULL);
# else
2000-06-16 10:49:21 +08:00
setitimer(ITIMER_PROF, &no_timeout, NULL);
# endif
2000-06-16 10:49:21 +08:00
}
#endif
zend_atomic_bool_store_ex(&EG(timed_out), false);
}
/* }}} */
static ZEND_COLD void report_class_fetch_error(zend_string *class_name, uint32_t fetch_type)
{
if (fetch_type & ZEND_FETCH_CLASS_SILENT) {
return;
}
if (EG(exception)) {
if (!(fetch_type & ZEND_FETCH_CLASS_EXCEPTION)) {
zend_exception_uncaught_error("During class fetch");
}
return;
}
if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) {
zend_throw_or_error(fetch_type, NULL, "Interface \"%s\" not found", ZSTR_VAL(class_name));
} else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) {
zend_throw_or_error(fetch_type, NULL, "Trait \"%s\" not found", ZSTR_VAL(class_name));
} else {
zend_throw_or_error(fetch_type, NULL, "Class \"%s\" not found", ZSTR_VAL(class_name));
}
}
zend_class_entry *zend_fetch_class(zend_string *class_name, uint32_t fetch_type) /* {{{ */
2003-08-03 16:21:08 +08:00
{
zend_class_entry *ce, *scope;
uint32_t fetch_sub_type = fetch_type & ZEND_FETCH_CLASS_MASK;
2003-08-03 16:21:08 +08:00
check_fetch_type:
switch (fetch_sub_type) {
2003-08-03 16:21:08 +08:00
case ZEND_FETCH_CLASS_SELF:
scope = zend_get_executed_scope();
if (UNEXPECTED(!scope)) {
zend_throw_or_error(fetch_type, NULL, "Cannot access \"self\" when no class scope is active");
2003-08-03 16:21:08 +08:00
}
return scope;
2003-08-03 16:21:08 +08:00
case ZEND_FETCH_CLASS_PARENT:
scope = zend_get_executed_scope();
if (UNEXPECTED(!scope)) {
zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when no class scope is active");
return NULL;
2003-08-03 16:21:08 +08:00
}
if (UNEXPECTED(!scope->parent)) {
zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when current class scope has no parent");
2003-08-03 16:21:08 +08:00
}
return scope->parent;
case ZEND_FETCH_CLASS_STATIC:
ce = zend_get_called_scope(EG(current_execute_data));
if (UNEXPECTED(!ce)) {
zend_throw_or_error(fetch_type, NULL, "Cannot access \"static\" when no class scope is active");
return NULL;
}
return ce;
2003-08-03 16:21:08 +08:00
case ZEND_FETCH_CLASS_AUTO: {
fetch_sub_type = zend_get_class_fetch_type(class_name);
if (UNEXPECTED(fetch_sub_type != ZEND_FETCH_CLASS_DEFAULT)) {
2003-08-03 16:21:08 +08:00
goto check_fetch_type;
}
}
break;
}
ce = zend_lookup_class_ex(class_name, NULL, fetch_type);
if (!ce) {
report_class_fetch_error(class_name, fetch_type);
return NULL;
2003-08-03 16:21:08 +08:00
}
return ce;
2003-08-03 16:21:08 +08:00
}
/* }}} */
zend_class_entry *zend_fetch_class_with_scope(
zend_string *class_name, uint32_t fetch_type, zend_class_entry *scope)
{
zend_class_entry *ce;
switch (fetch_type & ZEND_FETCH_CLASS_MASK) {
case ZEND_FETCH_CLASS_SELF:
if (UNEXPECTED(!scope)) {
zend_throw_or_error(fetch_type, NULL, "Cannot access \"self\" when no class scope is active");
}
return scope;
case ZEND_FETCH_CLASS_PARENT:
if (UNEXPECTED(!scope)) {
zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when no class scope is active");
return NULL;
}
if (UNEXPECTED(!scope->parent)) {
zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when current class scope has no parent");
}
return scope->parent;
case 0:
break;
/* Other fetch types are not supported by this function. */
EMPTY_SWITCH_DEFAULT_CASE()
}
ce = zend_lookup_class_ex(class_name, NULL, fetch_type);
if (!ce) {
report_class_fetch_error(class_name, fetch_type);
return NULL;
}
return ce;
}
zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string *key, uint32_t fetch_type) /* {{{ */
{
zend_class_entry *ce = zend_lookup_class_ex(class_name, key, fetch_type);
if (!ce) {
report_class_fetch_error(class_name, fetch_type);
return NULL;
}
return ce;
}
/* }}} */
ZEND_API zend_result zend_delete_global_variable(zend_string *name) /* {{{ */
{
2021-06-29 16:04:10 +08:00
return zend_hash_del_ind(&EG(symbol_table), name);
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API zend_array *zend_rebuild_symbol_table(void) /* {{{ */
{
zend_execute_data *ex;
zend_array *symbol_table;
/* Search for last called user function */
ex = EG(current_execute_data);
while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->common.type))) {
ex = ex->prev_execute_data;
}
if (!ex) {
return NULL;
}
if (ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_SYMBOL_TABLE) {
return ex->symbol_table;
}
ZEND_ADD_CALL_FLAG(ex, ZEND_CALL_HAS_SYMBOL_TABLE);
if (EG(symtable_cache_ptr) > EG(symtable_cache)) {
symbol_table = ex->symbol_table = *(--EG(symtable_cache_ptr));
2015-03-07 00:23:54 +08:00
if (!ex->func->op_array.last_var) {
return symbol_table;
}
zend_hash_extend(symbol_table, ex->func->op_array.last_var, 0);
} else {
symbol_table = ex->symbol_table = zend_new_array(ex->func->op_array.last_var);
2015-03-07 00:23:54 +08:00
if (!ex->func->op_array.last_var) {
return symbol_table;
}
2018-03-23 05:13:45 +08:00
zend_hash_real_init_mixed(symbol_table);
/*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/
}
2015-04-27 23:30:33 +08:00
if (EXPECTED(ex->func->op_array.last_var)) {
zend_string **str = ex->func->op_array.vars;
zend_string **end = str + ex->func->op_array.last_var;
zval *var = ZEND_CALL_VAR_NUM(ex, 0);
do {
_zend_hash_append_ind(symbol_table, *str, var);
str++;
var++;
} while (str != end);
}
return symbol_table;
}
/* }}} */
2014-04-18 17:46:36 +08:00
ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ */
{
zend_op_array *op_array = &execute_data->func->op_array;
HashTable *ht = execute_data->symbol_table;
2015-01-03 17:22:58 +08:00
/* copy real values from symbol table into CV slots and create
INDIRECT references to CV in symbol table */
2015-04-27 23:30:33 +08:00
if (EXPECTED(op_array->last_var)) {
zend_string **str = op_array->vars;
zend_string **end = str + op_array->last_var;
zval *var = EX_VAR_NUM(0);
2015-04-27 23:30:33 +08:00
do {
zval *zv = zend_hash_find_known_hash(ht, *str);
2014-12-15 19:43:16 +08:00
2015-04-27 23:30:33 +08:00
if (zv) {
if (Z_TYPE_P(zv) == IS_INDIRECT) {
zval *val = Z_INDIRECT_P(zv);
ZVAL_COPY_VALUE(var, val);
} else {
ZVAL_COPY_VALUE(var, zv);
}
} else {
2015-04-27 23:30:33 +08:00
ZVAL_UNDEF(var);
zv = zend_hash_add_new(ht, *str, var);
}
2015-04-27 23:30:33 +08:00
ZVAL_INDIRECT(zv, var);
str++;
var++;
} while (str != end);
}
}
/* }}} */
2014-04-18 17:46:36 +08:00
ZEND_API void zend_detach_symbol_table(zend_execute_data *execute_data) /* {{{ */
{
zend_op_array *op_array = &execute_data->func->op_array;
HashTable *ht = execute_data->symbol_table;
2015-01-03 17:22:58 +08:00
/* copy real values from CV slots into symbol table */
2015-04-27 23:30:33 +08:00
if (EXPECTED(op_array->last_var)) {
zend_string **str = op_array->vars;
zend_string **end = str + op_array->last_var;
zval *var = EX_VAR_NUM(0);
do {
if (Z_TYPE_P(var) == IS_UNDEF) {
zend_hash_del(ht, *str);
} else {
zend_hash_update(ht, *str, var);
ZVAL_UNDEF(var);
}
str++;
var++;
} while (str != end);
}
}
/* }}} */
ZEND_API zend_result zend_set_local_var(zend_string *name, zval *value, bool force) /* {{{ */
2014-04-02 02:36:17 +08:00
{
zend_execute_data *execute_data = EG(current_execute_data);
while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) {
execute_data = execute_data->prev_execute_data;
}
if (execute_data) {
if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
2014-08-26 01:24:55 +08:00
zend_ulong h = zend_string_hash_val(name);
zend_op_array *op_array = &execute_data->func->op_array;
2015-04-27 23:30:33 +08:00
if (EXPECTED(op_array->last_var)) {
zend_string **str = op_array->vars;
zend_string **end = str + op_array->last_var;
do {
if (ZSTR_H(*str) == h &&
zend_string_equal_content(*str, name)) {
2015-04-27 23:30:33 +08:00
zval *var = EX_VAR_NUM(str - op_array->vars);
ZVAL_COPY_VALUE(var, value);
return SUCCESS;
}
str++;
} while (str != end);
2014-04-02 02:36:17 +08:00
}
if (force) {
2014-12-14 06:06:14 +08:00
zend_array *symbol_table = zend_rebuild_symbol_table();
if (symbol_table) {
zend_hash_update(symbol_table, name, value);
return SUCCESS;
}
2014-04-02 02:36:17 +08:00
}
} else {
zend_hash_update_ind(execute_data->symbol_table, name, value);
return SUCCESS;
2014-04-02 02:36:17 +08:00
}
}
return FAILURE;
2014-04-02 02:36:17 +08:00
}
/* }}} */
ZEND_API zend_result zend_set_local_var_str(const char *name, size_t len, zval *value, bool force) /* {{{ */
{
zend_execute_data *execute_data = EG(current_execute_data);
while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) {
execute_data = execute_data->prev_execute_data;
}
if (execute_data) {
if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
zend_ulong h = zend_hash_func(name, len);
zend_op_array *op_array = &execute_data->func->op_array;
2015-04-27 23:30:33 +08:00
if (EXPECTED(op_array->last_var)) {
zend_string **str = op_array->vars;
zend_string **end = str + op_array->last_var;
do {
if (ZSTR_H(*str) == h &&
zend_string_equals_cstr(*str, name, len)) {
2015-04-27 23:30:33 +08:00
zval *var = EX_VAR_NUM(str - op_array->vars);
zval_ptr_dtor(var);
2015-04-27 23:30:33 +08:00
ZVAL_COPY_VALUE(var, value);
return SUCCESS;
}
str++;
} while (str != end);
}
if (force) {
2014-12-14 06:06:14 +08:00
zend_array *symbol_table = zend_rebuild_symbol_table();
if (symbol_table) {
zend_hash_str_update(symbol_table, name, len, value);
return SUCCESS;
}
}
} else {
zend_hash_str_update_ind(execute_data->symbol_table, name, len, value);
return SUCCESS;
}
}
return FAILURE;
}
/* }}} */