php-src/Zend/zend_execute_API.c

1692 lines
46 KiB
C
Raw Normal View History

1999-04-08 02:10:10 +08:00
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
2017-01-02 23:30:12 +08:00
| Copyright (c) 1998-2017 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@zend.com> |
| Zeev Suraski <zeev@zend.com> |
| Dmitry Stogov <dmitry@zend.com> |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
*/
/* $Id$ */
1999-07-16 22:58:16 +08:00
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"
#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"
2009-03-18 18:41:39 +08:00
#include "zend_float.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
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);
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, {{0}, {{0}}, {0}}, NULL, NULL, NULL, 0, 0 };
ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = { 0, NULL, NULL, NULL, NULL };
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(int dummy) /* {{{ */
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 (c->flags & 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) - 1;
EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE - 1;
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(autoload_func) = NULL;
EG(error_handling) = EH_NORMAL;
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;
EG(vm_interrupt) = 0;
EG(timed_out) = 0;
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;
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)));
2017-02-03 06:07:25 +08:00
EG(each_deprecation_thrown) = 0;
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);
}
2014-12-14 06:06:14 +08:00
i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC);
}
/* }}} */
static 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(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();
}
/* }}} */
2014-12-14 06:06:14 +08:00
void shutdown_executor(void) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_string *key;
zval *zv;
#if ZEND_DEBUG
zend_bool fast_shutdown = 0;
#else
zend_bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup);
#endif
zend_try {
zend_llist_destroy(&CG(open_files));
} zend_end_try();
zend_try {
zend_close_rsrc_list(&EG(regular_list));
} zend_end_try();
zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
/* All resources and objects are destroyed. */
/* No PHP callback functions may be called after this point. */
2017-06-23 19:58:19 +08:00
EG(active) = 0;
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.
*/
ZEND_HASH_REVERSE_FOREACH_VAL(EG(zend_constants), zv) {
zend_constant *c = Z_PTR_P(zv);
if (c->flags & CONST_PERSISTENT) {
break;
}
} ZEND_HASH_FOREACH_END_DEL();
ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
zend_function *func = Z_PTR_P(zv);
if (func->type == ZEND_INTERNAL_FUNCTION) {
break;
}
} ZEND_HASH_FOREACH_END_DEL();
ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
zend_class_entry *ce = Z_PTR_P(zv);
if (ce->type == ZEND_INTERNAL_CLASS) {
break;
}
} ZEND_HASH_FOREACH_END_DEL();
} else {
zend_hash_graceful_reverse_destroy(&EG(symbol_table));
#if ZEND_DEBUG
if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
gc_collect_cycles();
}
#endif
/* remove error handlers before destroying classes and functions,
* so that if handler used some class, crash would not happen */
if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
zval_ptr_dtor(&EG(user_error_handler));
2014-02-24 17:26:09 +08:00
ZVAL_UNDEF(&EG(user_error_handler));
}
if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
zval_ptr_dtor(&EG(user_exception_handler));
2014-02-24 17:26:09 +08:00
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);
zend_vm_stack_destroy();
if (EG(full_tables_cleanup)) {
zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full);
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_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) {
zend_constant *c = Z_PTR_P(zv);
if (c->flags & CONST_PERSISTENT) {
break;
}
zval_ptr_dtor_nogc(&c->value);
if (c->name) {
zend_string_release(c->name);
}
efree(c);
zend_string_release(key);
} ZEND_HASH_FOREACH_END_DEL();
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(function_table), key, zv) {
zend_function *func = Z_PTR_P(zv);
if (func->type == ZEND_INTERNAL_FUNCTION) {
break;
}
destroy_op_array(&func->op_array);
zend_string_release(key);
} ZEND_HASH_FOREACH_END_DEL();
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
zend_class_entry *ce = Z_PTR_P(zv);
if (ce->type == ZEND_INTERNAL_CLASS) {
break;
}
destroy_zend_class(zv);
zend_string_release(key);
} ZEND_HASH_FOREACH_END_DEL();
2001-10-23 09:23:36 +08:00
}
while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
zend_hash_destroy(*EG(symtable_cache_ptr));
2014-04-25 15:54:10 +08:00
FREE_HASHTABLE(*EG(symtable_cache_ptr));
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
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_cleanup_internal_classes();
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 = EG(current_execute_data)->func;
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 = EG(current_execute_data)->func;
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
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_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 ZSTR_VAL(ex->func->op_array.filename);
} else {
return "[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_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_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 (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;
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API zend_bool zend_is_executing(void) /* {{{ */
{
return EG(current_execute_data) != 0;
}
/* }}} */
ZEND_API void _zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-12-14 06:06:14 +08:00
i_zval_ptr_dtor(zval_ptr ZEND_FILE_LINE_RELAY_CC);
1999-04-08 02:10:10 +08:00
}
/* }}} */
ZEND_API void _zval_internal_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) /* {{{ */
{
if (Z_REFCOUNTED_P(zval_ptr)) {
Z_DELREF_P(zval_ptr);
if (Z_REFCOUNT_P(zval_ptr) == 0) {
_zval_internal_dtor_for_ptr(zval_ptr ZEND_FILE_LINE_CC);
}
}
}
/* }}} */
ZEND_API int zend_use_undefined_constant(zend_string *name, zend_ast_attr attr, zval *result) /* {{{ */
1999-04-08 02:10:10 +08:00
{
char *colon;
if (UNEXPECTED(EG(exception))) {
return FAILURE;
} else if ((colon = (char*)zend_memrchr(ZSTR_VAL(name), ':', ZSTR_LEN(name)))) {
zend_throw_error(NULL, "Undefined class constant '%s'", ZSTR_VAL(name));
return FAILURE;
} else if ((attr & IS_CONSTANT_UNQUALIFIED) == 0) {
zend_throw_error(NULL, "Undefined constant '%s'", ZSTR_VAL(name));
return FAILURE;
} else {
char *actual = ZSTR_VAL(name);
size_t actual_len = ZSTR_LEN(name);
char *slash = (char *) zend_memrchr(actual, '\\', actual_len);
if (slash) {
actual = slash + 1;
actual_len -= (actual - ZSTR_VAL(name));
}
zend_error(E_WARNING, "Use of undefined constant %s - assumed '%s' (this will throw an Error in a future version of PHP)", actual, actual);
if (EG(exception)) {
return FAILURE;
} else {
zval_ptr_dtor_nogc(result);
ZVAL_STRINGL(result, actual, actual_len);
}
}
return SUCCESS;
}
/* }}} */
ZEND_API int zval_update_constant_ex(zval *p, zend_class_entry *scope) /* {{{ */
{
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 zend_use_undefined_constant(name, ast->attr, p);
2013-11-07 02:21:07 +08:00
}
zval_ptr_dtor_nogc(p);
ZVAL_DUP(p, zv);
2013-11-07 02:21:07 +08:00
} else {
zval tmp;
if (UNEXPECTED(zend_ast_evaluate(&tmp, ast, scope) != 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 int 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
int _call_user_function_ex(zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[], int no_separation) /* {{{ */
2003-05-21 00:44:42 +08:00
{
zend_fcall_info fci;
fci.size = sizeof(fci);
fci.object = object ? Z_OBJ_P(object) : NULL;
ZVAL_COPY_VALUE(&fci.function_name, function_name);
fci.retval = retval_ptr;
fci.param_count = param_count;
fci.params = params;
fci.no_separation = (zend_bool) no_separation;
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
2014-12-14 06:06:14 +08:00
int 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, dummy_execute_data;
zend_fcall_info_cache fci_cache_local;
zend_function *func;
ZVAL_UNDEF(fci->retval);
if (!EG(active)) {
return FAILURE; /* executor is already inactive */
}
if (EG(exception)) {
return FAILURE; /* we would result in an instable executor otherwise */
}
switch (fci->size) {
case sizeof(zend_fcall_info):
break; /* nothing to do currently */
default:
zend_error_noreturn(E_CORE_ERROR, "Corrupted fcall_info provided to zend_call_function()");
break;
}
/* Initialize execute_data */
if (!EG(current_execute_data)) {
2004-02-11 21:01:39 +08:00
/* This only happens when we're called outside any execute()'s
* It shouldn't be strictly necessary to NULL execute_data out,
* but it may make bugs easier to spot
*/
memset(&dummy_execute_data, 0, sizeof(zend_execute_data));
EG(current_execute_data) = &dummy_execute_data;
2014-07-07 19:50:44 +08:00
} else if (EG(current_execute_data)->func &&
ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL &&
EG(current_execute_data)->opline->opcode != ZEND_DO_ICALL &&
EG(current_execute_data)->opline->opcode != ZEND_DO_UCALL &&
EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL_BY_NAME) {
/* Insert fake frame in case of include or magic calls */
dummy_execute_data = *EG(current_execute_data);
dummy_execute_data.prev_execute_data = EG(current_execute_data);
dummy_execute_data.call = NULL;
dummy_execute_data.opline = NULL;
dummy_execute_data.func = NULL;
EG(current_execute_data) = &dummy_execute_data;
}
2000-01-16 06:52:24 +08:00
if (!fci_cache || !fci_cache->initialized) {
char *error = NULL;
if (!fci_cache) {
fci_cache = &fci_cache_local;
}
if (!zend_is_callable_ex(&fci->function_name, fci->object, IS_CALLABLE_CHECK_SILENT, NULL, fci_cache, &error)) {
if (error) {
zend_string *callable_name
= zend_get_callable_name_ex(&fci->function_name, fci->object);
zend_error(E_WARNING, "Invalid callback %s, %s", ZSTR_VAL(callable_name), error);
efree(error);
2014-08-26 01:24:55 +08:00
zend_string_release(callable_name);
2008-07-27 03:14:38 +08:00
}
if (EG(current_execute_data) == &dummy_execute_data) {
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
}
1999-04-08 02:10:10 +08:00
return FAILURE;
} else if (error) {
/* Capitalize the first latter of the error message */
if (error[0] >= 'a' && error[0] <= 'z') {
error[0] += ('A' - 'a');
}
zend_error(E_DEPRECATED, "%s", error);
efree(error);
if (UNEXPECTED(EG(exception))) {
if (EG(current_execute_data) == &dummy_execute_data) {
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
}
return FAILURE;
}
2003-05-21 00:44:42 +08:00
}
}
func = fci_cache->function_handler;
fci->object = (func->common.fn_flags & ZEND_ACC_STATIC) ?
NULL : fci_cache->object;
call = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC,
func, fci->param_count, fci_cache->called_scope, fci->object);
if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_DEPRECATED)) {
zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
func->common.scope ? "::" : "",
ZSTR_VAL(func->common.function_name));
if (UNEXPECTED(EG(exception))) {
zend_vm_stack_free_call_frame(call);
2016-04-11 20:24:37 +08:00
if (EG(current_execute_data) == &dummy_execute_data) {
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
}
return FAILURE;
2006-02-26 02:25:45 +08:00
}
}
for (i=0; i<fci->param_count; i++) {
zval *param;
zval *arg = &fci->params[i];
1999-04-08 02:10:10 +08:00
if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
if (UNEXPECTED(!Z_ISREF_P(arg))) {
if (!fci->no_separation) {
/* Separation is enabled -- create a ref */
ZVAL_NEW_REF(arg, arg);
} else if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
/* By-value send is not allowed -- emit a warning,
* but still perform the call with a by-value send. */
zend_error(E_WARNING,
"Parameter %d to %s%s%s() expected to be a reference, value given", i+1,
func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
func->common.scope ? "::" : "",
ZSTR_VAL(func->common.function_name));
if (UNEXPECTED(EG(exception))) {
ZEND_CALL_NUM_ARGS(call) = i;
zend_vm_stack_free_args(call);
zend_vm_stack_free_call_frame(call);
if (EG(current_execute_data) == &dummy_execute_data) {
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
}
return FAILURE;
}
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
}
param = ZEND_CALL_ARG(call, i+1);
ZVAL_COPY(param, arg);
1999-04-08 02:10:10 +08:00
}
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
uint32_t call_info;
ZEND_ASSERT(GC_TYPE((zend_object*)func->op_array.prototype) == IS_OBJECT);
GC_ADDREF((zend_object*)func->op_array.prototype);
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->type == ZEND_USER_FUNCTION) {
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
int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
const zend_op *current_opline_before_exception = EG(opline_before_exception);
zend_init_func_execute_data(call, &func->op_array, fci->retval);
zend_execute_ex(call);
EG(opline_before_exception) = current_opline_before_exception;
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
if (call_via_handler) {
/* We must re-initialize function again */
fci_cache->initialized = 0;
}
} else if (func->type == ZEND_INTERNAL_FUNCTION) {
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
int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
ZVAL_NULL(fci->retval);
call->prev_execute_data = EG(current_execute_data);
call->return_value = NULL; /* this is not a constructor call */
EG(current_execute_data) = 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
}
EG(current_execute_data) = call->prev_execute_data;
2014-12-14 06:06:14 +08:00
zend_vm_stack_free_args(call);
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
}
if (call_via_handler) {
/* We must re-initialize function again */
fci_cache->initialized = 0;
}
} else { /* ZEND_OVERLOADED_FUNCTION */
2014-04-16 01:56:30 +08:00
ZVAL_NULL(fci->retval);
/* Not sure what should be done here if it's a static method */
if (fci->object) {
call->prev_execute_data = EG(current_execute_data);
EG(current_execute_data) = call;
2014-12-14 06:06:14 +08:00
fci->object->handlers->call_method(func->common.function_name, fci->object, call, fci->retval);
EG(current_execute_data) = call->prev_execute_data;
} else {
zend_throw_error(NULL, "Cannot call overloaded function for non-object");
}
2014-12-14 06:06:14 +08:00
zend_vm_stack_free_args(call);
if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
2014-08-26 01:24:55 +08:00
zend_string_release(func->common.function_name);
}
efree(func);
2014-05-24 21:37:15 +08:00
if (EG(exception)) {
zval_ptr_dtor(fci->retval);
ZVAL_UNDEF(fci->retval);
}
1999-04-08 02:10:10 +08:00
}
zend_vm_stack_free_call_frame(call);
if (EG(current_execute_data) == &dummy_execute_data) {
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
}
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
2014-12-14 06:06:14 +08:00
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *key, int use_autoload) /* {{{ */
{
zend_class_entry *ce = NULL;
zval args[1];
zval local_retval;
zend_string *lc_name;
zend_fcall_info fcall_info;
zend_fcall_info_cache fcall_cache;
2004-11-17 20:06:27 +08:00
if (key) {
lc_name = Z_STR_P(key);
} else {
if (name == NULL || !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
ce = zend_hash_find_ptr(EG(class_table), lc_name);
if (ce) {
if (!key) {
zend_string_release(lc_name);
}
return ce;
}
/* The compiler is not-reentrant. Make sure we __autoload() only during run-time
2013-07-24 07:55:43 +08:00
* (doesn't impact functionality of __autoload()
*/
2014-12-14 06:06:14 +08:00
if (!use_autoload || zend_is_compiling()) {
if (!key) {
zend_string_release(lc_name);
}
return NULL;
}
2014-04-22 05:41:40 +08:00
if (!EG(autoload_func)) {
zend_function *func = zend_hash_find_ptr(EG(function_table), ZSTR_KNOWN(ZEND_STR_MAGIC_AUTOLOAD));
2014-04-22 05:41:40 +08:00
if (func) {
EG(autoload_func) = func;
} else {
if (!key) {
zend_string_release(lc_name);
2014-04-22 05:41:40 +08:00
}
return NULL;
}
}
2015-01-03 17:22:58 +08:00
/* Verify class name before passing it to __autoload() */
if (!key && strspn(ZSTR_VAL(name), "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\") != ZSTR_LEN(name)) {
zend_string_release(lc_name);
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(lc_name);
}
return NULL;
}
ZVAL_UNDEF(&local_retval);
if (ZSTR_VAL(name)[0] == '\\') {
ZVAL_STRINGL(&args[0], ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
} else {
2014-09-19 21:32:50 +08:00
ZVAL_STR_COPY(&args[0], name);
}
fcall_info.size = sizeof(fcall_info);
2014-09-19 21:32:50 +08:00
ZVAL_STR_COPY(&fcall_info.function_name, EG(autoload_func)->common.function_name);
fcall_info.retval = &local_retval;
fcall_info.param_count = 1;
fcall_info.params = args;
fcall_info.object = NULL;
fcall_info.no_separation = 1;
2014-04-22 05:41:40 +08:00
fcall_cache.initialized = 1;
fcall_cache.function_handler = EG(autoload_func);
fcall_cache.calling_scope = NULL;
2008-07-25 16:23:07 +08:00
fcall_cache.called_scope = NULL;
fcall_cache.object = NULL;
2014-12-14 06:06:14 +08:00
zend_exception_save();
if ((zend_call_function(&fcall_info, &fcall_cache) == SUCCESS) && !EG(exception)) {
ce = zend_hash_find_ptr(EG(class_table), lc_name);
}
2014-12-14 06:06:14 +08:00
zend_exception_restore();
zval_ptr_dtor(&args[0]);
zval_dtor(&fcall_info.function_name);
zend_hash_del(EG(in_autoload), lc_name);
zval_ptr_dtor(&local_retval);
if (!key) {
zend_string_release(lc_name);
}
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) /* {{{ */
{
2014-12-14 06:06:14 +08:00
return zend_lookup_class_ex(name, NULL, 1);
}
/* }}} */
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;
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char *string_name) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zval pv;
zend_op_array *new_op_array;
2014-08-26 01:28:33 +08:00
uint32_t original_compiler_options;
int retval;
1999-04-08 02:10:10 +08:00
if (retval_ptr) {
2014-08-26 01:24:55 +08:00
ZVAL_NEW_STR(&pv, zend_string_alloc(str_len + sizeof("return ;")-1, 1));
memcpy(Z_STRVAL(pv), "return ", sizeof("return ") - 1);
memcpy(Z_STRVAL(pv) + sizeof("return ") - 1, str, str_len);
Z_STRVAL(pv)[Z_STRLEN(pv) - 1] = ';';
2006-12-28 08:17:48 +08:00
Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0';
1999-04-08 02:10:10 +08:00
} else {
ZVAL_STRINGL(&pv, str, str_len);
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;
2014-12-14 06:06:14 +08:00
new_op_array = zend_compile_string(&pv, string_name);
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;
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
}
zval_dtor(&pv);
return retval;
1999-04-08 02:10:10 +08:00
}
/* }}} */
1999-04-08 02:10:10 +08:00
2014-12-14 06:06:14 +08:00
ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name) /* {{{ */
{
2014-12-14 06:06:14 +08:00
return zend_eval_stringl(str, strlen(str), retval_ptr, string_name);
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API int zend_eval_stringl_ex(char *str, size_t str_len, zval *retval_ptr, char *string_name, int handle_exceptions) /* {{{ */
{
int 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)) {
2014-12-14 06:06:14 +08:00
zend_exception_error(EG(exception), E_ERROR);
result = FAILURE;
}
return result;
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions) /* {{{ */
{
2014-12-14 06:06:14 +08:00
return zend_eval_stringl_ex(str, strlen(str), retval_ptr, string_name, handle_exceptions);
}
/* }}} */
2016-04-20 18:52:21 +08:00
static void zend_set_timeout_ex(zend_long seconds, int reset_signals);
ZEND_API ZEND_NORETURN void zend_timeout(int dummy) /* {{{ */
{
#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) {
EG(timed_out) = 0;
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
2016-04-20 18:52:21 +08:00
EG(timed_out) = 0;
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
static void zend_timeout_handler(int dummy) /* {{{ */
{
#ifndef ZTS
if (EG(timed_out)) {
/* 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) {
2016-11-21 02:10:03 +08:00
write(2, log_buffer, MIN(output_len, sizeof(log_buffer)));
}
_exit(124);
2016-04-20 18:52:21 +08:00
}
#endif
2002-09-19 23:58:01 +08:00
if (zend_on_timeout) {
#ifdef ZEND_SIGNALS
2012-07-23 05:25:00 +08:00
/*
We got here because we got a timeout signal, so we are in a signal handler
at this point. However, we want to be able to timeout any user-supplied
shutdown functions, so pretend we are not in a signal handler while we are
2012-07-23 05:25:00 +08:00
calling these
*/
SIGG(running) = 0;
#endif
2014-12-14 06:06:14 +08:00
zend_on_timeout(EG(timeout_seconds));
2002-09-19 23:58:01 +08:00
}
2016-04-20 18:52:21 +08:00
EG(timed_out) = 1;
EG(vm_interrupt) = 1;
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;
eg->timed_out = 1;
eg->vm_interrupt = 1;
}
#endif
/* This one doesn't exists on QNX */
#ifndef SIGPROF
#define SIGPROF 27
#endif
2016-04-20 18:52:21 +08:00
static void zend_set_timeout_ex(zend_long seconds, int 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, NULL)) {
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;
}
#else
# ifdef HAVE_SETITIMER
2000-06-16 10:49:21 +08:00
{
struct itimerval t_r; /* timeout requested */
int signo;
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;
# ifdef __CYGWIN__
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;
2016-04-20 18:52:21 +08:00
# ifdef HAVE_SIGACTION
struct sigaction act;
act.sa_handler = zend_timeout_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESETHAND | SA_NODEFER;
sigaction(signo, &act, NULL);
# else
signal(signo, zend_timeout_handler);
# endif /* HAVE_SIGACTION */
sigemptyset(&sigset);
sigaddset(&sigset, signo);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
2016-04-20 18:52:21 +08:00
# endif /* ZEND_SIGNALS */
}
2000-06-16 10:49:21 +08:00
}
# endif /* HAVE_SETITIMER */
#endif
}
/* }}} */
2016-04-20 18:52:21 +08:00
void zend_set_timeout(zend_long seconds, int reset_signals) /* {{{ */
{
EG(timeout_seconds) = seconds;
zend_set_timeout_ex(seconds, reset_signals);
EG(timed_out) = 0;
}
/* }}} */
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, NULL)) {
EG(timed_out) = 0;
tq_timer = NULL;
zend_error_noreturn(E_ERROR, "Could not delete queued timer");
return;
}
tq_timer = NULL;
}
EG(timed_out) = 0;
#else
# ifdef 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;
#ifdef __CYGWIN__
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
2016-04-20 18:52:21 +08:00
EG(timed_out) = 0;
#endif
}
/* }}} */
2014-12-14 06:06:14 +08:00
zend_class_entry *zend_fetch_class(zend_string *class_name, int fetch_type) /* {{{ */
2003-08-03 16:21:08 +08:00
{
zend_class_entry *ce, *scope;
int 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;
}
if (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) {
return zend_lookup_class_ex(class_name, NULL, 0);
} else if ((ce = zend_lookup_class_ex(class_name, NULL, 1)) == NULL) {
if (!(fetch_type & ZEND_FETCH_CLASS_SILENT) && !EG(exception)) {
if (fetch_sub_type == ZEND_FETCH_CLASS_INTERFACE) {
zend_throw_or_error(fetch_type, NULL, "Interface '%s' not found", ZSTR_VAL(class_name));
} else if (fetch_sub_type == 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));
}
}
return NULL;
2003-08-03 16:21:08 +08:00
}
return ce;
2003-08-03 16:21:08 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, const zval *key, int fetch_type) /* {{{ */
{
zend_class_entry *ce;
if (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) {
return zend_lookup_class_ex(class_name, key, 0);
} else if ((ce = zend_lookup_class_ex(class_name, key, 1)) == NULL) {
if ((fetch_type & ZEND_FETCH_CLASS_SILENT) == 0 && !EG(exception)) {
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));
}
}
return NULL;
}
return ce;
}
/* }}} */
#define MAX_ABSTRACT_INFO_CNT 3
#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
#define DISPLAY_ABSTRACT_FN(idx) \
ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
ai.afn[idx] ? "::" : "", \
ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "")
typedef struct _zend_abstract_info {
zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1];
int cnt;
int ctor;
} zend_abstract_info;
2014-12-14 06:06:14 +08:00
static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai) /* {{{ */
{
if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
ai->afn[ai->cnt] = fn;
}
if (fn->common.fn_flags & ZEND_ACC_CTOR) {
if (!ai->ctor) {
ai->cnt++;
ai->ctor = 1;
} else {
ai->afn[ai->cnt] = NULL;
}
} else {
ai->cnt++;
}
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
{
2014-06-17 01:11:52 +08:00
zend_function *func;
zend_abstract_info ai;
if ((ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) && !(ce->ce_flags & (ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) {
memset(&ai, 0, sizeof(ai));
2014-06-17 01:11:52 +08:00
ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
2014-12-14 06:06:14 +08:00
zend_verify_abstract_class_function(func, &ai);
2014-06-17 01:11:52 +08:00
} ZEND_HASH_FOREACH_END();
2004-03-09 00:52:59 +08:00
if (ai.cnt) {
zend_error_noreturn(E_ERROR, "Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
ZSTR_VAL(ce->name), ai.cnt,
ai.cnt > 1 ? "s" : "",
2004-03-09 00:52:59 +08:00
DISPLAY_ABSTRACT_FN(0),
DISPLAY_ABSTRACT_FN(1),
DISPLAY_ABSTRACT_FN(2)
);
}
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API int zend_delete_global_variable(zend_string *name) /* {{{ */
{
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)) {
/*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/
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;
}
zend_hash_real_init(symbol_table, 0);
/*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(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);
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API int zend_set_local_var(zend_string *name, zval *value, int 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 &&
ZSTR_LEN(*str) == ZSTR_LEN(name) &&
memcmp(ZSTR_VAL(*str), ZSTR_VAL(name), ZSTR_LEN(name)) == 0) {
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) {
2017-06-26 05:24:23 +08:00
return zend_hash_update(symbol_table, name, value) ? SUCCESS : FAILURE;
}
2014-04-02 02:36:17 +08:00
}
} else {
return (zend_hash_update_ind(execute_data->symbol_table, name, value) != NULL) ? SUCCESS : FAILURE;
2014-04-02 02:36:17 +08:00
}
}
return FAILURE;
2014-04-02 02:36:17 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API int zend_set_local_var_str(const char *name, size_t len, zval *value, int 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 &&
ZSTR_LEN(*str) == len &&
memcmp(ZSTR_VAL(*str), name, len) == 0) {
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) {
2017-06-26 05:24:23 +08:00
return zend_hash_str_update(symbol_table, name, len, value) ? SUCCESS : FAILURE;
}
}
} else {
return (zend_hash_str_update_ind(execute_data->symbol_table, name, len, value) != NULL) ? SUCCESS : FAILURE;
}
}
return FAILURE;
}
/* }}} */
ZEND_API int zend_forbid_dynamic_call(const char *func_name) /* {{{ */
{
zend_execute_data *ex = EG(current_execute_data);
ZEND_ASSERT(ex != NULL && ex->func != NULL);
if (ZEND_CALL_INFO(ex) & ZEND_CALL_DYNAMIC) {
zend_error(E_WARNING, "Cannot call %s dynamically", func_name);
return FAILURE;
}
return SUCCESS;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* indent-tabs-mode: t
* End:
2017-07-05 00:12:45 +08:00
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/