diff options
156 files changed, 10632 insertions, 6320 deletions
diff --git a/.travis.yml b/.travis.yml index 10ea74e4df..d9e11a07d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,3 +47,4 @@ before_script: # Run PHPs run-tests.php script: - ./sapi/cli/php run-tests.php -p `pwd`/sapi/cli/php -g "FAIL,XFAIL,BORK,WARN,LEAK,SKIP" --show-diff --set-timeout 120 + - ./sapi/cli/php sapi/phpdbg/tests/run-tests.php -diff2stdout --phpdbg sapi/phpdbg/phpdbg diff --git a/Zend/tests/bug68262.phpt b/Zend/tests/bug68262.phpt new file mode 100644 index 0000000000..8d009f621e --- /dev/null +++ b/Zend/tests/bug68262.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #68262: Broken reference across cloned objects +--FILE-- +<?php + +class C { + public $p; +} + +$first = new C; +$first->p = 'init'; + +$clone = clone $first; +$ref =& $first->p; +unset($ref); + +$clone = clone $first; +$clone->p = 'foo'; + +var_dump($first->p); + +?> +--EXPECT-- +string(4) "init" diff --git a/Zend/zend.c b/Zend/zend.c index 7a4caf800d..21d354e5b3 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -224,13 +224,13 @@ ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy TSRMLS_DC) /* } /* }}} */ -ZEND_API int zend_print_zval(zval *expr, int indent TSRMLS_DC) /* {{{ */ +ZEND_API size_t zend_print_zval(zval *expr, int indent TSRMLS_DC) /* {{{ */ { return zend_print_zval_ex(zend_write, expr, indent TSRMLS_CC); } /* }}} */ -ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent TSRMLS_DC) /* {{{ */ +ZEND_API size_t zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent TSRMLS_DC) /* {{{ */ { zend_string *str = zval_get_string(expr); size_t len = str->len; @@ -797,7 +797,7 @@ void zend_shutdown(TSRMLS_D) /* {{{ */ void zend_set_utility_values(zend_utility_values *utility_values) /* {{{ */ { zend_uv = *utility_values; - zend_uv.import_use_extension_length = strlen(zend_uv.import_use_extension); + zend_uv.import_use_extension_length = (uint)strlen(zend_uv.import_use_extension); } /* }}} */ @@ -831,11 +831,11 @@ ZEND_API void zend_append_version_info(const zend_extension *extension) /* {{{ * char *new_info; uint new_info_length; - new_info_length = sizeof(" with v, , by \n") + new_info_length = (uint)(sizeof(" with v, , by \n") + strlen(extension->name) + strlen(extension->version) + strlen(extension->copyright) - + strlen(extension->author); + + strlen(extension->author)); new_info = (char *) malloc(new_info_length + 1); @@ -1101,7 +1101,7 @@ static void zend_error_va_list(int type, const char *format, va_list args) # endif #endif va_copy(usr_copy, args); - len = zend_vspprintf(&str, 0, format, usr_copy); + len = (int)zend_vspprintf(&str, 0, format, usr_copy); ZVAL_NEW_STR(¶ms[1], zend_string_init(str, len, 0)); efree(str); #ifdef va_copy diff --git a/Zend/zend.h b/Zend/zend.h index 8fbbcb190f..dfd15c6a76 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -213,7 +213,7 @@ typedef struct _zend_utility_values { zend_bool html_errors; } zend_utility_values; -typedef int (*zend_write_func_t)(const char *str, uint str_length); +typedef int (*zend_write_func_t)(const char *str, size_t str_length); #define zend_bailout() _zend_bailout(__FILE__, __LINE__) @@ -244,8 +244,8 @@ ZEND_API void _zend_bailout(char *filename, uint lineno); ZEND_API char *get_zend_version(void); ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy TSRMLS_DC); -ZEND_API int zend_print_zval(zval *expr, int indent TSRMLS_DC); -ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent TSRMLS_DC); +ZEND_API size_t zend_print_zval(zval *expr, int indent TSRMLS_DC); +ZEND_API size_t zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent TSRMLS_DC); ZEND_API void zend_print_zval_r(zval *expr, int indent TSRMLS_DC); ZEND_API void zend_print_flat_zval_r(zval *expr TSRMLS_DC); ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int indent TSRMLS_DC); diff --git a/Zend/zend_API.c b/Zend/zend_API.c index fe17968f06..c6b34e03f1 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1336,7 +1336,7 @@ ZEND_API int add_assoc_function(zval *arg, const char *key, void (*function_ptr) } /* }}} */ -ZEND_API int add_assoc_long_ex(zval *arg, const char *key, uint key_len, zend_long n) /* {{{ */ +ZEND_API int add_assoc_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */ { zval *ret, tmp; @@ -1346,7 +1346,7 @@ ZEND_API int add_assoc_long_ex(zval *arg, const char *key, uint key_len, zend_lo } /* }}} */ -ZEND_API int add_assoc_null_ex(zval *arg, const char *key, uint key_len) /* {{{ */ +ZEND_API int add_assoc_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */ { zval *ret, tmp; @@ -1356,7 +1356,7 @@ ZEND_API int add_assoc_null_ex(zval *arg, const char *key, uint key_len) /* {{{ } /* }}} */ -ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, uint key_len, int b) /* {{{ */ +ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, size_t key_len, int b) /* {{{ */ { zval *ret, tmp; @@ -1366,7 +1366,7 @@ ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, uint key_len, int b) } /* }}} */ -ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, uint key_len, zend_resource *r) /* {{{ */ +ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */ { zval *ret, tmp; @@ -1376,7 +1376,7 @@ ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, uint key_len, zen } /* }}} */ -ZEND_API int add_assoc_double_ex(zval *arg, const char *key, uint key_len, double d) /* {{{ */ +ZEND_API int add_assoc_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */ { zval *ret, tmp; @@ -1386,7 +1386,7 @@ ZEND_API int add_assoc_double_ex(zval *arg, const char *key, uint key_len, doubl } /* }}} */ -ZEND_API int add_assoc_str_ex(zval *arg, const char *key, uint key_len, zend_string *str) /* {{{ */ +ZEND_API int add_assoc_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */ { zval *ret, tmp; @@ -1396,7 +1396,7 @@ ZEND_API int add_assoc_str_ex(zval *arg, const char *key, uint key_len, zend_str } /* }}} */ -ZEND_API int add_assoc_string_ex(zval *arg, const char *key, uint key_len, char *str) /* {{{ */ +ZEND_API int add_assoc_string_ex(zval *arg, const char *key, size_t key_len, char *str) /* {{{ */ { zval *ret, tmp; @@ -1406,7 +1406,7 @@ ZEND_API int add_assoc_string_ex(zval *arg, const char *key, uint key_len, char } /* }}} */ -ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char *str, size_t length) /* {{{ */ +ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, char *str, size_t length) /* {{{ */ { zval *ret, tmp; @@ -1416,7 +1416,7 @@ ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char } /* }}} */ -ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, uint key_len, zval *value) /* {{{ */ +ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, size_t key_len, zval *value) /* {{{ */ { zval *ret; @@ -1689,7 +1689,7 @@ ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value TSRMLS_DC) } /* }}} */ -ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, zend_long n TSRMLS_DC) /* {{{ */ +ZEND_API int add_property_long_ex(zval *arg, const char *key, size_t key_len, zend_long n TSRMLS_DC) /* {{{ */ { zval tmp; zval z_key; @@ -1703,7 +1703,7 @@ ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, zend } /* }}} */ -ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, zend_long b TSRMLS_DC) /* {{{ */ +ZEND_API int add_property_bool_ex(zval *arg, const char *key, size_t key_len, zend_long b TSRMLS_DC) /* {{{ */ { zval tmp; zval z_key; @@ -1717,7 +1717,7 @@ ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, zend } /* }}} */ -ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRMLS_DC) /* {{{ */ +ZEND_API int add_property_null_ex(zval *arg, const char *key, size_t key_len TSRMLS_DC) /* {{{ */ { zval tmp; zval z_key; @@ -1731,7 +1731,7 @@ ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRML } /* }}} */ -ZEND_API int add_property_resource_ex(zval *arg, const char *key, uint key_len, zend_resource *r TSRMLS_DC) /* {{{ */ +ZEND_API int add_property_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r TSRMLS_DC) /* {{{ */ { zval tmp; zval z_key; @@ -1745,7 +1745,7 @@ ZEND_API int add_property_resource_ex(zval *arg, const char *key, uint key_len, } /* }}} */ -ZEND_API int add_property_double_ex(zval *arg, const char *key, uint key_len, double d TSRMLS_DC) /* {{{ */ +ZEND_API int add_property_double_ex(zval *arg, const char *key, size_t key_len, double d TSRMLS_DC) /* {{{ */ { zval tmp; zval z_key; @@ -1759,7 +1759,7 @@ ZEND_API int add_property_double_ex(zval *arg, const char *key, uint key_len, do } /* }}} */ -ZEND_API int add_property_str_ex(zval *arg, const char *key, uint key_len, zend_string *str TSRMLS_DC) /* {{{ */ +ZEND_API int add_property_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str TSRMLS_DC) /* {{{ */ { zval tmp; zval z_key; @@ -1773,7 +1773,7 @@ ZEND_API int add_property_str_ex(zval *arg, const char *key, uint key_len, zend_ } /* }}} */ -ZEND_API int add_property_string_ex(zval *arg, const char *key, uint key_len, const char *str TSRMLS_DC) /* {{{ */ +ZEND_API int add_property_string_ex(zval *arg, const char *key, size_t key_len, const char *str TSRMLS_DC) /* {{{ */ { zval tmp; zval z_key; @@ -1787,7 +1787,7 @@ ZEND_API int add_property_string_ex(zval *arg, const char *key, uint key_len, co } /* }}} */ -ZEND_API int add_property_stringl_ex(zval *arg, const char *key, uint key_len, const char *str, size_t length TSRMLS_DC) /* {{{ */ +ZEND_API int add_property_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length TSRMLS_DC) /* {{{ */ { zval tmp; zval z_key; @@ -1801,7 +1801,7 @@ ZEND_API int add_property_stringl_ex(zval *arg, const char *key, uint key_len, c } /* }}} */ -ZEND_API int add_property_zval_ex(zval *arg, const char *key, uint key_len, zval *value TSRMLS_DC) /* {{{ */ +ZEND_API int add_property_zval_ex(zval *arg, const char *key, size_t key_len, zval *value TSRMLS_DC) /* {{{ */ { zval z_key; @@ -1814,7 +1814,7 @@ ZEND_API int add_property_zval_ex(zval *arg, const char *key, uint key_len, zval ZEND_API int zend_startup_module_ex(zend_module_entry *module TSRMLS_DC) /* {{{ */ { - int name_len; + size_t name_len; zend_string *lcname; if (module->module_started) { @@ -2001,7 +2001,7 @@ ZEND_API void zend_destroy_modules(void) /* {{{ */ ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module TSRMLS_DC) /* {{{ */ { - int name_len; + size_t name_len; zend_string *lcname; zend_module_entry *module_ptr; @@ -2070,7 +2070,7 @@ ZEND_API zend_module_entry* zend_register_internal_module(zend_module_entry *mod ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, int error_type TSRMLS_DC) /* {{{ */ { char lcname[16]; - int name_len; + size_t name_len; /* we don't care if the function name is longer, in fact lowercasing only * the beginning of the name speeds up the check process */ @@ -2142,9 +2142,9 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio int error_type; zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__debugInfo = NULL; zend_string *lowercase_name; - int fname_len; + size_t fname_len; const char *lc_class_name = NULL; - int class_name_len = 0; + size_t class_name_len = 0; if (type==MODULE_PERSISTENT) { error_type = E_CORE_WARNING; @@ -2417,7 +2417,7 @@ ZEND_API void zend_unregister_functions(const zend_function_entry *functions, in int i=0; HashTable *target_function_table = function_table; zend_string *lowercase_name; - int fname_len; + size_t fname_len; if (!target_function_table) { target_function_table = CG(function_table); @@ -2699,7 +2699,7 @@ ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *or } /* }}} */ -ZEND_API int zend_register_class_alias_ex(const char *name, int name_len, zend_class_entry *ce TSRMLS_DC) /* {{{ */ +ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zend_class_entry *ce TSRMLS_DC) /* {{{ */ { zend_string *lcname; @@ -2759,7 +2759,7 @@ static zend_function_entry disabled_function[] = { ZEND_FE_END }; -ZEND_API int zend_disable_function(char *function_name, uint function_name_length TSRMLS_DC) /* {{{ */ +ZEND_API int zend_disable_function(char *function_name, size_t function_name_length TSRMLS_DC) /* {{{ */ { int ret; @@ -2792,7 +2792,7 @@ static const zend_function_entry disabled_class_new[] = { ZEND_FE_END }; -ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_DC) /* {{{ */ +ZEND_API int zend_disable_class(char *class_name, size_t class_name_length TSRMLS_DC) /* {{{ */ { zend_class_entry *disabled_class; zend_string *key; @@ -2814,7 +2814,7 @@ static int zend_is_callable_check_class(zend_string *name, zend_fcall_info_cache { int ret = 0; zend_class_entry *ce; - int name_len = name->len; + size_t name_len = name->len; zend_string *lcname; ALLOCA_FLAG(use_heap); @@ -2893,7 +2893,7 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca zend_string *mname, *cname; zend_string *lmname; const char *colon; - int clen, mlen; + size_t clen, mlen; zend_class_entry *last_scope; HashTable *ftable; int call_via_handler = 0; @@ -3579,7 +3579,7 @@ ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *f ZEND_API const char *zend_get_module_version(const char *module_name) /* {{{ */ { zend_string *lname; - int name_len = strlen(module_name); + size_t name_len = strlen(module_name); zend_module_entry *module; lname = zend_string_alloc(name_len, 0); @@ -3667,7 +3667,7 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z } /* }}} */ -ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type TSRMLS_DC) /* {{{ */ +ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type TSRMLS_DC) /* {{{ */ { zend_string *key = zend_string_init(name, name_length, ce->type & ZEND_INTERNAL_CLASS); int ret = zend_declare_property_ex(ce, key, property, access_type, NULL TSRMLS_CC); @@ -3676,7 +3676,7 @@ ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, int n } /* }}} */ -ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, int name_length, int access_type TSRMLS_DC) /* {{{ */ +ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, size_t name_length, int access_type TSRMLS_DC) /* {{{ */ { zval property; @@ -3685,7 +3685,7 @@ ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, } /* }}} */ -ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, int name_length, zend_long value, int access_type TSRMLS_DC) /* {{{ */ +ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type TSRMLS_DC) /* {{{ */ { zval property; @@ -3694,7 +3694,7 @@ ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, } /* }}} */ -ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, int name_length, zend_long value, int access_type TSRMLS_DC) /* {{{ */ +ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type TSRMLS_DC) /* {{{ */ { zval property; @@ -3703,7 +3703,7 @@ ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, } /* }}} */ -ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name, int name_length, double value, int access_type TSRMLS_DC) /* {{{ */ +ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name, size_t name_length, double value, int access_type TSRMLS_DC) /* {{{ */ { zval property; @@ -3712,7 +3712,7 @@ ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name } /* }}} */ -ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, int name_length, const char *value, int access_type TSRMLS_DC) /* {{{ */ +ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type TSRMLS_DC) /* {{{ */ { zval property; @@ -3721,7 +3721,7 @@ ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name } /* }}} */ -ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, int name_length, const char *value, size_t value_len, int access_type TSRMLS_DC) /* {{{ */ +ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type TSRMLS_DC) /* {{{ */ { zval property; @@ -3791,7 +3791,7 @@ ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char } /* }}} */ -ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, int name_length, zval *value TSRMLS_DC) /* {{{ */ +ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zval *value TSRMLS_DC) /* {{{ */ { zval property; zend_class_entry *old_scope = EG(scope); @@ -3809,7 +3809,7 @@ ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const } /* }}} */ -ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, int name_length TSRMLS_DC) /* {{{ */ +ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, size_t name_length TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3818,7 +3818,7 @@ ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, c } /* }}} */ -ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_long value TSRMLS_DC) /* {{{ */ +ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3827,7 +3827,7 @@ ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, c } /* }}} */ -ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_long value TSRMLS_DC) /* {{{ */ +ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3836,7 +3836,7 @@ ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, c } /* }}} */ -ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, int name_length, double value TSRMLS_DC) /* {{{ */ +ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, size_t name_length, double value TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3845,7 +3845,7 @@ ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, } /* }}} */ -ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_string *value TSRMLS_DC) /* {{{ */ +ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_string *value TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3854,7 +3854,7 @@ ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, co } /* }}} */ -ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, int name_length, const char *value TSRMLS_DC) /* {{{ */ +ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3864,7 +3864,7 @@ ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, } /* }}} */ -ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, int name_length, const char *value, size_t value_len TSRMLS_DC) /* {{{ */ +ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value, size_t value_len TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3874,7 +3874,7 @@ ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object } /* }}} */ -ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, int name_length, zval *value TSRMLS_DC) /* {{{ */ +ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, size_t name_length, zval *value TSRMLS_DC) /* {{{ */ { zval *property; zend_class_entry *old_scope = EG(scope); @@ -3913,7 +3913,7 @@ ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *na } /* }}} */ -ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, int name_length TSRMLS_DC) /* {{{ */ +ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, size_t name_length TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3922,7 +3922,7 @@ ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const cha } /* }}} */ -ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, int name_length, zend_long value TSRMLS_DC) /* {{{ */ +ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, size_t name_length, zend_long value TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3931,7 +3931,7 @@ ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const cha } /* }}} */ -ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, int name_length, zend_long value TSRMLS_DC) /* {{{ */ +ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, size_t name_length, zend_long value TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3940,7 +3940,7 @@ ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const cha } /* }}} */ -ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, int name_length, double value TSRMLS_DC) /* {{{ */ +ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, size_t name_length, double value TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3949,7 +3949,7 @@ ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const c } /* }}} */ -ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, int name_length, const char *value TSRMLS_DC) /* {{{ */ +ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, size_t name_length, const char *value TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3959,7 +3959,7 @@ ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const c } /* }}} */ -ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, int name_length, const char *value, size_t value_len TSRMLS_DC) /* {{{ */ +ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, size_t name_length, const char *value, size_t value_len TSRMLS_DC) /* {{{ */ { zval tmp; @@ -3969,7 +3969,7 @@ ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const } /* }}} */ -ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_bool silent TSRMLS_DC) /* {{{ */ +ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_bool silent TSRMLS_DC) /* {{{ */ { zval property, *value; zend_class_entry *old_scope = EG(scope); @@ -3990,7 +3990,7 @@ ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const c } /* }}} */ -ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, int name_length, zend_bool silent TSRMLS_DC) /* {{{ */ +ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, size_t name_length, zend_bool silent TSRMLS_DC) /* {{{ */ { zval *property; zend_class_entry *old_scope = EG(scope); diff --git a/Zend/zend_API.h b/Zend/zend_API.h index b2faf7e253..46e284be7f 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -276,15 +276,15 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *cla ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry TSRMLS_DC); ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int num_interfaces, ...); -ZEND_API int zend_register_class_alias_ex(const char *name, int name_len, zend_class_entry *ce TSRMLS_DC); +ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zend_class_entry *ce TSRMLS_DC); #define zend_register_class_alias(name, ce) \ zend_register_class_alias_ex(name, sizeof(name)-1, ce TSRMLS_CC) #define zend_register_ns_class_alias(ns, name, ce) \ zend_register_class_alias_ex(ZEND_NS_NAME(ns, name), sizeof(ZEND_NS_NAME(ns, name))-1, ce TSRMLS_CC) -ZEND_API int zend_disable_function(char *function_name, uint function_name_length TSRMLS_DC); -ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_DC); +ZEND_API int zend_disable_function(char *function_name, size_t function_name_length TSRMLS_DC); +ZEND_API int zend_disable_class(char *class_name, size_t class_name_length TSRMLS_DC); ZEND_API void zend_wrong_param_count(TSRMLS_D); @@ -301,13 +301,13 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam ZEND_API const char *zend_get_module_version(const char *module_name); ZEND_API int zend_get_module_started(const char *module_name); ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment TSRMLS_DC); -ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type TSRMLS_DC); -ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, int name_length, int access_type TSRMLS_DC); -ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, int name_length, zend_long value, int access_type TSRMLS_DC); -ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, int name_length, zend_long value, int access_type TSRMLS_DC); -ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name, int name_length, double value, int access_type TSRMLS_DC); -ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, int name_length, const char *value, int access_type TSRMLS_DC); -ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, int name_length, const char *value, size_t value_len, int access_type TSRMLS_DC); +ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type TSRMLS_DC); +ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, size_t name_length, int access_type TSRMLS_DC); +ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type TSRMLS_DC); +ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type TSRMLS_DC); +ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name, size_t name_length, double value, int access_type TSRMLS_DC); +ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type TSRMLS_DC); +ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type TSRMLS_DC); ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value TSRMLS_DC); ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length TSRMLS_DC); @@ -318,26 +318,26 @@ ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, const cha ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value TSRMLS_DC); ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC); -ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, int name_length, zval *value TSRMLS_DC); -ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, int name_length TSRMLS_DC); -ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_long value TSRMLS_DC); -ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_long value TSRMLS_DC); -ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, int name_length, double value TSRMLS_DC); -ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_string *value TSRMLS_DC); -ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, int name_length, const char *value TSRMLS_DC); -ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, int name_length, const char *value, size_t value_length TSRMLS_DC); - -ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, int name_length, zval *value TSRMLS_DC); -ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, int name_length TSRMLS_DC); -ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, int name_length, zend_long value TSRMLS_DC); -ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, int name_length, zend_long value TSRMLS_DC); -ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, int name_length, double value TSRMLS_DC); -ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, int name_length, const char *value TSRMLS_DC); -ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, int name_length, const char *value, size_t value_length TSRMLS_DC); - -ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, int name_length, zend_bool silent TSRMLS_DC); - -ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, int name_length, zend_bool silent TSRMLS_DC); +ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zval *value TSRMLS_DC); +ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, size_t name_length TSRMLS_DC); +ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value TSRMLS_DC); +ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value TSRMLS_DC); +ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, size_t name_length, double value TSRMLS_DC); +ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_string *value TSRMLS_DC); +ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value TSRMLS_DC); +ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value, size_t value_length TSRMLS_DC); + +ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, size_t name_length, zval *value TSRMLS_DC); +ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, size_t name_length TSRMLS_DC); +ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, size_t name_length, zend_long value TSRMLS_DC); +ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, size_t name_length, zend_long value TSRMLS_DC); +ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, size_t name_length, double value TSRMLS_DC); +ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, size_t name_length, const char *value TSRMLS_DC); +ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, size_t name_length, const char *value, size_t value_length TSRMLS_DC); + +ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_bool silent TSRMLS_DC); + +ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, size_t name_length, zend_bool silent TSRMLS_DC); ZEND_API char *zend_get_type_by_const(int type); @@ -373,15 +373,15 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties TSRMLS_DC); /* no longer supported */ ZEND_API int add_assoc_function(zval *arg, const char *key, void (*function_ptr)(INTERNAL_FUNCTION_PARAMETERS)); -ZEND_API int add_assoc_long_ex(zval *arg, const char *key, uint key_len, zend_long n); -ZEND_API int add_assoc_null_ex(zval *arg, const char *key, uint key_len); -ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, uint key_len, int b); -ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, uint key_len, zend_resource *r); -ZEND_API int add_assoc_double_ex(zval *arg, const char *key, uint key_len, double d); -ZEND_API int add_assoc_str_ex(zval *arg, const char *key, uint key_len, zend_string *str); -ZEND_API int add_assoc_string_ex(zval *arg, const char *key, uint key_len, char *str); -ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char *str, size_t length); -ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, uint key_len, zval *value); +ZEND_API int add_assoc_long_ex(zval *arg, const char *key, size_t key_len, zend_long n); +ZEND_API int add_assoc_null_ex(zval *arg, const char *key, size_t key_len); +ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, size_t key_len, int b); +ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r); +ZEND_API int add_assoc_double_ex(zval *arg, const char *key, size_t key_len, double d); +ZEND_API int add_assoc_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str); +ZEND_API int add_assoc_string_ex(zval *arg, const char *key, size_t key_len, char *str); +ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, char *str, size_t length); +ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, size_t key_len, zval *value); #define add_assoc_long(__arg, __key, __n) add_assoc_long_ex(__arg, __key, strlen(__key), __n) #define add_assoc_null(__arg, __key) add_assoc_null_ex(__arg, __key, strlen(__key)) @@ -433,15 +433,15 @@ ZEND_API zval *add_get_index_stringl(zval *arg, zend_ulong idx, const char *str, ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value TSRMLS_DC); -ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, zend_long l TSRMLS_DC); -ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRMLS_DC); -ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, zend_long b TSRMLS_DC); -ZEND_API int add_property_resource_ex(zval *arg, const char *key, uint key_len, zend_resource *r TSRMLS_DC); -ZEND_API int add_property_double_ex(zval *arg, const char *key, uint key_len, double d TSRMLS_DC); -ZEND_API int add_property_str_ex(zval *arg, const char *key, uint key_len, zend_string *str TSRMLS_DC); -ZEND_API int add_property_string_ex(zval *arg, const char *key, uint key_len, const char *str TSRMLS_DC); -ZEND_API int add_property_stringl_ex(zval *arg, const char *key, uint key_len, const char *str, size_t length TSRMLS_DC); -ZEND_API int add_property_zval_ex(zval *arg, const char *key, uint key_len, zval *value TSRMLS_DC); +ZEND_API int add_property_long_ex(zval *arg, const char *key, size_t key_len, zend_long l TSRMLS_DC); +ZEND_API int add_property_null_ex(zval *arg, const char *key, size_t key_len TSRMLS_DC); +ZEND_API int add_property_bool_ex(zval *arg, const char *key, size_t key_len, zend_long b TSRMLS_DC); +ZEND_API int add_property_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r TSRMLS_DC); +ZEND_API int add_property_double_ex(zval *arg, const char *key, size_t key_len, double d TSRMLS_DC); +ZEND_API int add_property_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str TSRMLS_DC); +ZEND_API int add_property_string_ex(zval *arg, const char *key, size_t key_len, const char *str TSRMLS_DC); +ZEND_API int add_property_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length TSRMLS_DC); +ZEND_API int add_property_zval_ex(zval *arg, const char *key, size_t key_len, zval *value TSRMLS_DC); #define add_property_long(__arg, __key, __n) add_property_long_ex(__arg, __key, strlen(__key), __n TSRMLS_CC) #define add_property_null(__arg, __key) add_property_null_ex(__arg, __key, strlen(__key) TSRMLS_CC) @@ -451,7 +451,7 @@ ZEND_API int add_property_zval_ex(zval *arg, const char *key, uint key_len, zval #define add_property_str(__arg, __key, __str) add_property_str_ex(__arg, __key, strlen(__key), __str TSRMLS_CC) #define add_property_string(__arg, __key, __str) add_property_string_ex(__arg, __key, strlen(__key), __str TSRMLS_CC) #define add_property_stringl(__arg, __key, __str, __length) add_property_stringl_ex(__arg, __key, strlen(__key), __str, __length TSRMLS_CC) -#define add_property_zval(__arg, __key, __value) add_property_zval_ex(__arg, __key, strlen(__key), __value TSRMLS_CC) +#define add_property_zval(__arg, __key, __value) add_property_zval_ex(__arg, __key, strlen(__key), __value TSRMLS_CC) ZEND_API int call_user_function(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[] TSRMLS_DC); diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 8bc7bcb44d..578c3a80ea 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -1028,7 +1028,7 @@ found: static zend_always_inline void *zend_mm_alloc_large(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { - int pages_count = ZEND_MM_SIZE_TO_NUM(size, ZEND_MM_PAGE_SIZE); + int pages_count = (int)ZEND_MM_SIZE_TO_NUM(size, ZEND_MM_PAGE_SIZE); #if ZEND_DEBUG void *ptr = zend_mm_alloc_pages(heap, pages_count, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); #else @@ -1261,7 +1261,7 @@ static zend_always_inline zend_mm_debug_info *zend_mm_get_debug_info(zend_mm_hea ZEND_MM_CHECK(page_offset != 0, "zend_mm_heap corrupted"); chunk = (zend_mm_chunk*)ZEND_MM_ALIGNED_BASE(ptr, ZEND_MM_CHUNK_SIZE); - page_num = page_offset / ZEND_MM_PAGE_SIZE; + page_num = (int)(page_offset / ZEND_MM_PAGE_SIZE); info = chunk->map[page_num]; ZEND_MM_CHECK(chunk->heap == heap, "zend_mm_heap corrupted"); if (EXPECTED(info & ZEND_MM_IS_SRUN)) { @@ -1326,7 +1326,7 @@ static zend_always_inline void zend_mm_free_heap(zend_mm_heap *heap, void *ptr Z } } else { zend_mm_chunk *chunk = (zend_mm_chunk*)ZEND_MM_ALIGNED_BASE(ptr, ZEND_MM_CHUNK_SIZE); - int page_num = page_offset / ZEND_MM_PAGE_SIZE; + int page_num = (int)(page_offset / ZEND_MM_PAGE_SIZE); zend_mm_page_info info = chunk->map[page_num]; ZEND_MM_CHECK(chunk->heap == heap, "zend_mm_heap corrupted"); @@ -1357,7 +1357,7 @@ static size_t zend_mm_size(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZEND_ zend_mm_page_info info; chunk = (zend_mm_chunk*)ZEND_MM_ALIGNED_BASE(ptr, ZEND_MM_CHUNK_SIZE); - page_num = page_offset / ZEND_MM_PAGE_SIZE; + page_num = (int)(page_offset / ZEND_MM_PAGE_SIZE); info = chunk->map[page_num]; ZEND_MM_CHECK(chunk->heap == heap, "zend_mm_heap corrupted"); if (EXPECTED(info & ZEND_MM_IS_SRUN)) { @@ -1451,7 +1451,7 @@ static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size ZEN } } else { zend_mm_chunk *chunk = (zend_mm_chunk*)ZEND_MM_ALIGNED_BASE(ptr, ZEND_MM_CHUNK_SIZE); - int page_num = page_offset / ZEND_MM_PAGE_SIZE; + int page_num = (int)(page_offset / ZEND_MM_PAGE_SIZE); zend_mm_page_info info = chunk->map[page_num]; #if ZEND_DEBUG size_t real_size = size; @@ -1494,8 +1494,8 @@ static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size ZEN return ptr; } else if (new_size < old_size) { /* free tail pages */ - int new_pages_count = new_size / ZEND_MM_PAGE_SIZE; - int rest_pages_count = (old_size - new_size) / ZEND_MM_PAGE_SIZE; + int new_pages_count = (int)(new_size / ZEND_MM_PAGE_SIZE); + int rest_pages_count = (int)((old_size - new_size) / ZEND_MM_PAGE_SIZE); #if ZEND_MM_STAT heap->size -= rest_pages_count * ZEND_MM_PAGE_SIZE; @@ -1513,8 +1513,8 @@ static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size ZEN #endif return ptr; } else /* if (new_size > old_size) */ { - int new_pages_count = new_size / ZEND_MM_PAGE_SIZE; - int old_pages_count = old_size / ZEND_MM_PAGE_SIZE; + int new_pages_count = (int)(new_size / ZEND_MM_PAGE_SIZE); + int old_pages_count = (int)(old_size / ZEND_MM_PAGE_SIZE); /* try to allocate tail pages after this block */ if (page_num + new_pages_count <= ZEND_MM_PAGES && diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 9487bb6c1e..8203d39e51 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1059,7 +1059,7 @@ ZEND_FUNCTION(get_object_vars) } /* }}} */ -static int same_name(const char *key, const char *name, uint32_t name_len) /* {{{ */ +static int same_name(const char *key, const char *name, size_t name_len) /* {{{ */ { char *lcname = zend_str_tolower_dup(name, name_len); int ret = memcmp(lcname, key, name_len) == 0; @@ -1102,7 +1102,7 @@ ZEND_FUNCTION(get_class_methods) zend_check_protected(mptr->common.scope, EG(scope))) || ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) && EG(scope) == mptr->common.scope)))) { - uint len = mptr->common.function_name->len; + size_t len = mptr->common.function_name->len; /* Do not display old-style inherited constructors */ if (!key) { diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e1246b28dc..c72a972007 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -514,7 +514,7 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */ opline->result_type |= EXT_TYPE_UNUSED; } } else { - while (opline>CG(active_op_array)->opcodes) { + while (opline >= CG(active_op_array)->opcodes) { if (opline->opcode == ZEND_FETCH_LIST && opline->op1_type == IS_VAR && opline->op1.var == op1->u.op.var) { @@ -1107,7 +1107,7 @@ ZEND_API zend_string *zend_mangle_property_name(const char *src1, size_t src1_le } /* }}} */ -static int zend_strnlen(const char* s, size_t maxlen) /* {{{ */ +static size_t zend_strnlen(const char* s, size_t maxlen) /* {{{ */ { size_t len = 0; while (*s++ && maxlen--) len++; @@ -1641,11 +1641,8 @@ static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */ case BP_VAR_R: return; case BP_VAR_W: - opline->opcode += 3; - return; case BP_VAR_REF: opline->opcode += 3; - opline->extended_value |= ZEND_FETCH_MAKE_REF; return; case BP_VAR_RW: opline->opcode += 6; @@ -2281,8 +2278,6 @@ void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ opline->opcode = ZEND_ASSIGN_DIM; opline = zend_emit_op_data(&expr_node TSRMLS_CC); - opline->op2.var = get_temporary_variable(CG(active_op_array)); - opline->op2_type = IS_VAR; return; case ZEND_AST_PROP: offset = zend_delayed_compile_begin(TSRMLS_C); @@ -2374,8 +2369,6 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ opline->extended_value = ZEND_ASSIGN_DIM; opline = zend_emit_op_data(&expr_node TSRMLS_CC); - opline->op2.var = get_temporary_variable(CG(active_op_array)); - opline->op2_type = IS_VAR; return; case ZEND_AST_PROP: offset = zend_delayed_compile_begin(TSRMLS_C); @@ -2944,10 +2937,23 @@ void zend_compile_new(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ zend_op *opline; uint32_t opnum; - zend_compile_class_ref(&class_node, class_ast TSRMLS_CC); + if (zend_is_const_default_class_ref(class_ast)) { + class_node.op_type = IS_CONST; + ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast TSRMLS_CC)); + } else { + zend_compile_class_ref(&class_node, class_ast TSRMLS_CC); + } opnum = get_next_op_number(CG(active_op_array)); - zend_emit_op(result, ZEND_NEW, &class_node, NULL TSRMLS_CC); + opline = zend_emit_op(result, ZEND_NEW, NULL, NULL TSRMLS_CC); + + if (class_node.op_type == IS_CONST) { + opline->op1_type = IS_CONST; + opline->op1.constant = zend_add_class_name_literal( + CG(active_op_array), Z_STR(class_node.u.constant) TSRMLS_CC); + } else { + SET_NODE(opline->op1, &class_node); + } zend_compile_call_common(&ctor_result, args_ast, NULL TSRMLS_CC); zend_do_free(&ctor_result TSRMLS_CC); @@ -3125,7 +3131,7 @@ void zend_compile_return(zend_ast *ast TSRMLS_DC) /* {{{ */ if (expr_ast) { if (zend_is_call(expr_ast)) { opline->extended_value = ZEND_RETURNS_FUNCTION; - } else if (!zend_is_variable(expr_ast)) { + } else if (by_ref && !zend_is_variable(expr_ast)) { opline->extended_value = ZEND_RETURNS_VALUE; } } @@ -3812,7 +3818,7 @@ void zend_compile_params(zend_ast *ast TSRMLS_DC) /* {{{ */ arg_info = &arg_infos[i]; arg_info->name = estrndup(name->val, name->len); - arg_info->name_len = name->len; + arg_info->name_len = (uint32_t)name->len; arg_info->pass_by_reference = is_ref; arg_info->is_variadic = is_variadic; arg_info->type_hint = 0; @@ -3856,7 +3862,7 @@ void zend_compile_params(zend_ast *ast TSRMLS_DC) /* {{{ */ arg_info->type_hint = IS_OBJECT; arg_info->class_name = estrndup(class_name->val, class_name->len); - arg_info->class_name_len = class_name->len; + arg_info->class_name_len = (uint32_t)class_name->len; zend_string_release(class_name); @@ -4389,7 +4395,6 @@ void zend_compile_use_trait(zend_ast *ast TSRMLS_DC) /* {{{ */ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_ADD_TRAIT; SET_NODE(opline->op1, &CG(implementing_class)); - opline->extended_value = ZEND_FETCH_CLASS_TRAIT; opline->op2_type = IS_CONST; opline->op2.constant = zend_add_class_name_literal(CG(active_op_array), zend_resolve_class_name_ast(trait_ast TSRMLS_CC) TSRMLS_CC); @@ -4438,7 +4443,6 @@ void zend_compile_implements(znode *class_node, zend_ast *ast TSRMLS_DC) /* {{{ } opline = zend_emit_op(NULL, ZEND_ADD_INTERFACE, class_node, NULL TSRMLS_CC); - opline->extended_value = ZEND_FETCH_CLASS_INTERFACE; opline->op2_type = IS_CONST; opline->op2.constant = zend_add_class_name_literal(CG(active_op_array), zend_resolve_class_name_ast(class_ast TSRMLS_CC) TSRMLS_CC); @@ -5420,10 +5424,23 @@ void zend_compile_instanceof(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ "instanceof expects an object instance, constant given"); } - opline = zend_compile_class_ref(&class_node, class_ast TSRMLS_CC); - opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD; + if (zend_is_const_default_class_ref(class_ast)) { + class_node.op_type = IS_CONST; + ZVAL_STR(&class_node.u.constant, zend_resolve_class_name_ast(class_ast TSRMLS_CC)); + } else { + opline = zend_compile_class_ref(&class_node, class_ast TSRMLS_CC); + opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD; + } + + opline = zend_emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, NULL TSRMLS_CC); - zend_emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, &class_node TSRMLS_CC); + if (class_node.op_type == IS_CONST) { + opline->op2_type = IS_CONST; + opline->op2.constant = zend_add_class_name_literal( + CG(active_op_array), Z_STR(class_node.u.constant) TSRMLS_CC); + } else { + SET_NODE(opline->op2, &class_node); + } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index e9ee6e56d7..bc9b88227f 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -619,7 +619,6 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC); #define ZEND_FETCH_TYPE_MASK 0x70000000 #define ZEND_FETCH_STANDARD 0x00000000 -#define ZEND_FETCH_MAKE_REF 0x04000000 #define ZEND_ISSET 0x02000000 #define ZEND_ISEMPTY 0x01000000 diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 164901f898..61cc49e5c5 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -161,7 +161,7 @@ void clean_non_persistent_constants(TSRMLS_D) } } -ZEND_API void zend_register_null_constant(const char *name, uint name_len, int flags, int module_number TSRMLS_DC) +ZEND_API void zend_register_null_constant(const char *name, size_t name_len, int flags, int module_number TSRMLS_DC) { zend_constant c; @@ -172,7 +172,7 @@ ZEND_API void zend_register_null_constant(const char *name, uint name_len, int f zend_register_constant(&c TSRMLS_CC); } -ZEND_API void zend_register_bool_constant(const char *name, uint name_len, zend_bool bval, int flags, int module_number TSRMLS_DC) +ZEND_API void zend_register_bool_constant(const char *name, size_t name_len, zend_bool bval, int flags, int module_number TSRMLS_DC) { zend_constant c; @@ -183,7 +183,7 @@ ZEND_API void zend_register_bool_constant(const char *name, uint name_len, zend_ zend_register_constant(&c TSRMLS_CC); } -ZEND_API void zend_register_long_constant(const char *name, uint name_len, zend_long lval, int flags, int module_number TSRMLS_DC) +ZEND_API void zend_register_long_constant(const char *name, size_t name_len, zend_long lval, int flags, int module_number TSRMLS_DC) { zend_constant c; @@ -195,7 +195,7 @@ ZEND_API void zend_register_long_constant(const char *name, uint name_len, zend_ } -ZEND_API void zend_register_double_constant(const char *name, uint name_len, double dval, int flags, int module_number TSRMLS_DC) +ZEND_API void zend_register_double_constant(const char *name, size_t name_len, double dval, int flags, int module_number TSRMLS_DC) { zend_constant c; @@ -207,7 +207,7 @@ ZEND_API void zend_register_double_constant(const char *name, uint name_len, dou } -ZEND_API void zend_register_stringl_constant(const char *name, uint name_len, char *strval, uint strlen, int flags, int module_number TSRMLS_DC) +ZEND_API void zend_register_stringl_constant(const char *name, size_t name_len, char *strval, size_t strlen, int flags, int module_number TSRMLS_DC) { zend_constant c; @@ -219,12 +219,12 @@ ZEND_API void zend_register_stringl_constant(const char *name, uint name_len, ch } -ZEND_API void zend_register_string_constant(const char *name, uint name_len, char *strval, int flags, int module_number TSRMLS_DC) +ZEND_API void zend_register_string_constant(const char *name, size_t name_len, char *strval, int flags, int module_number TSRMLS_DC) { zend_register_stringl_constant(name, name_len, strval, strlen(strval), flags, module_number TSRMLS_CC); } -static zend_constant *zend_get_special_constant(const char *name, uint name_len TSRMLS_DC) +static zend_constant *zend_get_special_constant(const char *name, size_t name_len TSRMLS_DC) { zend_constant *c; static char haltoff[] = "__COMPILER_HALT_OFFSET__"; @@ -236,7 +236,7 @@ static zend_constant *zend_get_special_constant(const char *name, uint name_len /* Returned constants may be cached, so they have to be stored */ if (EG(scope) && EG(scope)->name) { - int const_name_len; + size_t const_name_len; zend_string *const_name; const_name_len = sizeof("\0__CLASS__") + EG(scope)->name->len; @@ -265,7 +265,7 @@ static zend_constant *zend_get_special_constant(const char *name, uint name_len !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) { const char *cfilename; zend_string *haltname; - int clen; + size_t clen; cfilename = zend_get_executed_filename(TSRMLS_C); clen = strlen(cfilename); @@ -281,7 +281,7 @@ static zend_constant *zend_get_special_constant(const char *name, uint name_len } -ZEND_API zval *zend_get_constant_str(const char *name, uint name_len TSRMLS_DC) +ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len TSRMLS_DC) { zend_constant *c; ALLOCA_FLAG(use_heap) @@ -330,7 +330,7 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, zend_class_entry *ce = NULL; zend_string *class_name; const char *name = cname->val; - uint name_len = cname->len; + size_t name_len = cname->len; /* Skip leading \\ */ if (name[0] == '\\') { @@ -342,7 +342,7 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, if ((colon = zend_memrchr(name, ':', name_len)) && colon > name && (*(colon - 1) == ':')) { int class_name_len = colon - name - 1; - int const_name_len = name_len - class_name_len - 2; + size_t const_name_len = name_len - class_name_len - 2; zend_string *constant_name = zend_string_init(colon + 1, const_name_len, 0); char *lcname; zval *ret_constant = NULL; @@ -408,10 +408,10 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, if ((colon = zend_memrchr(name, '\\', name_len)) != NULL) { /* compound constant name */ int prefix_len = colon - name; - int const_name_len = name_len - prefix_len - 1; + size_t const_name_len = name_len - prefix_len - 1; const char *constant_name = colon + 1; char *lcname; - int lcname_len; + size_t lcname_len; ALLOCA_FLAG(use_heap) lcname_len = prefix_len + 1 + const_name_len; diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index d81476f3f4..6d5542e1ec 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -66,14 +66,14 @@ int zend_shutdown_constants(TSRMLS_D); void zend_register_standard_constants(TSRMLS_D); void clean_non_persistent_constants(TSRMLS_D); ZEND_API zval *zend_get_constant(zend_string *name TSRMLS_DC); -ZEND_API zval *zend_get_constant_str(const char *name, uint name_len TSRMLS_DC); +ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len TSRMLS_DC); ZEND_API zval *zend_get_constant_ex(zend_string *name, zend_class_entry *scope, zend_ulong flags TSRMLS_DC); -ZEND_API void zend_register_bool_constant(const char *name, uint name_len, zend_bool bval, int flags, int module_number TSRMLS_DC); -ZEND_API void zend_register_null_constant(const char *name, uint name_len, int flags, int module_number TSRMLS_DC); -ZEND_API void zend_register_long_constant(const char *name, uint name_len, zend_long lval, int flags, int module_number TSRMLS_DC); -ZEND_API void zend_register_double_constant(const char *name, uint name_len, double dval, int flags, int module_number TSRMLS_DC); -ZEND_API void zend_register_string_constant(const char *name, uint name_len, char *strval, int flags, int module_number TSRMLS_DC); -ZEND_API void zend_register_stringl_constant(const char *name, uint name_len, char *strval, uint strlen, int flags, int module_number TSRMLS_DC); +ZEND_API void zend_register_bool_constant(const char *name, size_t name_len, zend_bool bval, int flags, int module_number TSRMLS_DC); +ZEND_API void zend_register_null_constant(const char *name, size_t name_len, int flags, int module_number TSRMLS_DC); +ZEND_API void zend_register_long_constant(const char *name, size_t name_len, zend_long lval, int flags, int module_number TSRMLS_DC); +ZEND_API void zend_register_double_constant(const char *name, size_t name_len, double dval, int flags, int module_number TSRMLS_DC); +ZEND_API void zend_register_string_constant(const char *name, size_t name_len, char *strval, int flags, int module_number TSRMLS_DC); +ZEND_API void zend_register_stringl_constant(const char *name, size_t name_len, char *strval, size_t strlen, int flags, int module_number TSRMLS_DC); ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC); void zend_copy_constants(HashTable *target, HashTable *sourc); zend_constant *zend_quick_get_constant(const zval *key, zend_ulong flags TSRMLS_DC); diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index f9c1a509a6..4159a46d3c 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -90,7 +90,7 @@ ZEND_API void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */ #ifdef HAVE_DTRACE if (DTRACE_EXCEPTION_THROWN_ENABLED()) { if (exception != NULL) { - DTRACE_EXCEPTION_THROWN(Z_OBJ_P(exception)->ce->val); + DTRACE_EXCEPTION_THROWN(Z_OBJ_P(exception)->ce->name->val); } else { DTRACE_EXCEPTION_THROWN(NULL); } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 58038c94a4..61a605971e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -547,13 +547,13 @@ static inline zval* make_real_object(zval *object_ptr TSRMLS_DC) return object; } -ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, zend_ulong fetch_type, char **class_name, zend_class_entry **pce TSRMLS_DC) +ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC) { zend_string *key; ALLOCA_FLAG(use_heap); STR_ALLOCA_INIT(key, cur_arg_info->class_name, cur_arg_info->class_name_len, use_heap); - *pce = zend_fetch_class(key, (fetch_type | ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC); + *pce = zend_fetch_class(key, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC); STR_ALLOCA_FREE(key, use_heap); *class_name = (*pce) ? (*pce)->name->val : (char*)cur_arg_info->class_name; @@ -596,7 +596,7 @@ ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uin } } -static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zend_ulong fetch_type TSRMLS_DC) +static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg TSRMLS_DC) { zend_arg_info *cur_arg_info; char *need_msg; @@ -619,12 +619,12 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, ZVAL_DEREF(arg); if (Z_TYPE_P(arg) == IS_OBJECT) { - need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); + need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC); if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) { zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg TSRMLS_CC); } } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) { - need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); + need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC); zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg TSRMLS_CC); } } else if (cur_arg_info->type_hint) { @@ -645,7 +645,7 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, } } -static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num, zend_ulong fetch_type TSRMLS_DC) +static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num TSRMLS_DC) { zend_arg_info *cur_arg_info; char *need_msg; @@ -666,7 +666,7 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n if (cur_arg_info->class_name) { char *class_name; - need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); + need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC); zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL TSRMLS_CC); return 0; } else if (cur_arg_info->type_hint) { @@ -687,7 +687,7 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n static void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t arg_num TSRMLS_DC) { if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) || - zend_verify_missing_arg_type(EX(func), arg_num, EX(opline)->extended_value TSRMLS_CC)) { + zend_verify_missing_arg_type(EX(func), arg_num TSRMLS_CC)) { const char *class_name = EX(func)->common.scope ? EX(func)->common.scope->name->val : ""; const char *space = EX(func)->common.scope ? "::" : ""; const char *func_name = EX(func)->common.function_name ? EX(func)->common.function_name->val : "main"; @@ -1048,12 +1048,61 @@ str_index: return retval; } -static zend_always_inline zval *zend_fetch_dimension_address(zval *result, zval *container_ptr, zval *dim, int dim_type, int type, int is_ref, int allow_str_offset TSRMLS_DC) +static zend_never_inline zend_long zend_check_string_offset(zval *container, zval *dim, int type TSRMLS_DC) +{ + zend_long offset; + + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) { + switch(Z_TYPE_P(dim)) { + case IS_STRING: + if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) { + break; + } + if (type != BP_VAR_UNSET) { + zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim)); + } + break; + case IS_DOUBLE: + case IS_NULL: + case IS_FALSE: + case IS_TRUE: + zend_error(E_NOTICE, "String offset cast occurred"); + break; + default: + zend_error(E_WARNING, "Illegal offset type"); + break; + } + + offset = zval_get_long(dim); + } else { + offset = Z_LVAL_P(dim); + } + + return offset; +} + +static zend_always_inline zend_long zend_fetch_string_offset(zval *container, zval *dim, int type TSRMLS_DC) +{ + zend_long offset = zend_check_string_offset(container, dim, type TSRMLS_CC); + + if (Z_REFCOUNTED_P(container)) { + if (Z_REFCOUNT_P(container) > 1) { + Z_DELREF_P(container); + zval_copy_ctor_func(container); + } + Z_ADDREF_P(container); + } + return offset; +} + +static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *container, zval *dim, int dim_type, int type TSRMLS_DC) { zval *retval; - zval *container = container_ptr; - ZVAL_DEREF(container); if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { SEPARATE_ARRAY(container); fetch_from_array: @@ -1066,13 +1115,8 @@ fetch_from_array: } else { retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC); } - if (is_ref) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(result, retval); } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { - zend_long offset; - if (type != BP_VAR_UNSET && UNEXPECTED(Z_STRLEN_P(container) == 0)) { zval_ptr_dtor_nogc(container); convert_to_array: @@ -1081,49 +1125,9 @@ convert_to_array: goto fetch_from_array; } - if (dim == NULL) { - zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); - } - - if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) { - switch(Z_TYPE_P(dim)) { - case IS_STRING: - if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) { - break; - } - if (type != BP_VAR_UNSET) { - zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim)); - } - break; - case IS_DOUBLE: - case IS_NULL: - case IS_FALSE: - case IS_TRUE: - zend_error(E_NOTICE, "String offset cast occurred"); - break; - default: - zend_error(E_WARNING, "Illegal offset type"); - break; - } - - offset = zval_get_long(dim); - } else { - offset = Z_LVAL_P(dim); - } - - if (allow_str_offset) { - if (Z_REFCOUNTED_P(container)) { - if (Z_REFCOUNT_P(container) > 1) { - Z_DELREF_P(container); - zval_copy_ctor_func(container); - } - Z_ADDREF_P(container); - } - ZVAL_LONG(result, offset); - return container; /* assignment to string offset */ - } else { - ZVAL_INDIRECT(result, NULL); /* wrong string offset */ - } + zend_check_string_offset(container, dim, type TSRMLS_CC); + + ZVAL_INDIRECT(result, NULL); /* wrong string offset */ } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (!Z_OBJ_HT_P(container)->read_dimension) { zend_error_noreturn(E_ERROR, "Cannot use object as array"); @@ -1154,9 +1158,6 @@ convert_to_array: } } if (result != retval) { - if (is_ref) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(result, retval); } } else { @@ -1185,32 +1186,21 @@ convert_to_array: ZVAL_INDIRECT(result, &EG(error_zval)); } } - return NULL; /* not an assignment to string offset */ } static zend_never_inline void zend_fetch_dimension_address_W(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) { - zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 0, 0 TSRMLS_CC); -} - -static zend_never_inline zval *zend_fetch_dimension_address_W_str(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) -{ - return zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 0, 1 TSRMLS_CC); -} - -static zend_never_inline void zend_fetch_dimension_address_W_ref(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) -{ - zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 1, 0 TSRMLS_CC); + zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W TSRMLS_CC); } static zend_never_inline void zend_fetch_dimension_address_RW(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) { - zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW, 0, 0 TSRMLS_CC); + zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW TSRMLS_CC); } static zend_never_inline void zend_fetch_dimension_address_UNSET(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) { - zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET, 0, 0 TSRMLS_CC); + zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET TSRMLS_CC); } static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type TSRMLS_DC) @@ -1302,7 +1292,7 @@ ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval * zend_fetch_dimension_address_read_R(result, container, dim, IS_TMP_VAR TSRMLS_CC); } -static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, void **cache_slot, int type, int is_ref TSRMLS_DC) +static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, void **cache_slot, int type TSRMLS_DC) { if (container_op_type != IS_UNUSED) { ZVAL_DEREF(container); @@ -1332,26 +1322,17 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c if (Z_OBJ_HT_P(container)->read_property && (ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result TSRMLS_CC)) != NULL) { if (ptr != result) { - if (is_ref && ptr != &EG(uninitialized_zval)) { - ZVAL_MAKE_REF(ptr); - } ZVAL_INDIRECT(result, ptr); } } else { zend_error_noreturn(E_ERROR, "Cannot access undefined property for object with overloaded property access"); } } else { - if (is_ref) { - ZVAL_MAKE_REF(ptr); - } ZVAL_INDIRECT(result, ptr); } } else if (EXPECTED(Z_OBJ_HT_P(container)->read_property)) { zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result TSRMLS_CC); if (ptr != result) { - if (is_ref && ptr != &EG(uninitialized_zval)) { - ZVAL_MAKE_REF(ptr); - } ZVAL_INDIRECT(result, ptr); } } else { diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 95421191f0..982413e032 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -44,11 +44,11 @@ ZEND_API int zend_is_true(zval *op TSRMLS_DC); ZEND_API zend_class_entry *zend_lookup_class(zend_string *name TSRMLS_DC); ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *key, int use_autoload TSRMLS_DC); ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC); -ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *string_name TSRMLS_DC); +ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char *string_name TSRMLS_DC); ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); -ZEND_API int zend_eval_stringl_ex(char *str, int str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); +ZEND_API int zend_eval_stringl_ex(char *str, size_t str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); -ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, zend_ulong fetch_type, char **class_name, zend_class_entry **pce TSRMLS_DC); +ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce TSRMLS_DC); ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC); static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC TSRMLS_DC) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index bd24609d01..7cbf2ac87c 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -529,7 +529,7 @@ ZEND_API int zval_update_constant_ex(zval *p, zend_bool inline_change, zend_clas char *actual = Z_STRVAL_P(p); if ((colon = (char*)zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p)))) { - int len; + size_t len; zend_error(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(p)); len = Z_STRLEN_P(p) - ((colon - Z_STRVAL_P(p)) + 1); @@ -544,7 +544,7 @@ ZEND_API int zval_update_constant_ex(zval *p, zend_bool inline_change, zend_clas } else { zend_string *save = Z_STR_P(p); char *slash; - int actual_len = Z_STRLEN_P(p); + size_t actual_len = Z_STRLEN_P(p); if ((Z_CONST_FLAGS_P(p) & IS_CONSTANT_UNQUALIFIED) && (slash = (char *)zend_memrchr(actual, '\\', actual_len))) { actual = slash + 1; actual_len -= (actual - Z_STRVAL_P(p)); @@ -1055,7 +1055,7 @@ ZEND_API zend_class_entry *zend_lookup_class(zend_string *name TSRMLS_DC) /* {{{ } /* }}} */ -ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *string_name TSRMLS_DC) /* {{{ */ +ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char *string_name TSRMLS_DC) /* {{{ */ { zval pv; zend_op_array *new_op_array; @@ -1123,7 +1123,7 @@ ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSR } /* }}} */ -ZEND_API int zend_eval_stringl_ex(char *str, int str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC) /* {{{ */ +ZEND_API int zend_eval_stringl_ex(char *str, size_t str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC) /* {{{ */ { int result; diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index dfd63aa7e1..6dc0941c6f 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -99,19 +99,34 @@ static const uint32_t uninitialized_bucket = {INVALID_IDX}; ZEND_API void _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) { - uint32_t i = 3; - - SET_INCONSISTENT(HT_OK); - - if (nSize >= 0x80000000) { + /* Use big enough power of 2 */ +#ifdef PHP_WIN32 + if (nSize <= 8) { + ht->nTableSize = 8; + } else if (nSize >= 0x80000000) { /* prevent overflow */ ht->nTableSize = 0x80000000; } else { - while ((1U << i) < nSize) { - i++; + ht->nTableSize = 1U << __lzcnt(nSize); + if (ht->nTableSize < nSize) { + ht->nTableSize <<= 1; } - ht->nTableSize = 1 << i; } +#else + /* size should be between 8 and 0x80000000 */ + nSize = (nSize <= 8 ? 8 : (nSize >= 0x80000000 ? 0x80000000 : nSize)); +# if defined(__GNUC__) + ht->nTableSize = 0x2 << (__builtin_clz(nSize - 1) ^ 0x1f); +# else + nSize -= 1; + nSize |= (nSize >> 1); + nSize |= (nSize >> 2); + nSize |= (nSize >> 4); + nSize |= (nSize >> 8); + nSize |= (nSize >> 16); + ht->nTableSize = nSize + 1; +# endif +#endif ht->nTableMask = 0; /* 0 means that ht->arBuckets is uninitialized */ ht->nNumUsed = 0; @@ -121,11 +136,7 @@ ZEND_API void _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestru ht->arHash = (uint32_t*)&uninitialized_bucket; ht->pDestructor = pDestructor; ht->nInternalPointer = INVALID_IDX; - if (persistent) { - ht->u.flags = HASH_FLAG_PERSISTENT | HASH_FLAG_APPLY_PROTECTION; - } else { - ht->u.flags = HASH_FLAG_APPLY_PROTECTION; - } + ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION; } static void zend_hash_packed_grow(HashTable *ht) @@ -1749,11 +1760,12 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co return result; } } else { /* string indices */ - result = (p1->key ? p1->key->len : 0) - (p2->key ? p2->key->len : 0); - if (result != 0) { + size_t len0 = (p1->key ? p1->key->len : 0); + size_t len1 = (p2->key ? p2->key->len : 0); + if (len0 != len1) { HASH_UNPROTECT_RECURSION(ht1); HASH_UNPROTECT_RECURSION(ht2); - return result; + return len0 > len1 ? 1 : -1; } result = memcmp(p1->key->val, p2->key->val, p1->key->len); if (result != 0) { diff --git a/Zend/zend_highlight.c b/Zend/zend_highlight.c index 26c34686a6..79a552635f 100644 --- a/Zend/zend_highlight.c +++ b/Zend/zend_highlight.c @@ -54,7 +54,7 @@ ZEND_API void zend_html_putc(char c) } -ZEND_API void zend_html_puts(const char *s, uint len TSRMLS_DC) +ZEND_API void zend_html_puts(const char *s, size_t len TSRMLS_DC) { const unsigned char *ptr = (const unsigned char*)s, *end = ptr + len; unsigned char *filtered = NULL; diff --git a/Zend/zend_highlight.h b/Zend/zend_highlight.h index 1a35505135..3e91fd71f4 100644 --- a/Zend/zend_highlight.h +++ b/Zend/zend_highlight.h @@ -44,7 +44,7 @@ ZEND_API void zend_strip(TSRMLS_D); ZEND_API int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC); ZEND_API int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC); ZEND_API void zend_html_putc(char c); -ZEND_API void zend_html_puts(const char *s, uint len TSRMLS_DC); +ZEND_API void zend_html_puts(const char *s, size_t len TSRMLS_DC); END_EXTERN_C() extern zend_syntax_highlighter_ini syntax_highlighter_ini; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index e9897ed34e..6b4e8f1a97 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -268,12 +268,7 @@ static zend_always_inline int zend_verify_property_access(zend_property_info *pr case ZEND_ACC_PROTECTED: return zend_check_protected(property_info->ce, EG(scope)); case ZEND_ACC_PRIVATE: - if ((ce==EG(scope) || property_info->ce == EG(scope)) && EG(scope)) { - return 1; - } else { - return 0; - } - break; + return (ce == EG(scope) || property_info->ce == EG(scope)); } return 0; } @@ -295,9 +290,9 @@ static zend_always_inline zend_bool is_derived_class(zend_class_entry *child_cla static zend_always_inline zend_property_info *zend_get_property_info_quick(zend_class_entry *ce, zend_string *member, int silent, void **cache_slot TSRMLS_DC) /* {{{ */ { - zend_property_info *property_info; - zend_property_info *scope_property_info; - zend_bool denied_access = 0; + zval *zv; + zend_property_info *property_info = NULL; + uint32_t flags; if (cache_slot && EXPECTED(ce == CACHED_PTR_EX(cache_slot))) { return CACHED_PTR_EX(cache_slot + 1); @@ -313,60 +308,61 @@ static zend_always_inline zend_property_info *zend_get_property_info_quick(zend_ } return ZEND_WRONG_PROPERTY_INFO; } - property_info = zend_hash_find_ptr(&ce->properties_info, member); - if (property_info != NULL) { - if (UNEXPECTED((property_info->flags & ZEND_ACC_SHADOW) != 0)) { + + if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0)) { + goto exit_dynamic; + } + + zv = zend_hash_find(&ce->properties_info, member); + if (EXPECTED(zv != NULL)) { + property_info = (zend_property_info*)Z_PTR_P(zv); + flags = property_info->flags; + if (UNEXPECTED((flags & ZEND_ACC_SHADOW) != 0)) { /* if it's a shadow - go to access it's private */ property_info = NULL; } else { if (EXPECTED(zend_verify_property_access(property_info, ce TSRMLS_CC) != 0)) { - if (EXPECTED((property_info->flags & ZEND_ACC_CHANGED) != 0) - && EXPECTED(!(property_info->flags & ZEND_ACC_PRIVATE))) { - /* We still need to make sure that we're not in a context - * where the right property is a different 'statically linked' private - * continue checking below... - */ - } else { - if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) != 0) && !silent) { + if (UNEXPECTED(!(flags & ZEND_ACC_CHANGED)) + || UNEXPECTED((flags & ZEND_ACC_PRIVATE))) { + if (UNEXPECTED((flags & ZEND_ACC_STATIC) != 0) && !silent) { zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name->val, member->val); } - if (cache_slot) { - CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, property_info); - } - return property_info; + goto exit; } } else { /* Try to look in the scope instead */ - denied_access = 1; + property_info = ZEND_WRONG_PROPERTY_INFO; } } } + if (EG(scope) != ce && EG(scope) && is_derived_class(ce, EG(scope)) - && (scope_property_info = zend_hash_find_ptr(&EG(scope)->properties_info, member)) != NULL - && scope_property_info->flags & ZEND_ACC_PRIVATE) { + && (zv = zend_hash_find(&EG(scope)->properties_info, member)) != NULL + && ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE) { + property_info = (zend_property_info*)Z_PTR_P(zv); + goto exit; + } else if (UNEXPECTED(property_info == NULL)) { +exit_dynamic: if (cache_slot) { - CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, scope_property_info); + CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, NULL); } - return scope_property_info; - } else if (property_info) { - if (UNEXPECTED(denied_access != 0)) { - /* Information was available, but we were denied access. Error out. */ - if (!silent) { - zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name->val, member->val); - } - return ZEND_WRONG_PROPERTY_INFO; - } else { - /* fall through, return property_info... */ - if (cache_slot) { - CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, property_info); - } + return NULL; + } else if (UNEXPECTED(property_info == ZEND_WRONG_PROPERTY_INFO)) { + /* Information was available, but we were denied access. Error out. */ + if (!silent) { + zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(flags), ce->name->val, member->val); } - } else { if (cache_slot) { - CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, NULL); + CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, ZEND_WRONG_PROPERTY_INFO); } + return ZEND_WRONG_PROPERTY_INFO; + } + +exit: + if (cache_slot) { + CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, property_info); } return property_info; } @@ -462,12 +458,12 @@ zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_ EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0)) { retval = &zobj->properties_table[property_info->offset]; - if (Z_TYPE_P(retval) != IS_UNDEF) { + if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) { goto exit; } - } else if (UNEXPECTED(zobj->properties != NULL)) { + } else if (EXPECTED(zobj->properties != NULL)) { retval = zend_hash_find(zobj->properties, Z_STR_P(member)); - if (retval) goto exit; + if (EXPECTED(retval)) goto exit; } } @@ -831,7 +827,7 @@ static void zend_std_unset_property(zval *object, zval *member, void **cache_slo ZVAL_UNDEF(&zobj->properties_table[property_info->offset]); goto exit; } - } else if (zobj->properties && + } else if (EXPECTED(zobj->properties != NULL) && EXPECTED(zend_hash_del(zobj->properties, Z_STR_P(member)) != FAILURE)) { goto exit; } @@ -1427,7 +1423,7 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists, if (Z_TYPE_P(value) != IS_UNDEF) { goto found; } - } else if (UNEXPECTED(zobj->properties != NULL) && + } else if (EXPECTED(zobj->properties != NULL) && (value = zend_hash_find(zobj->properties, Z_STR_P(member))) != NULL) { found: switch (has_set_exists) { diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 40d37b3d36..58c034163e 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -144,7 +144,8 @@ ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object *o if (old_object->ce->default_properties_count) { for (i = 0; i < old_object->ce->default_properties_count; i++) { zval_ptr_dtor(&new_object->properties_table[i]); - ZVAL_COPY(&new_object->properties_table[i], &old_object->properties_table[i]); + ZVAL_COPY_VALUE(&new_object->properties_table[i], &old_object->properties_table[i]); + zval_add_ref(&new_object->properties_table[i]); } } if (old_object->properties) { diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index b0a0e7519e..03e913c31d 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -924,7 +924,7 @@ ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * } else if (Z_ISREF_P(op2)) { op2 = Z_REFVAL_P(op2); } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD); + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function); zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); @@ -977,7 +977,7 @@ ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * } else if (Z_ISREF_P(op2)) { op2 = Z_REFVAL_P(op2); } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB); + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB, sub_function); zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); @@ -1024,7 +1024,7 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * } else if (Z_ISREF_P(op2)) { op2 = Z_REFVAL_P(op2); } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL); + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL, mul_function); zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); @@ -1102,7 +1102,7 @@ ZEND_API int pow_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * } else if (Z_ISREF_P(op2)) { op2 = Z_REFVAL_P(op2); } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW); + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW, pow_function); if (Z_TYPE_P(op1) == IS_ARRAY) { ZVAL_LONG(result, 0); @@ -1183,7 +1183,7 @@ ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * } else if (Z_ISREF_P(op2)) { op2 = Z_REFVAL_P(op2); } else if (!converted) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV); + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function); zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); @@ -1202,14 +1202,14 @@ ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ * zval op1_copy, op2_copy; zend_long op1_lval; - if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MOD); - + if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_MOD, mod_function); zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); + } + op1_lval = Z_LVAL_P(op1); + if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_MOD); zendi_convert_to_long(op2, op2_copy, result); - } else { - op1_lval = Z_LVAL_P(op1); } if (Z_LVAL_P(op2) == 0) { @@ -1234,15 +1234,14 @@ ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) zval op1_copy, op2_copy; zend_long op1_lval; - if ((Z_TYPE_P(op1) != IS_FALSE && Z_TYPE_P(op1) != IS_TRUE) || - (Z_TYPE_P(op2) != IS_FALSE && Z_TYPE_P(op2) != IS_TRUE)) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_XOR); - + if (UNEXPECTED(Z_TYPE_P(op1) != IS_FALSE && Z_TYPE_P(op1) != IS_TRUE)) { + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BOOL_XOR, boolean_xor_function); zendi_convert_to_boolean(op1, op1_copy, result); - op1_lval = Z_TYPE_P(op1) == IS_TRUE; + } + op1_lval = Z_TYPE_P(op1) == IS_TRUE; + if (UNEXPECTED(Z_TYPE_P(op2) != IS_FALSE && Z_TYPE_P(op2) != IS_TRUE)) { + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BOOL_XOR); zendi_convert_to_boolean(op2, op2_copy, result); - } else { - op1_lval = Z_TYPE_P(op1) == IS_TRUE; } ZVAL_BOOL(result, op1_lval ^ (Z_TYPE_P(op2) == IS_TRUE)); @@ -1281,11 +1280,10 @@ ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */ return SUCCESS; case IS_STRING: { size_t i; - zval op1_copy = *op1; - ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN(op1_copy), 0)); - for (i = 0; i < Z_STRLEN(op1_copy); i++) { - Z_STRVAL_P(result)[i] = ~Z_STRVAL(op1_copy)[i]; + ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0)); + for (i = 0; i < Z_STRLEN_P(op1); i++) { + Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i]; } Z_STRVAL_P(result)[i] = 0; return SUCCESS; @@ -1329,14 +1327,14 @@ ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / return SUCCESS; } - if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_OR); - + if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR, bitwise_or_function); zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); + } + op1_lval = Z_LVAL_P(op1); + if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR); zendi_convert_to_long(op2, op2_copy, result); - } else { - op1_lval = Z_LVAL_P(op1); } ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2)); @@ -1374,14 +1372,14 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) return SUCCESS; } - if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_AND); - + if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND, bitwise_and_function); zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); + } + op1_lval = Z_LVAL_P(op1); + if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND); zendi_convert_to_long(op2, op2_copy, result); - } else { - op1_lval = Z_LVAL_P(op1); } ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2)); @@ -1419,14 +1417,14 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) return SUCCESS; } - if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_XOR); - + if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR, bitwise_xor_function); zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); + } + op1_lval = Z_LVAL_P(op1); + if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR); zendi_convert_to_long(op2, op2_copy, result); - } else { - op1_lval = Z_LVAL_P(op1); } ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2)); @@ -1439,14 +1437,14 @@ ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) / zval op1_copy, op2_copy; zend_long op1_lval; - if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SL); - + if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_SL, shift_left_function); zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); + } + op1_lval = Z_LVAL_P(op1); + if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_SL); zendi_convert_to_long(op2, op2_copy, result); - } else { - op1_lval = Z_LVAL_P(op1); } /* prevent wrapping quirkiness on some processors where << 64 + x == << x */ @@ -1471,14 +1469,14 @@ ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) zval op1_copy, op2_copy; zend_long op1_lval; - if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SR); - + if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_SR, shift_right_function); zendi_convert_to_long(op1, op1_copy, result); - op1_lval = Z_LVAL_P(op1); + } + op1_lval = Z_LVAL_P(op1); + if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_SR); zendi_convert_to_long(op2, op2_copy, result); - } else { - op1_lval = Z_LVAL_P(op1); } /* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */ @@ -1530,29 +1528,28 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{ zval op1_copy, op2_copy; int use_copy1 = 0, use_copy2 = 0; - if (UNEXPECTED(Z_TYPE_P(op1) != IS_STRING) || - UNEXPECTED(Z_TYPE_P(op2) != IS_STRING)) { - ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT); - - if (Z_TYPE_P(op1) != IS_STRING) { - use_copy1 = zend_make_printable_zval(op1, &op1_copy TSRMLS_CC); - } - if (Z_TYPE_P(op2) != IS_STRING) { - use_copy2 = zend_make_printable_zval(op2, &op2_copy TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(op1) != IS_STRING)) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT, concat_function); + use_copy1 = zend_make_printable_zval(op1, &op1_copy TSRMLS_CC); + if (use_copy1) { + /* We have created a converted copy of op1. Therefore, op1 won't become the result so + * we have to free it. + */ + if (result == op1) { + zval_dtor(op1); + if (UNEXPECTED(op1 == op2)) { + op2 = &op1_copy; + } + } + op1 = &op1_copy; } } - - if (use_copy1) { - /* We have created a converted copy of op1. Therefore, op1 won't become the result so - * we have to free it. - */ - if (result == op1) { - zval_dtor(op1); + if (UNEXPECTED(Z_TYPE_P(op2) != IS_STRING)) { + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT); + use_copy2 = zend_make_printable_zval(op2, &op2_copy TSRMLS_CC); + if (use_copy2) { + op2 = &op2_copy; } - op1 = &op1_copy; - } - if (use_copy2) { - op2 = &op2_copy; } { diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 8075edf939..f95e856e68 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -887,22 +887,43 @@ static zend_always_inline void fast_is_not_identical_function(zval *result, zval ZVAL_BOOL(result, Z_TYPE_P(result) != IS_TRUE); } -#define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode) \ - if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)) { \ - if (SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { \ - return SUCCESS; \ - } \ - } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, do_operation)) { \ - if (SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { \ - return SUCCESS; \ - } \ +#define ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode, binary_op) \ + if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT) \ + && op1 == result \ + && UNEXPECTED(Z_OBJ_HANDLER_P(op1, get)) \ + && EXPECTED(Z_OBJ_HANDLER_P(op1, set))) { \ + int ret; \ + zval rv; \ + zval *objval = Z_OBJ_HANDLER_P(op1, get)(op1, &rv TSRMLS_CC); \ + Z_ADDREF_P(objval); \ + ret = binary_op(objval, objval, op2 TSRMLS_CC); \ + Z_OBJ_HANDLER_P(op1, set)(op1, objval TSRMLS_CC); \ + zval_ptr_dtor(objval); \ + return ret; \ + } else if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT) \ + && UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation))) { \ + if (EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC))) { \ + return SUCCESS; \ + } \ } -#define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode) \ - if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation) \ - && SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, NULL TSRMLS_CC) \ - ) { \ - return SUCCESS; \ +#define ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode) \ + if (UNEXPECTED(Z_TYPE_P(op2) == IS_OBJECT) \ + && UNEXPECTED(Z_OBJ_HANDLER_P(op2, do_operation)) \ + && EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC))) { \ + return SUCCESS; \ + } + +#define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode, binary_op) \ + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode, binary_op) \ + else \ + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode) + +#define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode) \ + if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT) \ + && UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation)) \ + && EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, NULL TSRMLS_CC))) { \ + return SUCCESS; \ } /* buf points to the END of the buffer */ diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c index 3e68a38487..aae8465791 100644 --- a/Zend/zend_variables.c +++ b/Zend/zend_variables.c @@ -221,7 +221,7 @@ ZEND_API void zval_add_ref_unref(zval *p) { if (Z_REFCOUNTED_P(p)) { if (Z_ISREF_P(p)) { - ZVAL_DUP(p, Z_REFVAL_P(p)); + ZVAL_COPY(p, Z_REFVAL_P(p)); } else { Z_ADDREF_P(p); } @@ -266,7 +266,7 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC) } -ZEND_API int zend_print_variable(zval *var TSRMLS_DC) +ZEND_API size_t zend_print_variable(zval *var TSRMLS_DC) { return zend_print_zval(var, 0 TSRMLS_CC); } diff --git a/Zend/zend_variables.h b/Zend/zend_variables.h index 94ae438e9d..4f840bdd8a 100644 --- a/Zend/zend_variables.h +++ b/Zend/zend_variables.h @@ -93,7 +93,7 @@ static zend_always_inline void _zval_opt_copy_ctor_no_imm(zval *zvalue ZEND_FILE ZEND_API int zval_copy_static_var(zval *p TSRMLS_DC, int num_args, va_list args, zend_hash_key *key); -ZEND_API int zend_print_variable(zval *var TSRMLS_DC); +ZEND_API size_t zend_print_variable(zval *var TSRMLS_DC); ZEND_API void _zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC); ZEND_API void _zval_internal_dtor_for_ptr(zval *zvalue ZEND_FILE_LINE_DC); ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC); diff --git a/Zend/zend_virtual_cwd.c b/Zend/zend_virtual_cwd.c index 01a91cad80..a596b7ca06 100644 --- a/Zend/zend_virtual_cwd.c +++ b/Zend/zend_virtual_cwd.c @@ -380,7 +380,7 @@ CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat) /* {{ } if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { - int len = strlen(path); + size_t len = strlen(path); if (path[len-4] == '.') { if (_memicmp(path+len-3, "exe", 3) == 0 || @@ -467,7 +467,7 @@ CWD_API void virtual_cwd_startup(void) /* {{{ */ cwd[0] = '\0'; } - main_cwd_state.cwd_length = strlen(cwd); + main_cwd_state.cwd_length = (int)strlen(cwd); #ifdef TSRM_WIN32 if (main_cwd_state.cwd_length >= 2 && cwd[1] == ':') { cwd[0] = toupper(cwd[0]); @@ -1146,7 +1146,7 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i return -1; } if (save) { - i = strlen(data.cFileName); + i = (int)strlen(data.cFileName); memcpy(path+j, data.cFileName, i+1); j += i; } else { @@ -1180,7 +1180,7 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i /* returns 0 for ok, 1 for error */ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func verify_path, int use_realpath TSRMLS_DC) /* {{{ */ { - int path_length = strlen(path); + int path_length = (int)strlen(path); char resolved_path[MAXPATHLEN]; int start = 1; int ll = 0; @@ -1394,7 +1394,7 @@ CWD_API int virtual_chdir(const char *path TSRMLS_DC) /* {{{ */ CWD_API int virtual_chdir_file(const char *path, int (*p_chdir)(const char *path TSRMLS_DC) TSRMLS_DC) /* {{{ */ { - int length = strlen(path); + size_t length = strlen(path); char *temp; int retval; ALLOCA_FLAG(use_heap) @@ -1972,7 +1972,7 @@ CWD_API char *tsrm_realpath(const char *path, char *real_path TSRMLS_DC) /* {{{ } else if (!IS_ABSOLUTE_PATH(path, strlen(path)) && VCWD_GETCWD(cwd, MAXPATHLEN)) { new_state.cwd = estrdup(cwd); - new_state.cwd_length = strlen(cwd); + new_state.cwd_length = (int)strlen(cwd); } else { new_state.cwd = (char*)emalloc(1); if (new_state.cwd == NULL) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index fad4d5b99c..72fbf7fbb4 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -333,7 +333,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR zval *object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); zval *property = GET_OP2_ZVAL_PTR(BP_VAR_R); zval *value; - int have_get_ptr = 0; + zval *zptr; if (OP1_TYPE == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -356,21 +356,17 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { + + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -427,15 +423,19 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC)) { USE_OPLINE - zend_free_op free_op1, free_op2, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op1, free_op2, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (OP1_TYPE == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (OP1_TYPE != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (OP1_TYPE == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (OP1_TYPE == IS_VAR && !OP1_FREE) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -443,9 +443,10 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMP|VAR } else { zval *dim = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, OP2_TYPE TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, OP2_TYPE TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -456,33 +457,19 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMP|VAR if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - ZEND_VM_C_GOTO(assign_op_dim_exit); - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -ZEND_VM_C_LABEL(assign_op_dim_exit): FREE_OP2(); FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); FREE_OP1_VAR_PTR(); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -508,30 +495,17 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - ZEND_VM_C_GOTO(assign_op_exit); - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -ZEND_VM_C_LABEL(assign_op_exit): FREE_OP2(); FREE_OP1_VAR_PTR(); CHECK_EXCEPTION(); @@ -688,7 +662,7 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR| zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); @@ -716,21 +690,17 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR| /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -783,7 +753,7 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); @@ -809,19 +779,15 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -1161,9 +1127,6 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMP|VAR|CV, UNUSED|CONST| } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -1233,11 +1196,8 @@ ZEND_VM_HANDLER(84, ZEND_FETCH_DIM_W, VAR|CV, CONST|TMP|VAR|UNUSED|CV) if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -1259,6 +1219,7 @@ ZEND_VM_HANDLER(87, ZEND_FETCH_DIM_RW, VAR|CV, CONST|TMP|VAR|UNUSED|CV) if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -1300,6 +1261,7 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMP|VAR|UNU if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -1331,6 +1293,7 @@ ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMP|VAR|CV) if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -1389,7 +1352,7 @@ ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|CV, CONST|TMP|VAR|CV) zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -1413,7 +1376,7 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|CV, CONST|TMP|VAR|CV) if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -1475,7 +1438,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|CV, CONST|TMP| if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -1501,7 +1464,7 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|CV, CONST|TMP|VAR|CV) if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, OP1_TYPE, property, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -1579,29 +1542,33 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV) if (OP1_TYPE == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zend_free_op free_op2; zval *property_name = GET_OP2_ZVAL_PTR(BP_VAR_R); zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, OP1_TYPE, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); FREE_OP2(); } else { - zend_free_op free_op2, free_op_data1, free_op_data2; + zend_free_op free_op2, free_op_data1; + zval rv; zval *value; zval *dim = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, OP2_TYPE TSRMLS_CC); - FREE_OP2(); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); + FREE_OP2(); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, OP2_TYPE TSRMLS_CC); + FREE_OP2(); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -1615,7 +1582,6 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV) if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -1669,10 +1635,13 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) SAVE_OPLINE(); value_ptr = GET_OP2_ZVAL_PTR_PTR(BP_VAR_W); + if (OP2_TYPE == IS_VAR && UNEXPECTED(value_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (OP2_TYPE == IS_VAR && - opline->extended_value == ZEND_RETURNS_FUNCTION && - !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF) && - !Z_ISREF_P(value_ptr)) { + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { if (!OP2_FREE) { PZVAL_LOCK(value_ptr); /* undo the effect of get_zval_ptr_ptr() */ } @@ -1689,15 +1658,14 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) } variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); + if (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT) && UNEXPECTED(!Z_ISREF_P(variable_ptr))) { zend_error_noreturn(E_ERROR, "Cannot assign by reference to overloaded object"); } - if ((OP2_TYPE == IS_VAR && UNEXPECTED(value_ptr == NULL)) || - (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == NULL))) { - zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); - } if ((OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) || (OP2_TYPE == IS_VAR && UNEXPECTED(value_ptr == &EG(error_zval)))) { variable_ptr = &EG(uninitialized_zval); @@ -2101,7 +2069,7 @@ ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, ANY, CONST|TMP|VAR|UNUSED|CV) if (CACHED_PTR(Z_CACHE_SLOT_P(class_name))) { Z_CE_P(EX_VAR(opline->result.var)) = CACHED_PTR(Z_CACHE_SLOT_P(class_name)); } else { - Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, opline->extended_value TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, 0 TSRMLS_CC); CACHE_PTR(Z_CACHE_SLOT_P(class_name), Z_CE_P(EX_VAR(opline->result.var))); } } else if (Z_TYPE_P(class_name) == IS_OBJECT) { @@ -2662,7 +2630,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) zval *p = ZEND_CALL_ARG(call, 1); for (i = 0; i < call->num_args; ++i) { - zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); + zend_verify_arg_type(fbc, i + 1, p TSRMLS_CC); p++; } if (UNEXPECTED(EG(exception) != NULL)) { @@ -2862,10 +2830,10 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY) zend_error_noreturn(E_ERROR, "Cannot return string offsets by reference"); } - if (OP1_TYPE == IS_VAR && !Z_ISREF_P(retval_ptr)) { - if (opline->extended_value == ZEND_RETURNS_FUNCTION && - (Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF)) { - } else { + if (OP1_TYPE == IS_VAR) { + if (retval_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF))) { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { ZVAL_NEW_REF(EX(return_value), retval_ptr); @@ -3521,7 +3489,7 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); CHECK_EXCEPTION(); } @@ -3549,7 +3517,7 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) } if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); } CHECK_EXCEPTION(); @@ -3574,7 +3542,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY) param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { - zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); param++; @@ -3667,23 +3635,38 @@ ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) +ZEND_VM_HANDLER(68, ZEND_NEW, CONST|VAR, ANY) { USE_OPLINE zval object_zval; zend_function *constructor; + zend_class_entry *ce; SAVE_OPLINE(); - if (UNEXPECTED((Z_CE_P(EX_VAR(opline->op1.var))->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) != 0)) { - if (Z_CE_P(EX_VAR(opline->op1.var))->ce_flags & ZEND_ACC_INTERFACE) { - zend_error_noreturn(E_ERROR, "Cannot instantiate interface %s", Z_CE_P(EX_VAR(opline->op1.var))->name->val); - } else if ((Z_CE_P(EX_VAR(opline->op1.var))->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { - zend_error_noreturn(E_ERROR, "Cannot instantiate trait %s", Z_CE_P(EX_VAR(opline->op1.var))->name->val); + if (OP1_TYPE == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - zend_error_noreturn(E_ERROR, "Cannot instantiate abstract class %s", Z_CE_P(EX_VAR(opline->op1.var))->name->val); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, 0 TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); } - object_init_ex(&object_zval, Z_CE_P(EX_VAR(opline->op1.var))); + if (UNEXPECTED((ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) != 0)) { + if (ce->ce_flags & ZEND_ACC_INTERFACE) { + zend_error_noreturn(E_ERROR, "Cannot instantiate interface %s", ce->name->val); + } else if ((ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { + zend_error_noreturn(E_ERROR, "Cannot instantiate trait %s", ce->name->val); + } else { + zend_error_noreturn(E_ERROR, "Cannot instantiate abstract class %s", ce->name->val); + } + } + object_init_ex(&object_zval, ce); constructor = Z_OBJ_HT(object_zval)->get_constructor(Z_OBJ(object_zval) TSRMLS_CC); if (constructor == NULL) { @@ -3702,7 +3685,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED)), constructor, opline->extended_value, - Z_CE_P(EX_VAR(opline->op1.var)), + ce, Z_OBJ(object_zval), EX(call) TSRMLS_CC); @@ -3829,7 +3812,7 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST) } else if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -5321,7 +5304,7 @@ ZEND_VM_HANDLER(105, ZEND_TICKS, ANY, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(138, ZEND_INSTANCEOF, TMP|VAR|CV, ANY) +ZEND_VM_HANDLER(138, ZEND_INSTANCEOF, TMP|VAR|CV, CONST|VAR) { USE_OPLINE zend_free_op free_op1; @@ -5332,7 +5315,25 @@ ZEND_VM_HANDLER(138, ZEND_INSTANCEOF, TMP|VAR|CV, ANY) expr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); if (Z_TYPE_P(expr) == IS_OBJECT) { - result = instanceof_function(Z_OBJCE_P(expr), Z_CE_P(EX_VAR(opline->op2.var)) TSRMLS_CC); + zend_class_entry *ce; + + if (OP2_TYPE == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + FREE_OP1(); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op2.var)); + } + result = instanceof_function(Z_OBJCE_P(expr), ce TSRMLS_CC); } else { result = 0; } @@ -5362,7 +5363,7 @@ ZEND_VM_HANDLER(144, ZEND_ADD_INTERFACE, ANY, CONST) if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { iface = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else { - iface = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, opline->extended_value TSRMLS_CC); + iface = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, ZEND_FETCH_CLASS_INTERFACE TSRMLS_CC); if (UNEXPECTED(iface == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5391,7 +5392,7 @@ ZEND_VM_HANDLER(154, ZEND_ADD_TRAIT, ANY, ANY) } else { trait = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, - opline->extended_value TSRMLS_CC); + ZEND_FETCH_CLASS_TRAIT TSRMLS_CC); if (UNEXPECTED(trait == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5686,9 +5687,10 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (OP1_TYPE == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (OP1_TYPE == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4b58d95618..94466c581b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -538,7 +538,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *p = ZEND_CALL_ARG(call, 1); for (i = 0; i < call->num_args; ++i) { - zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); + zend_verify_arg_type(fbc, i + 1, p TSRMLS_CC); p++; } if (UNEXPECTED(EG(exception) != NULL)) { @@ -978,7 +978,7 @@ static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); CHECK_EXCEPTION(); } @@ -1003,7 +1003,7 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { - zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); param++; @@ -1023,57 +1023,6 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval object_zval; - zend_function *constructor; - - SAVE_OPLINE(); - if (UNEXPECTED((Z_CE_P(EX_VAR(opline->op1.var))->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) != 0)) { - if (Z_CE_P(EX_VAR(opline->op1.var))->ce_flags & ZEND_ACC_INTERFACE) { - zend_error_noreturn(E_ERROR, "Cannot instantiate interface %s", Z_CE_P(EX_VAR(opline->op1.var))->name->val); - } else if ((Z_CE_P(EX_VAR(opline->op1.var))->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { - zend_error_noreturn(E_ERROR, "Cannot instantiate trait %s", Z_CE_P(EX_VAR(opline->op1.var))->name->val); - } else { - zend_error_noreturn(E_ERROR, "Cannot instantiate abstract class %s", Z_CE_P(EX_VAR(opline->op1.var))->name->val); - } - } - object_init_ex(&object_zval, Z_CE_P(EX_VAR(opline->op1.var))); - constructor = Z_OBJ_HT(object_zval)->get_constructor(Z_OBJ(object_zval) TSRMLS_CC); - - if (constructor == NULL) { - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY_VALUE(EX_VAR(opline->result.var), &object_zval); - } else { - zval_ptr_dtor(&object_zval); - } - ZEND_VM_JMP(opline->op2.jmp_addr); - } else { - /* We are not handling overloaded classes right now */ - EX(call) = zend_vm_stack_push_call_frame( - VM_FRAME_INFO( - VM_FRAME_NESTED_FUNCTION, - RETURN_VALUE_USED(opline) ? - ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED)), - constructor, - opline->extended_value, - Z_CE_P(EX_VAR(opline->op1.var)), - Z_OBJ(object_zval), - EX(call) TSRMLS_CC); - - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); - EX(call)->return_value = EX_VAR(opline->result.var); - } else { - EX(call)->return_value = NULL; - } - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); - } -} - static int ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -1225,7 +1174,7 @@ static int ZEND_FASTCALL ZEND_ADD_TRAIT_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { trait = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, - opline->extended_value TSRMLS_CC); + ZEND_FETCH_CLASS_TRAIT TSRMLS_CC); if (UNEXPECTED(trait == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1474,7 +1423,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE if (CACHED_PTR(Z_CACHE_SLOT_P(class_name))) { Z_CE_P(EX_VAR(opline->result.var)) = CACHED_PTR(Z_CACHE_SLOT_P(class_name)); } else { - Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, opline->extended_value TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, 0 TSRMLS_CC); CACHE_PTR(Z_CACHE_SLOT_P(class_name), Z_CE_P(EX_VAR(opline->result.var))); } } else if (Z_TYPE_P(class_name) == IS_OBJECT) { @@ -1713,7 +1662,7 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ } if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); } CHECK_EXCEPTION(); @@ -1772,7 +1721,7 @@ static int ZEND_FASTCALL ZEND_ADD_INTERFACE_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { iface = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else { - iface = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, opline->extended_value TSRMLS_CC); + iface = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, ZEND_FETCH_CLASS_INTERFACE TSRMLS_CC); if (UNEXPECTED(iface == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1809,7 +1758,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ if (CACHED_PTR(Z_CACHE_SLOT_P(class_name))) { Z_CE_P(EX_VAR(opline->result.var)) = CACHED_PTR(Z_CACHE_SLOT_P(class_name)); } else { - Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, opline->extended_value TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, 0 TSRMLS_CC); CACHE_PTR(Z_CACHE_SLOT_P(class_name), Z_CE_P(EX_VAR(opline->result.var))); } } else if (Z_TYPE_P(class_name) == IS_OBJECT) { @@ -1995,7 +1944,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ if (CACHED_PTR(Z_CACHE_SLOT_P(class_name))) { Z_CE_P(EX_VAR(opline->result.var)) = CACHED_PTR(Z_CACHE_SLOT_P(class_name)); } else { - Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, opline->extended_value TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, 0 TSRMLS_CC); CACHE_PTR(Z_CACHE_SLOT_P(class_name), Z_CE_P(EX_VAR(opline->result.var))); } } else if (Z_TYPE_P(class_name) == IS_OBJECT) { @@ -2181,7 +2130,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDL if (CACHED_PTR(Z_CACHE_SLOT_P(class_name))) { Z_CE_P(EX_VAR(opline->result.var)) = CACHED_PTR(Z_CACHE_SLOT_P(class_name)); } else { - Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, opline->extended_value TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, 0 TSRMLS_CC); CACHE_PTR(Z_CACHE_SLOT_P(class_name), Z_CE_P(EX_VAR(opline->result.var))); } } else if (Z_TYPE_P(class_name) == IS_OBJECT) { @@ -2220,7 +2169,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A if (CACHED_PTR(Z_CACHE_SLOT_P(class_name))) { Z_CE_P(EX_VAR(opline->result.var)) = CACHED_PTR(Z_CACHE_SLOT_P(class_name)); } else { - Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, opline->extended_value TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = zend_fetch_class_by_name(Z_STR_P(class_name), opline->op2.zv + 1, 0 TSRMLS_CC); CACHE_PTR(Z_CACHE_SLOT_P(class_name), Z_CE_P(EX_VAR(opline->result.var))); } } else if (Z_TYPE_P(class_name) == IS_OBJECT) { @@ -2662,10 +2611,10 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND zend_error_noreturn(E_ERROR, "Cannot return string offsets by reference"); } - if (IS_CONST == IS_VAR && !Z_ISREF_P(retval_ptr)) { - if (opline->extended_value == ZEND_RETURNS_FUNCTION && - (Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF)) { - } else { + if (IS_CONST == IS_VAR) { + if (retval_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF))) { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { ZVAL_NEW_REF(EX(return_value), retval_ptr); @@ -2769,6 +2718,72 @@ static int ZEND_FASTCALL ZEND_BOOL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_NEW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval object_zval; + zend_function *constructor; + zend_class_entry *ce; + + SAVE_OPLINE(); + if (IS_CONST == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, 0 TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); + } + if (UNEXPECTED((ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) != 0)) { + if (ce->ce_flags & ZEND_ACC_INTERFACE) { + zend_error_noreturn(E_ERROR, "Cannot instantiate interface %s", ce->name->val); + } else if ((ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { + zend_error_noreturn(E_ERROR, "Cannot instantiate trait %s", ce->name->val); + } else { + zend_error_noreturn(E_ERROR, "Cannot instantiate abstract class %s", ce->name->val); + } + } + object_init_ex(&object_zval, ce); + constructor = Z_OBJ_HT(object_zval)->get_constructor(Z_OBJ(object_zval) TSRMLS_CC); + + if (constructor == NULL) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY_VALUE(EX_VAR(opline->result.var), &object_zval); + } else { + zval_ptr_dtor(&object_zval); + } + ZEND_VM_JMP(opline->op2.jmp_addr); + } else { + /* We are not handling overloaded classes right now */ + EX(call) = zend_vm_stack_push_call_frame( + VM_FRAME_INFO( + VM_FRAME_NESTED_FUNCTION, + RETURN_VALUE_USED(opline) ? + ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED)), + constructor, + opline->extended_value, + ce, + Z_OBJ(object_zval), + EX(call) TSRMLS_CC); + + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); + EX(call)->return_value = EX_VAR(opline->result.var); + } else { + EX(call)->return_value = NULL; + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } +} + static int ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -3840,9 +3855,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_CONST(int type } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -3931,6 +3943,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_CONST_HANDLER(ZEND_ if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_CONST == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -4033,7 +4046,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CONST_HANDLER(ZEND_ if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CONST, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CONST, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_CONST == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -4324,7 +4337,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO } else if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -4855,9 +4868,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CONST == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CONST == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -5275,6 +5289,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_TMP_HANDLER(ZEND_OP if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); if (IS_CONST == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -5379,7 +5394,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_TMP_HANDLER(ZEND_OP if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CONST, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CONST, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CONST == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -5898,9 +5913,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CONST == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CONST == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -6378,9 +6394,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_VAR(int type, } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -6469,6 +6482,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_VAR_HANDLER(ZEND_OP if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); if (IS_CONST == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -6573,7 +6587,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_VAR_HANDLER(ZEND_OP if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CONST, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CONST, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CONST == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -7237,9 +7251,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CONST == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CONST == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -7442,9 +7457,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_UNUSED(int typ } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -7503,6 +7515,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER(ZEND if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); if (IS_CONST == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -7981,9 +7994,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CONST == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CONST == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -8386,6 +8400,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_CV_HANDLER(ZEND_OPC if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_CONST == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -8488,7 +8503,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CV_HANDLER(ZEND_OPC if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CONST, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CONST, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_CONST == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -9056,9 +9071,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CONST == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CONST == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -9444,10 +9460,10 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLE zend_error_noreturn(E_ERROR, "Cannot return string offsets by reference"); } - if (IS_TMP_VAR == IS_VAR && !Z_ISREF_P(retval_ptr)) { - if (opline->extended_value == ZEND_RETURNS_FUNCTION && - (Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF)) { - } else { + if (IS_TMP_VAR == IS_VAR) { + if (retval_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF))) { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { ZVAL_NEW_REF(EX(return_value), retval_ptr); @@ -10154,27 +10170,6 @@ static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1; - zval *expr; - zend_bool result; - - SAVE_OPLINE(); - expr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - - if (Z_TYPE_P(expr) == IS_OBJECT) { - result = instanceof_function(Z_OBJCE_P(expr), Z_CE_P(EX_VAR(opline->op2.var)) TSRMLS_CC); - } else { - result = 0; - } - ZVAL_BOOL(EX_VAR(opline->result.var), result); - zval_ptr_dtor_nogc(free_op1.var); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_FASTCALL ZEND_STRLEN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -10643,9 +10638,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMP_CONST(int type, } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -10734,6 +10726,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CONST_HANDLER(ZEND_OP if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_TMP_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -10836,7 +10829,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CONST_HANDLER(ZEND_OP if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_TMP_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_TMP_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_TMP_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -11451,6 +11444,45 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_CONST_HANDLER(ZEN ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *expr; + zend_bool result; + + SAVE_OPLINE(); + expr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + + if (Z_TYPE_P(expr) == IS_OBJECT) { + zend_class_entry *ce; + + if (IS_CONST == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op2.var)); + } + result = instanceof_function(Z_OBJCE_P(expr), ce TSRMLS_CC); + } else { + result = 0; + } + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_ptr_dtor_nogc(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -11497,9 +11529,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_TMP_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_TMP_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -11917,6 +11950,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_TMP_HANDLER(ZEND_OPCO if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); if (IS_TMP_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -12021,7 +12055,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_TMP_HANDLER(ZEND_OPCO if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_TMP_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_TMP_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_TMP_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -12513,9 +12547,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_TMP_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_TMP_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -12993,9 +13028,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMP_VAR(int type, ZE } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -13084,6 +13116,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_VAR_HANDLER(ZEND_OPCO if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); if (IS_TMP_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -13188,7 +13221,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_VAR_HANDLER(ZEND_OPCO if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_TMP_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_TMP_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_TMP_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -13780,6 +13813,45 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_VAR_HANDLER(ZEND_ ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *expr; + zend_bool result; + + SAVE_OPLINE(); + expr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + + if (Z_TYPE_P(expr) == IS_OBJECT) { + zend_class_entry *ce; + + if (IS_VAR == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op2.var)); + } + result = instanceof_function(Z_OBJCE_P(expr), ce TSRMLS_CC); + } else { + result = 0; + } + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_ptr_dtor_nogc(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -13826,9 +13898,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_TMP_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_TMP_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -14031,9 +14104,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMP_UNUSED(int type, } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -14092,6 +14162,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_UNUSED_HANDLER(ZEND_O if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); if (IS_TMP_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -14422,9 +14493,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_TMP_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_TMP_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -14827,6 +14899,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CV_HANDLER(ZEND_OPCOD if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_TMP_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -14929,7 +15002,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CV_HANDLER(ZEND_OPCOD if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_TMP_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_TMP_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_TMP_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -15416,9 +15489,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_TMP_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_TMP_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -15970,10 +16044,10 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLE zend_error_noreturn(E_ERROR, "Cannot return string offsets by reference"); } - if (IS_VAR == IS_VAR && !Z_ISREF_P(retval_ptr)) { - if (opline->extended_value == ZEND_RETURNS_FUNCTION && - (Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF)) { - } else { + if (IS_VAR == IS_VAR) { + if (retval_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF))) { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { ZVAL_NEW_REF(EX(return_value), retval_ptr); @@ -16243,6 +16317,72 @@ static int ZEND_FASTCALL ZEND_BOOL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_NEW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval object_zval; + zend_function *constructor; + zend_class_entry *ce; + + SAVE_OPLINE(); + if (IS_VAR == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, 0 TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op1.var)); + } + if (UNEXPECTED((ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) != 0)) { + if (ce->ce_flags & ZEND_ACC_INTERFACE) { + zend_error_noreturn(E_ERROR, "Cannot instantiate interface %s", ce->name->val); + } else if ((ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { + zend_error_noreturn(E_ERROR, "Cannot instantiate trait %s", ce->name->val); + } else { + zend_error_noreturn(E_ERROR, "Cannot instantiate abstract class %s", ce->name->val); + } + } + object_init_ex(&object_zval, ce); + constructor = Z_OBJ_HT(object_zval)->get_constructor(Z_OBJ(object_zval) TSRMLS_CC); + + if (constructor == NULL) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY_VALUE(EX_VAR(opline->result.var), &object_zval); + } else { + zval_ptr_dtor(&object_zval); + } + ZEND_VM_JMP(opline->op2.jmp_addr); + } else { + /* We are not handling overloaded classes right now */ + EX(call) = zend_vm_stack_push_call_frame( + VM_FRAME_INFO( + VM_FRAME_NESTED_FUNCTION, + RETURN_VALUE_USED(opline) ? + ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED)), + constructor, + opline->extended_value, + ce, + Z_OBJ(object_zval), + EX(call) TSRMLS_CC); + + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); + EX(call)->return_value = EX_VAR(opline->result.var); + } else { + EX(call)->return_value = NULL; + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } +} + static int ZEND_FASTCALL ZEND_CLONE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -17082,27 +17222,6 @@ static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1; - zval *expr; - zend_bool result; - - SAVE_OPLINE(); - expr = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - - if (Z_TYPE_P(expr) == IS_OBJECT) { - result = instanceof_function(Z_OBJCE_P(expr), Z_CE_P(EX_VAR(opline->op2.var)) TSRMLS_CC); - } else { - result = 0; - } - ZVAL_BOOL(EX_VAR(opline->result.var), result); - zval_ptr_dtor_nogc(free_op1.var); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_FASTCALL ZEND_STRLEN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -17472,7 +17591,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b zval *object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); zval *property = opline->op2.zv; zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_VAR == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -17495,21 +17614,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { + + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -17565,15 +17680,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op1, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op1, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_VAR != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -17581,9 +17700,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(int (*b } else { zval *dim = opline->op2.zv; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CONST TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CONST TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -17594,33 +17714,18 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(int (*b if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -17646,31 +17751,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CONST(int (*binar if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -17826,7 +17917,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CONST(incdec_t zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -17854,21 +17945,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CONST(incdec_t /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -17920,7 +18007,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_CONST(incdec_ zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -17946,19 +18033,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_CONST(incdec_ /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -18107,9 +18190,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_CONST(int type, } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -18179,11 +18259,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HA if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -18205,6 +18282,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_H if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -18246,6 +18324,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -18277,6 +18356,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_CONST_HANDLER(ZEND_OPCOD if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -18334,7 +18414,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HA zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -18358,7 +18438,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_H if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -18419,7 +18499,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -18445,7 +18525,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CONST_HANDLER(ZEND_OPCOD if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -18523,29 +18603,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HAN if (IS_VAR == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zval *property_name = opline->op2.zv; zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_VAR, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); } else { - zend_free_op free_op_data1, free_op_data2; + zend_free_op free_op_data1; + zval rv; zval *value; zval *dim = opline->op2.zv; zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CONST TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_CONST TSRMLS_CC); + + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -18559,7 +18643,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HAN if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -18902,7 +18985,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE } else if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -19468,6 +19551,45 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_VAR_CONST_HANDLER(ZEN ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *expr; + zend_bool result; + + SAVE_OPLINE(); + expr = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + + if (Z_TYPE_P(expr) == IS_OBJECT) { + zend_class_entry *ce; + + if (IS_CONST == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op2.var)); + } + result = instanceof_function(Z_OBJCE_P(expr), ce TSRMLS_CC); + } else { + result = 0; + } + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_ptr_dtor_nogc(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -19514,9 +19636,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -19901,7 +20024,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(int (*bin zval *object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); zval *property = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_VAR == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -19924,21 +20047,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(int (*bin } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { + + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -19995,15 +20114,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(int (*bin static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op1, free_op2, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op1, free_op2, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_VAR != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -20011,9 +20134,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(int (*bin } else { zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_TMP_VAR TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_TMP_VAR TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -20024,33 +20148,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_TMP(int (*bin if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: zval_ptr_dtor_nogc(free_op2.var); FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -20076,30 +20186,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_TMP(int (*binary_ if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: zval_ptr_dtor_nogc(free_op2.var); if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); @@ -20256,7 +20353,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_TMP(incdec_t i zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -20284,21 +20381,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_TMP(incdec_t i /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -20351,7 +20444,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_TMP(incdec_t zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -20377,19 +20470,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_TMP(incdec_t /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -20460,11 +20549,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HAND if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -20486,6 +20572,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HAN if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -20527,6 +20614,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -20558,6 +20646,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_ if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -20616,7 +20705,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HAND zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -20640,7 +20729,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HAN if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -20702,7 +20791,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -20728,7 +20817,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_ if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -20773,29 +20862,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDL if (IS_VAR == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zend_free_op free_op2; zval *property_name = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_VAR, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); } else { - zend_free_op free_op2, free_op_data1, free_op_data2; + zend_free_op free_op2, free_op_data1; + zval rv; zval *value; zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_TMP_VAR TSRMLS_CC); - zval_ptr_dtor_nogc(free_op2.var); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_TMP_VAR TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -20809,7 +20902,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDL if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -21526,9 +21618,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -21913,7 +22006,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(int (*bin zval *object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); zval *property = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_VAR == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -21936,21 +22029,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(int (*bin } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { + + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -22007,15 +22096,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(int (*bin static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op1, free_op2, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op1, free_op2, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_VAR != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -22023,9 +22116,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(int (*bin } else { zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_VAR TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_VAR TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -22036,33 +22130,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_VAR(int (*bin if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: zval_ptr_dtor_nogc(free_op2.var); FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -22088,30 +22168,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_VAR(int (*binary_ if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: zval_ptr_dtor_nogc(free_op2.var); if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); @@ -22268,7 +22335,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_VAR(incdec_t i zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -22296,21 +22363,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_VAR(incdec_t i /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -22363,7 +22426,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_VAR(incdec_t zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -22389,19 +22452,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_VAR(incdec_t /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -22551,9 +22610,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_VAR(int type, ZE } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -22623,11 +22679,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HAND if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -22649,6 +22702,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HAN if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -22690,6 +22744,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -22721,6 +22776,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_ if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -22779,7 +22835,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HAND zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -22803,7 +22859,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HAN if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -22865,7 +22921,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -22891,7 +22947,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_ if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -22936,29 +22992,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDL if (IS_VAR == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zend_free_op free_op2; zval *property_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_VAR, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); } else { - zend_free_op free_op2, free_op_data1, free_op_data2; + zend_free_op free_op2, free_op_data1; + zval rv; zval *value; zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_VAR TSRMLS_CC); - zval_ptr_dtor_nogc(free_op2.var); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_VAR TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -22972,7 +23032,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDL if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -23026,10 +23085,13 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDL SAVE_OPLINE(); value_ptr = _get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + if (IS_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (IS_VAR == IS_VAR && - opline->extended_value == ZEND_RETURNS_FUNCTION && - !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF) && - !Z_ISREF_P(value_ptr)) { + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { if (!(free_op2.var != NULL)) { PZVAL_LOCK(value_ptr); /* undo the effect of get_zval_ptr_ptr() */ } @@ -23046,15 +23108,14 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDL } variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT) && UNEXPECTED(!Z_ISREF_P(variable_ptr))) { zend_error_noreturn(E_ERROR, "Cannot assign by reference to overloaded object"); } - if ((IS_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) || - (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == NULL))) { - zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); - } if ((IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) || (IS_VAR == IS_VAR && UNEXPECTED(value_ptr == &EG(error_zval)))) { variable_ptr = &EG(uninitialized_zval); @@ -23853,6 +23914,45 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_VAR_VAR_HANDLER(ZEND_ ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *expr; + zend_bool result; + + SAVE_OPLINE(); + expr = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + + if (Z_TYPE_P(expr) == IS_OBJECT) { + zend_class_entry *ce; + + if (IS_VAR == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + zval_ptr_dtor_nogc(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op2.var)); + } + result = instanceof_function(Z_OBJCE_P(expr), ce TSRMLS_CC); + } else { + result = 0; + } + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_ptr_dtor_nogc(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -23899,9 +23999,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -24011,7 +24112,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(int (* zval *object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); zval *property = NULL; zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_VAR == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -24034,21 +24135,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(int (* } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_UNUSED == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_UNUSED == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - if (!have_get_ptr) { + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); + + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -24104,15 +24201,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(int (* static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op1, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op1, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_VAR != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -24120,9 +24221,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(int (* } else { zval *dim = NULL; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_UNUSED TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_UNUSED TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -24133,33 +24235,18 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(int (* if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -24185,31 +24272,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_UNUSED(int (*bina if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -24464,9 +24537,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_UNUSED(int type, } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -24521,11 +24591,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_H if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -24547,6 +24614,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_ if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -24573,6 +24641,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_UNUSED_HANDLER(ZEND_O if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -24604,29 +24673,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HA if (IS_VAR == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zval *property_name = NULL; zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_VAR, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_UNUSED == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); } else { - zend_free_op free_op_data1, free_op_data2; + zend_free_op free_op_data1; + zval rv; zval *value; zval *dim = NULL; zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_UNUSED TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_UNUSED TSRMLS_CC); + + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -24640,7 +24713,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HA if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -25104,9 +25176,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -25476,7 +25549,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina zval *object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); zval *property = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_VAR == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -25499,21 +25572,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - if (!have_get_ptr) { + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); + + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -25569,15 +25638,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op1, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op1, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_VAR != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_VAR == IS_VAR && !(free_op1.var != NULL)) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -25585,9 +25658,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CV(int (*bina } else { zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CV TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CV TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -25598,33 +25672,18 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CV(int (*bina if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -25650,31 +25709,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_VAR_CV(int (*binary_o if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: - if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -25830,7 +25875,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CV(incdec_t in zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -25858,21 +25903,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CV(incdec_t in /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -25924,7 +25965,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_CV(incdec_t i zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -25950,19 +25991,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_CV(incdec_t i /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -26032,11 +26069,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDL if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -26058,6 +26092,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HAND if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -26099,6 +26134,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -26130,6 +26166,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_H if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -26187,7 +26224,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDL zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -26211,7 +26248,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HAND if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -26272,7 +26309,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -26298,7 +26335,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_H if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_VAR, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); if (IS_VAR == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -26343,29 +26380,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLE if (IS_VAR == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zval *property_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_VAR, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); } else { - zend_free_op free_op_data1, free_op_data2; + zend_free_op free_op_data1; + zval rv; zval *value; zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CV TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_CV TSRMLS_CC); + + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -26379,7 +26420,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLE if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -26432,10 +26472,13 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLE SAVE_OPLINE(); value_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op2.var TSRMLS_CC); + if (IS_CV == IS_VAR && UNEXPECTED(value_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (IS_CV == IS_VAR && - opline->extended_value == ZEND_RETURNS_FUNCTION && - !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF) && - !Z_ISREF_P(value_ptr)) { + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { if (!0) { PZVAL_LOCK(value_ptr); /* undo the effect of get_zval_ptr_ptr() */ } @@ -26452,15 +26495,14 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLE } variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT) && UNEXPECTED(!Z_ISREF_P(variable_ptr))) { zend_error_noreturn(E_ERROR, "Cannot assign by reference to overloaded object"); } - if ((IS_CV == IS_VAR && UNEXPECTED(value_ptr == NULL)) || - (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == NULL))) { - zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); - } if ((IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) || (IS_CV == IS_VAR && UNEXPECTED(value_ptr == &EG(error_zval)))) { variable_ptr = &EG(uninitialized_zval); @@ -27154,9 +27196,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_VAR == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_VAR == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -27346,7 +27389,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int zval *object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); zval *property = opline->op2.zv; zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_UNUSED == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -27369,21 +27412,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { + + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -27438,15 +27477,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_UNUSED != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_UNUSED == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -27454,9 +27497,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(int } else { zval *dim = opline->op2.zv; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CONST TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CONST TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -27467,33 +27511,18 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(int if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -27519,31 +27548,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CONST(int (*bi if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -27699,7 +27714,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CONST(incde zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); @@ -27727,21 +27742,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CONST(incde /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -27793,7 +27804,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_CONST(incd zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); @@ -27819,19 +27830,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_CONST(incd /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -27921,7 +27928,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -27945,7 +27952,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCOD if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -28006,7 +28013,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CONST_HANDLER(ZEND if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -28032,7 +28039,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_UNUSED_CONST_HANDLER(ZEND_OP if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -28262,7 +28269,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC } else if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, 0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -28640,9 +28647,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_UNUSED == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_UNUSED == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -28736,7 +28744,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(int (* zval *object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); zval *property = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_UNUSED == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -28759,21 +28767,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(int (* } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - if (!have_get_ptr) { + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); + + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -28829,15 +28833,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(int (* static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op2, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op2, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_UNUSED != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_UNUSED == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -28845,9 +28853,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(int (* } else { zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_TMP_VAR TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_TMP_VAR TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -28858,33 +28867,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMP(int (* if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: zval_ptr_dtor_nogc(free_op2.var); FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -28910,30 +28905,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_TMP(int (*bina if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: zval_ptr_dtor_nogc(free_op2.var); CHECK_EXCEPTION(); @@ -29090,7 +29072,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_TMP(incdec_ zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); @@ -29118,21 +29100,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_TMP(incdec_ /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -29185,7 +29163,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_TMP(incdec zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); @@ -29211,19 +29189,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_TMP(incdec /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -29315,7 +29289,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_H zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -29339,7 +29313,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_ if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -29401,7 +29375,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_TMP_HANDLER(ZEND_O if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -29427,7 +29401,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCO if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -29948,9 +29922,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_UNUSED == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_UNUSED == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -30044,7 +30019,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(int (* zval *object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); zval *property = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_UNUSED == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -30067,21 +30042,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(int (* } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - if (!have_get_ptr) { + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); + + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -30137,15 +30108,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(int (* static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op2, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op2, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_UNUSED != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_UNUSED == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -30153,9 +30128,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(int (* } else { zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_VAR TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_VAR TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -30166,33 +30142,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_VAR(int (* if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: zval_ptr_dtor_nogc(free_op2.var); FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -30218,30 +30180,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_VAR(int (*bina if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: zval_ptr_dtor_nogc(free_op2.var); CHECK_EXCEPTION(); @@ -30398,7 +30347,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_VAR(incdec_ zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); @@ -30426,21 +30375,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_VAR(incdec_ /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -30493,7 +30438,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_VAR(incdec zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); @@ -30519,19 +30464,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_VAR(incdec /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -30623,7 +30564,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_H zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -30647,7 +30588,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_ if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -30709,7 +30650,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_VAR_HANDLER(ZEND_O if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -30735,7 +30676,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCO if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -31256,9 +31197,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_UNUSED == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_UNUSED == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -31352,7 +31294,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(int zval *object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); zval *property = NULL; zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_UNUSED == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -31375,21 +31317,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(int } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_UNUSED == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_UNUSED == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { + + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -31444,15 +31382,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(int static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_UNUSED != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_UNUSED == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -31460,9 +31402,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(int } else { zval *dim = NULL; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_UNUSED TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_UNUSED TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -31473,33 +31416,18 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(int if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -31525,31 +31453,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_UNUSED(int (*b if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -31775,9 +31689,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_UNUSED == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_UNUSED == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -31871,7 +31786,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b zval *object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); zval *property = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_UNUSED == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -31894,21 +31809,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - if (!have_get_ptr) { + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); + + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -31963,15 +31874,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_UNUSED != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_UNUSED == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -31979,9 +31894,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(int (*b } else { zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CV TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CV TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -31992,33 +31908,18 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(int (*b if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -32044,31 +31945,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_UNUSED_CV(int (*binar if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -32224,7 +32111,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CV(incdec_t zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); @@ -32252,21 +32139,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CV(incdec_t /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -32318,7 +32201,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_CV(incdec_ zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_obj_zval_ptr_unused(execute_data TSRMLS_CC); @@ -32344,19 +32227,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_CV(incdec_ /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -32446,7 +32325,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HA zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -32470,7 +32349,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_H if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -32531,7 +32410,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CV_HANDLER(ZEND_OP if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -32557,7 +32436,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_UNUSED_CV_HANDLER(ZEND_OPCOD if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_UNUSED, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); if (IS_UNUSED == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -33074,9 +32953,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_UNUSED == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_UNUSED == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -33603,10 +33483,10 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER zend_error_noreturn(E_ERROR, "Cannot return string offsets by reference"); } - if (IS_CV == IS_VAR && !Z_ISREF_P(retval_ptr)) { - if (opline->extended_value == ZEND_RETURNS_FUNCTION && - (Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF)) { - } else { + if (IS_CV == IS_VAR) { + if (retval_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(retval_ptr) & IS_VAR_RET_REF))) { zend_error(E_NOTICE, "Only variable references should be returned by reference"); if (EX(return_value)) { ZVAL_NEW_REF(EX(return_value), retval_ptr); @@ -34456,27 +34336,6 @@ static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - - zval *expr; - zend_bool result; - - SAVE_OPLINE(); - expr = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - - if (Z_TYPE_P(expr) == IS_OBJECT) { - result = instanceof_function(Z_OBJCE_P(expr), Z_CE_P(EX_VAR(opline->op2.var)) TSRMLS_CC); - } else { - result = 0; - } - ZVAL_BOOL(EX_VAR(opline->result.var), result); - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_FASTCALL ZEND_STRLEN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -34846,7 +34705,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi zval *object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); zval *property = opline->op2.zv; zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_CV == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -34869,21 +34728,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - if (!have_get_ptr) { + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); + + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -34938,15 +34793,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CONST(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_CV != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_CV == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -34954,9 +34813,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CONST(int (*bi } else { zval *dim = opline->op2.zv; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CONST TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CONST TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -34967,33 +34827,18 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CONST(int (*bi if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -35019,31 +34864,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CONST(int (*binary if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -35199,7 +35030,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CONST(incdec_t zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); @@ -35227,21 +35058,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CONST(incdec_t /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -35293,7 +35120,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_CONST(incdec_t zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); @@ -35319,19 +35146,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_CONST(incdec_t /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -35480,9 +35303,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_CONST(int type, Z } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -35552,11 +35372,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HAN if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -35578,6 +35395,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HA if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -35619,6 +35437,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -35650,6 +35469,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_CONST_HANDLER(ZEND_OPCODE if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -35707,7 +35527,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HAN zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -35731,7 +35551,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HA if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -35792,7 +35612,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -35818,7 +35638,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_CONST_HANDLER(ZEND_OPCODE if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -35896,29 +35716,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HAND if (IS_CV == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zval *property_name = opline->op2.zv; zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_CV, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); } else { - zend_free_op free_op_data1, free_op_data2; + zend_free_op free_op_data1; + zval rv; zval *value; zval *dim = opline->op2.zv; zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CONST TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_CONST TSRMLS_CC); + + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -35932,7 +35756,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HAND if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -36618,6 +36441,45 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CV_CONST_HANDLER(ZEND ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *expr; + zend_bool result; + + SAVE_OPLINE(); + expr = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); + + if (Z_TYPE_P(expr) == IS_OBJECT) { + zend_class_entry *ce; + + if (IS_CONST == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op2.var)); + } + result = instanceof_function(Z_OBJCE_P(expr), ce TSRMLS_CC); + } else { + result = 0; + } + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -36664,9 +36526,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CV == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CV == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -37107,7 +36970,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMP(int (*bina zval *object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); zval *property = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_CV == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -37130,21 +36993,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMP(int (*bina } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - if (!have_get_ptr) { + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); + + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -37200,15 +37059,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMP(int (*bina static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_TMP(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op2, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op2, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_CV != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_CV == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -37216,9 +37079,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_TMP(int (*bina } else { zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_TMP_VAR TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_TMP_VAR TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -37229,33 +37093,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_TMP(int (*bina if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: zval_ptr_dtor_nogc(free_op2.var); FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -37281,30 +37131,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_TMP(int (*binary_o if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: zval_ptr_dtor_nogc(free_op2.var); CHECK_EXCEPTION(); @@ -37461,7 +37298,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_TMP(incdec_t in zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); @@ -37489,21 +37326,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_TMP(incdec_t in /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -37556,7 +37389,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_TMP(incdec_t i zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); @@ -37582,19 +37415,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_TMP(incdec_t i /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -37665,11 +37494,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDL if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -37691,6 +37517,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HAND if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -37732,6 +37559,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -37763,6 +37591,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_H if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -37821,7 +37650,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDL zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -37845,7 +37674,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HAND if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -37907,7 +37736,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -37933,7 +37762,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_H if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -37978,29 +37807,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLE if (IS_CV == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zend_free_op free_op2; zval *property_name = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_CV, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_TMP_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); } else { - zend_free_op free_op2, free_op_data1, free_op_data2; + zend_free_op free_op2, free_op_data1; + zval rv; zval *value; zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_TMP_VAR TSRMLS_CC); - zval_ptr_dtor_nogc(free_op2.var); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_TMP_VAR TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -38014,7 +37847,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLE if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -38605,9 +38437,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CV == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CV == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -38991,7 +38824,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_VAR(int (*bina zval *object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); zval *property = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_CV == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -39014,21 +38847,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_VAR(int (*bina } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - if (!have_get_ptr) { + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); + + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -39084,15 +38913,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_VAR(int (*bina static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_VAR(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op2, free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op2, free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_CV != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_CV == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -39100,9 +38933,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_VAR(int (*bina } else { zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_VAR TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_VAR TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -39113,33 +38947,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_VAR(int (*bina if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: zval_ptr_dtor_nogc(free_op2.var); FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -39165,30 +38985,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_VAR(int (*binary_o if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: zval_ptr_dtor_nogc(free_op2.var); CHECK_EXCEPTION(); @@ -39345,7 +39152,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_VAR(incdec_t in zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); @@ -39373,21 +39180,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_VAR(incdec_t in /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -39440,7 +39243,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_VAR(incdec_t i zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); @@ -39466,19 +39269,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_VAR(incdec_t i /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -39628,9 +39427,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_VAR(int type, ZEN } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -39700,11 +39496,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDL if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -39726,6 +39519,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HAND if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -39767,6 +39561,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -39798,6 +39593,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_H if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -39856,7 +39652,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDL zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -39880,7 +39676,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HAND if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -39942,7 +39738,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -39968,7 +39764,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_H if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -40013,29 +39809,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLE if (IS_CV == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zend_free_op free_op2; zval *property_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_CV, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_VAR == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); } else { - zend_free_op free_op2, free_op_data1, free_op_data2; + zend_free_op free_op2, free_op_data1; + zval rv; zval *value; zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_VAR TSRMLS_CC); - zval_ptr_dtor_nogc(free_op2.var); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_VAR TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -40049,7 +39849,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLE if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -40103,10 +39902,13 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLE SAVE_OPLINE(); value_ptr = _get_zval_ptr_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + if (IS_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (IS_VAR == IS_VAR && - opline->extended_value == ZEND_RETURNS_FUNCTION && - !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF) && - !Z_ISREF_P(value_ptr)) { + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { if (!(free_op2.var != NULL)) { PZVAL_LOCK(value_ptr); /* undo the effect of get_zval_ptr_ptr() */ } @@ -40123,15 +39925,14 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLE } variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT) && UNEXPECTED(!Z_ISREF_P(variable_ptr))) { zend_error_noreturn(E_ERROR, "Cannot assign by reference to overloaded object"); } - if ((IS_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) || - (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == NULL))) { - zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); - } if ((IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) || (IS_VAR == IS_VAR && UNEXPECTED(value_ptr == &EG(error_zval)))) { variable_ptr = &EG(uninitialized_zval); @@ -40802,6 +40603,45 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CV_VAR_HANDLER(ZEND_O ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *expr; + zend_bool result; + + SAVE_OPLINE(); + expr = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); + + if (Z_TYPE_P(expr) == IS_OBJECT) { + zend_class_entry *ce; + + if (IS_VAR == IS_CONST) { + if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { + ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + } else { + ce = zend_fetch_class_by_name(Z_STR_P(opline->op2.zv), opline->op2.zv + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce); + } + } else { + ce = Z_CE_P(EX_VAR(opline->op2.var)); + } + result = instanceof_function(Z_OBJCE_P(expr), ce TSRMLS_CC); + } else { + result = 0; + } + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -40848,9 +40688,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CV == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CV == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -40959,7 +40800,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(int (*b zval *object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); zval *property = NULL; zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_CV == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -40982,21 +40823,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(int (*b } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_UNUSED == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_UNUSED == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { + + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -41051,15 +40888,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(int (*b static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_CV != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_CV == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -41067,9 +40908,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(int (*b } else { zval *dim = NULL; - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_UNUSED TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_UNUSED TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -41080,33 +40922,18 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(int (*b if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -41132,31 +40959,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_UNUSED(int (*binar if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -41411,9 +41224,6 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_UNUSED(int type, } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { - if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { - ZVAL_MAKE_REF(retval); - } ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } CHECK_EXCEPTION(); @@ -41468,11 +41278,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HA if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -41494,6 +41301,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_H if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -41520,6 +41328,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OP if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -41551,29 +41360,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HAN if (IS_CV == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zval *property_name = NULL; zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_CV, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_UNUSED == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); } else { - zend_free_op free_op_data1, free_op_data2; + zend_free_op free_op_data1; + zval rv; zval *value; zval *dim = NULL; zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_UNUSED TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_UNUSED TSRMLS_CC); + + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -41587,7 +41400,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HAN if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -41908,9 +41720,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CV == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CV == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -42279,7 +42092,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar zval *object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); zval *property = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); zval *value; - int have_get_ptr = 0; + zval *zptr; if (IS_CV == IS_VAR && UNEXPECTED(object == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); @@ -42302,21 +42115,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar } else { /* here we are sure we are dealing with an object */ if (opline->extended_value == ZEND_ASSIGN_OBJ - && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); - - have_get_ptr = 1; - binary_op(zptr, zptr, value TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(EX_VAR(opline->result.var), zptr); - } - } - } + && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { + + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + binary_op(zptr, zptr, value TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(EX_VAR(opline->result.var), zptr); + } + } else { zval *z = NULL; zval rv; @@ -42371,15 +42180,19 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CV(int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC), ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_free_op free_op_data2, free_op_data1; - zval *var_ptr; + zend_free_op free_op_data1; + zval *var_ptr, rv; zval *value, *container; SAVE_OPLINE(); container = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + } + if (IS_CV != IS_UNUSED) { + ZVAL_DEREF(container); + } + if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { if (IS_CV == IS_VAR && !0) { Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } @@ -42387,9 +42200,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CV(int (*binar } else { zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, IS_CV TSRMLS_CC); + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CV TSRMLS_CC); value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); } if (UNEXPECTED(var_ptr == NULL)) { @@ -42400,33 +42214,18 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CV(int (*binar if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_dim_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_dim_exit: - FREE_OP(free_op_data1); - FREE_OP_VAR_PTR(free_op_data2); CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); @@ -42452,31 +42251,17 @@ static int ZEND_FASTCALL zend_binary_assign_op_helper_SPEC_CV_CV(int (*binary_op if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } - goto assign_op_exit; - } - - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - - if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_OBJECT) && - UNEXPECTED(Z_OBJ_HANDLER_P(var_ptr, get) && Z_OBJ_HANDLER_P(var_ptr, set))) { - /* proxy object */ - zval rv; - zval *objval = Z_OBJ_HANDLER_P(var_ptr, get)(var_ptr, &rv TSRMLS_CC); - Z_ADDREF_P(objval); - binary_op(objval, objval, value TSRMLS_CC); - Z_OBJ_HANDLER_P(var_ptr, set)(var_ptr, objval TSRMLS_CC); - zval_ptr_dtor(objval); } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); - } - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } -assign_op_exit: - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -42632,7 +42417,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CV(incdec_t inc zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); @@ -42660,21 +42445,17 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CV(incdec_t inc /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - ZVAL_DEREF(zptr); - SEPARATE_ZVAL_NOREF(zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - have_get_ptr = 1; - incdec_op(zptr); - if (RETURN_VALUE_USED(opline)) { - ZVAL_COPY(retval, zptr); - } - } - } + ZVAL_DEREF(zptr); + SEPARATE_ZVAL_NOREF(zptr); - if (!have_get_ptr) { + incdec_op(zptr); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, zptr); + } + } else { zval rv; if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { @@ -42726,7 +42507,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_CV(incdec_t in zval *object; zval *property; zval *retval; - int have_get_ptr = 0; + zval *zptr; SAVE_OPLINE(); object = _get_zval_ptr_cv_BP_VAR_RW(execute_data, opline->op1.var TSRMLS_CC); @@ -42752,19 +42533,15 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_CV(incdec_t in /* here we are sure we are dealing with an object */ - if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval *zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - if (zptr != NULL) { /* NULL means no success in getting PTR */ - have_get_ptr = 1; - ZVAL_DEREF(zptr); - ZVAL_COPY(retval, zptr); + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { - SEPARATE_ZVAL_NOREF(zptr); - incdec_op(zptr); - } - } + ZVAL_DEREF(zptr); + ZVAL_COPY(retval, zptr); - if (!have_get_ptr) { + SEPARATE_ZVAL_NOREF(zptr); + incdec_op(zptr); + } else { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { zval rv; zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); @@ -42834,11 +42611,8 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLE if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (EXPECTED(opline->extended_value == 0)) { - zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); - } else { - zend_fetch_dimension_address_W_ref(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); - } + ZVAL_DEREF(container); + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -42860,6 +42634,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_RW_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDL if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -42901,6 +42676,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -42932,6 +42708,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HA if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } + ZVAL_DEREF(container); zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { @@ -42989,7 +42766,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLE zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, (opline->extended_value & ZEND_FETCH_MAKE_REF) != 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -43013,7 +42790,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_RW_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDL if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_RW TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -43074,7 +42851,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_W TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -43100,7 +42877,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HA if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET, 0 TSRMLS_CC); + zend_fetch_property_address(EX_VAR(opline->result.var), container, IS_CV, property, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), BP_VAR_UNSET TSRMLS_CC); if (IS_CV == IS_VAR && READY_TO_DESTROY(free_op1.var)) { EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); @@ -43145,29 +42922,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER if (IS_CV == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (UNEXPECTED(Z_ISREF_P(object_ptr)) && Z_TYPE_P(Z_REFVAL_P(object_ptr)) == IS_OBJECT) { - object_ptr = Z_REFVAL_P(object_ptr); - } - if (Z_TYPE_P(object_ptr) == IS_OBJECT) { + ZVAL_DEREF(object_ptr); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zval *property_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, IS_CV, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); } else { - zend_free_op free_op_data1, free_op_data2; + zend_free_op free_op_data1; + zval rv; zval *value; zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); zval *variable_ptr; - variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CV TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && + EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { + zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - if (UNEXPECTED(variable_ptr != NULL)) { - zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); FREE_OP(free_op_data1); } else { - variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); + zend_fetch_dimension_address_W(&rv, object_ptr, dim, IS_CV TSRMLS_CC); + + value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + variable_ptr = Z_INDIRECT(rv); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (RETURN_VALUE_USED(opline)) { @@ -43181,7 +42962,6 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), value); } - FREE_OP_VAR_PTR(free_op_data2); } } } @@ -43234,10 +43014,13 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER SAVE_OPLINE(); value_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op2.var TSRMLS_CC); + if (IS_CV == IS_VAR && UNEXPECTED(value_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (IS_CV == IS_VAR && - opline->extended_value == ZEND_RETURNS_FUNCTION && - !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF) && - !Z_ISREF_P(value_ptr)) { + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { if (!0) { PZVAL_LOCK(value_ptr); /* undo the effect of get_zval_ptr_ptr() */ } @@ -43254,15 +43037,14 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER } variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); + } if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT) && UNEXPECTED(!Z_ISREF_P(variable_ptr))) { zend_error_noreturn(E_ERROR, "Cannot assign by reference to overloaded object"); } - if ((IS_CV == IS_VAR && UNEXPECTED(value_ptr == NULL)) || - (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == NULL))) { - zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); - } if ((IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) || (IS_CV == IS_VAR && UNEXPECTED(value_ptr == &EG(error_zval)))) { variable_ptr = &EG(uninitialized_zval); @@ -43829,9 +43611,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* If a function call result is yielded and the function did * not return by reference we throw a notice. */ - if (IS_CV == IS_VAR && !Z_ISREF_P(value_ptr) - && !(opline->extended_value == ZEND_RETURNS_FUNCTION - && (Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF))) { + if (IS_CV == IS_VAR && + (value_ptr == &EG(uninitialized_zval) || + (opline->extended_value == ZEND_RETURNS_FUNCTION && + !(Z_VAR_FLAGS_P(value_ptr) & IS_VAR_RET_REF)))) { zend_error(E_NOTICE, "Only variable references should be yielded by reference"); } else { ZVAL_MAKE_REF(value_ptr); @@ -45643,31 +45426,31 @@ void zend_init_opcodes_handlers(void) ZEND_SEND_REF_SPEC_CV_HANDLER, ZEND_SEND_REF_SPEC_CV_HANDLER, ZEND_SEND_REF_SPEC_CV_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, - ZEND_NEW_SPEC_HANDLER, + ZEND_NEW_SPEC_CONST_HANDLER, + ZEND_NEW_SPEC_CONST_HANDLER, + ZEND_NEW_SPEC_CONST_HANDLER, + ZEND_NEW_SPEC_CONST_HANDLER, + ZEND_NEW_SPEC_CONST_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NEW_SPEC_VAR_HANDLER, + ZEND_NEW_SPEC_VAR_HANDLER, + ZEND_NEW_SPEC_VAR_HANDLER, + ZEND_NEW_SPEC_VAR_HANDLER, + ZEND_NEW_SPEC_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -47398,26 +47181,26 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_INSTANCEOF_SPEC_TMP_HANDLER, - ZEND_INSTANCEOF_SPEC_TMP_HANDLER, - ZEND_INSTANCEOF_SPEC_TMP_HANDLER, - ZEND_INSTANCEOF_SPEC_TMP_HANDLER, - ZEND_INSTANCEOF_SPEC_TMP_HANDLER, - ZEND_INSTANCEOF_SPEC_VAR_HANDLER, - ZEND_INSTANCEOF_SPEC_VAR_HANDLER, - ZEND_INSTANCEOF_SPEC_VAR_HANDLER, - ZEND_INSTANCEOF_SPEC_VAR_HANDLER, - ZEND_INSTANCEOF_SPEC_VAR_HANDLER, + ZEND_INSTANCEOF_SPEC_TMP_CONST_HANDLER, + ZEND_NULL_HANDLER, + ZEND_INSTANCEOF_SPEC_TMP_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_INSTANCEOF_SPEC_VAR_CONST_HANDLER, + ZEND_NULL_HANDLER, + ZEND_INSTANCEOF_SPEC_VAR_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INSTANCEOF_SPEC_CV_CONST_HANDLER, ZEND_NULL_HANDLER, + ZEND_INSTANCEOF_SPEC_CV_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_INSTANCEOF_SPEC_CV_HANDLER, - ZEND_INSTANCEOF_SPEC_CV_HANDLER, - ZEND_INSTANCEOF_SPEC_CV_HANDLER, - ZEND_INSTANCEOF_SPEC_CV_HANDLER, - ZEND_INSTANCEOF_SPEC_CV_HANDLER, ZEND_DECLARE_CLASS_SPEC_HANDLER, ZEND_DECLARE_CLASS_SPEC_HANDLER, ZEND_DECLARE_CLASS_SPEC_HANDLER, diff --git a/ext/fileinfo/libmagic/readcdf.c b/ext/fileinfo/libmagic/readcdf.c index ec97ced44b..175719a2d7 100644 --- a/ext/fileinfo/libmagic/readcdf.c +++ b/ext/fileinfo/libmagic/readcdf.c @@ -88,6 +88,9 @@ static const struct cv { { 0x00000000000c1084LLU, 0x46000000000000c0LLU }, #endif "x-msi", + }, + { { 0, 0 }, + NULL, } }, clsid2desc[] = { { @@ -98,6 +101,9 @@ static const struct cv { #endif "MSI Installer", }, + { { 0, 0 }, + NULL, + } }; private const char * diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 926fc30e8b..2a77132ba3 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1798,7 +1798,7 @@ ZEND_FUNCTION(gmp_random) Gets a random number in the range 0 to (2 ** n) - 1 */ ZEND_FUNCTION(gmp_random_bits) { - long bits; + zend_long bits; mpz_ptr gmpnum_result; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &bits) == FAILURE) { diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index f43802647b..5c6880beea 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -616,7 +616,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, VAR_SOURCE(opline->op1)->opcode == ZEND_QM_ASSIGN && ZEND_OP1_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST && opline->opcode != ZEND_CASE && /* CASE _always_ expects variable */ - opline->opcode != ZEND_FETCH_LIST && /* in 5.1, FETCH_DIM_TMP_VAR expects T */ + opline->opcode != ZEND_FETCH_LIST && opline->opcode != ZEND_FE_RESET && opline->opcode != ZEND_FREE ) { diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index 091437e119..8fb5a9b0c9 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -227,10 +227,16 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx case ZEND_FETCH_CLASS: case ZEND_ADD_INTERFACE: case ZEND_ADD_TRAIT: + case ZEND_INSTANCEOF: if (ZEND_OP2_TYPE(opline) == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2); } break; + case ZEND_NEW: + if (ZEND_OP1_TYPE(opline) == IS_CONST) { + LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); + } + break; case ZEND_ASSIGN_OBJ: case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_W: diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 70e58f5695..1a6d0b675a 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -126,6 +126,7 @@ void zend_optimizer_update_op1_const(zend_op_array *op_array, case ZEND_CATCH: case ZEND_FETCH_CONSTANT: case ZEND_DEFINED: + case ZEND_NEW: opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC); zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline))); Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->last_cache_slot++; @@ -173,6 +174,7 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array, case ZEND_ISSET_ISEMPTY_VAR: case ZEND_ADD_INTERFACE: case ZEND_ADD_TRAIT: + case ZEND_INSTANCEOF: Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->last_cache_slot++; zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); zend_optimizer_add_literal(op_array, val TSRMLS_CC); diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 4650dc286b..6f37146a91 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1130,10 +1130,6 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr return new_persistent_script; } - if (!compact_persistent_script(new_persistent_script)) { - return new_persistent_script; - } - /* exclusive lock */ zend_shared_alloc_lock(TSRMLS_C); diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index ee7be50619..22683245f6 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -88,64 +88,6 @@ zend_persistent_script* create_persistent_script(void) return persistent_script; } -static int compact_hash_table(HashTable *ht) -{ - uint i = 3; - uint j; - uint nSize; - Bucket *d; - Bucket *p; - - if (!ht->nNumOfElements || (ht->u.flags & HASH_FLAG_PACKED)) { - /* Empty tables don't allocate space for Buckets */ - return 1; - } - - if (ht->nNumOfElements >= 0x80000000) { - /* prevent overflow */ - nSize = 0x80000000; - } else { - while ((1U << i) < ht->nNumOfElements) { - i++; - } - nSize = 1 << i; - } - - if (nSize >= ht->nTableSize) { - /* Keep the size */ - return 1; - } - - d = (Bucket *)pemalloc(nSize * (sizeof(Bucket) + sizeof(uint32_t)), ht->u.flags & HASH_FLAG_PERSISTENT); - if (!d) { - return 0; - } - - for (i = 0, j = 0; i < ht->nNumUsed; i++) { - p = ht->arData + i; - if (Z_TYPE(p->val) != IS_UNDEF) { - d[j++] = *p; - } - } - ht->nNumUsed = j; - - pefree(ht->arData, ht->u.flags & HASH_FLAG_PERSISTENT); - - ht->arData = d; - ht->arHash = (uint32_t *)(d + nSize); - ht->nTableSize = nSize; - ht->nTableMask = ht->nTableSize - 1; - zend_hash_rehash(ht); - - return 1; -} - -int compact_persistent_script(zend_persistent_script *persistent_script) -{ - return compact_hash_table(&persistent_script->function_table) && - compact_hash_table(&persistent_script->class_table); -} - void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements) { if (destroy_elements) { diff --git a/ext/opcache/zend_accelerator_util_funcs.h b/ext/opcache/zend_accelerator_util_funcs.h index 2f515d85cc..cbcb2ffa8e 100644 --- a/ext/opcache/zend_accelerator_util_funcs.h +++ b/ext/opcache/zend_accelerator_util_funcs.h @@ -28,7 +28,6 @@ void zend_accel_copy_internal_functions(TSRMLS_D); zend_persistent_script* create_persistent_script(void); -int compact_persistent_script(zend_persistent_script *script); void free_persistent_script(zend_persistent_script *persistent_script, int destroy_elements); void zend_accel_free_user_functions(HashTable *ht TSRMLS_DC); diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index 40d4114879..323c805fca 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -61,7 +61,6 @@ static int dblib_fetch_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS msg, einfo->dberr, einfo->severity, stmt ? stmt->active_query_string : ""); add_next_index_long(info, einfo->dberr); - // TODO: avoid reallocation ??? add_next_index_string(info, message); efree(message); add_next_index_long(info, einfo->oserr); @@ -145,10 +144,12 @@ static zend_long dblib_handle_doer(pdo_dbh_t *dbh, const char *sql, zend_long sq static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC) { - pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; + + /* pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; */ + char *q; int l = 1; - + *quoted = q = safe_emalloc(2, unquotedlen, 3); *q++ = '\''; @@ -174,7 +175,6 @@ static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquote static int pdo_dblib_transaction_cmd(const char *cmd, pdo_dbh_t *dbh TSRMLS_DC) { pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data; - RETCODE ret; if (FAIL == dbcmd(H->link, cmd)) { return 0; @@ -246,6 +246,23 @@ char *dblib_handle_last_id(pdo_dbh_t *dbh, const char *name, unsigned int *len T return id; } +static int dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val TSRMLS_DC) +{ + switch(attr) { + case PDO_ATTR_TIMEOUT: + return 0; + default: + return 1; + } + +} + +static int dblib_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value TSRMLS_DC) +{ + /* dblib_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; */ + return 0; +} + static struct pdo_dbh_methods dblib_methods = { dblib_handle_closer, dblib_handle_preparer, @@ -254,10 +271,10 @@ static struct pdo_dbh_methods dblib_methods = { dblib_handle_begin, /* begin */ dblib_handle_commit, /* commit */ dblib_handle_rollback, /* rollback */ - NULL, /*set attr */ + dblib_set_attr, /*set attr */ dblib_handle_last_id, /* last insert id */ dblib_fetch_error, /* fetch error */ - NULL, /* get attr */ + dblib_get_attribute, /* get attr */ NULL, /* check liveness */ NULL, /* get driver methods */ NULL, /* request shutdown */ @@ -303,6 +320,12 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_ php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, nvars); + if (driver_options) { + int timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC); + dbsetlogintime(timeout); /* Connection/Login Timeout */ + dbsettime(timeout); /* Statement Timeout */ + } + H = pecalloc(1, sizeof(*H), dbh->is_persistent); H->login = dblogin(); H->err.sqlstate = dbh->error_code; @@ -311,8 +334,8 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_ goto cleanup; } - DBERRHANDLE(H->login, (EHANDLEFUNC) error_handler); - DBMSGHANDLE(H->login, (MHANDLEFUNC) msg_handler); + DBERRHANDLE(H->login, (EHANDLEFUNC) pdo_dblib_error_handler); + DBMSGHANDLE(H->login, (MHANDLEFUNC) pdo_dblib_msg_handler); if(vars[5].optval) { for(i=0;i<nvers;i++) { diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index a29405b24e..bd79be3e9c 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -103,21 +103,15 @@ static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) /* Cancel any pending results */ dbcancel(H->link); - efree(stmt->columns); - stmt->columns = NULL; - return 1; } static int pdo_dblib_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) { pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; - - efree(stmt->columns); - stmt->columns = NULL; - + efree(S); - + return 1; } @@ -128,16 +122,16 @@ static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) RETCODE ret; ret = dbresults(H->link); - + if (FAIL == ret) { pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO_DBLIB: dbresults() returned FAIL" TSRMLS_CC); return 0; } - + if(NO_MORE_RESULTS == ret) { return 0; } - + stmt->row_count = DBCOUNT(H->link); stmt->column_count = dbnumcols(H->link); @@ -204,7 +198,7 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) struct pdo_column_data *col = &stmt->columns[colno]; - col->name = (char*)dbcolname(H->link, colno+1); + col->name = estrdup(dbcolname(H->link, colno+1)); col->maxlen = dbcollen(H->link, colno+1); col->namelen = strlen(col->name); col->param_type = PDO_PARAM_STR; @@ -255,12 +249,11 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, break; } case SQLUNIQUE: { - *len = 36+1; + *len = 37; tmp_ptr = emalloc(*len + 1); - - /* uniqueidentifier is a 16-byte binary number, convert to 32 char hex string */ *len = dbconvert(NULL, SQLUNIQUE, *ptr, *len, SQLCHAR, tmp_ptr, *len); php_strtoupper(tmp_ptr, *len); + tmp_ptr[36] = '\0'; *ptr = tmp_ptr; break; } diff --git a/ext/pdo_dblib/pdo_dblib.c b/ext/pdo_dblib/pdo_dblib.c index 3afd885df5..4cd0749cf8 100644 --- a/ext/pdo_dblib/pdo_dblib.c +++ b/ext/pdo_dblib/pdo_dblib.c @@ -86,7 +86,7 @@ ZEND_GET_MODULE(pdo_dblib) #endif #endif -int error_handler(DBPROCESS *dbproc, int severity, int dberr, +int pdo_dblib_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr) { pdo_dblib_err *einfo; @@ -103,6 +103,7 @@ int error_handler(DBPROCESS *dbproc, int severity, int dberr, einfo->severity = severity; einfo->oserr = oserr; einfo->dberr = dberr; + if (einfo->oserrstr) { efree(einfo->oserrstr); } @@ -128,16 +129,10 @@ int error_handler(DBPROCESS *dbproc, int severity, int dberr, } strcpy(einfo->sqlstate, state); -#if 0 - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "dblib error: %d %s (severity %d)", - dberr, dberrstr, severity); -#endif - return INT_CANCEL; } -int msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, +int pdo_dblib_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, DBUSMALLINT line) { pdo_dblib_err *einfo; @@ -156,10 +151,6 @@ int msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, einfo->lastmsg = estrdup(msgtext); } -#if 0 - php_error_docref(NULL TSRMLS_CC, E_WARNING, "dblib message: %s (severity %d)", msgtext, severity); -#endif - return 0; } @@ -196,18 +187,9 @@ PHP_MINIT_FUNCTION(pdo_dblib) return FAILURE; } - /* TODO: - - dbsetifile() - dbsetmaxprocs() - dbsetlogintime() - dbsettime() - - */ - #if !PHP_DBLIB_IS_MSSQL - dberrhandle(error_handler); - dbmsghandle(msg_handler); + dberrhandle((EHANDLEFUNC) pdo_dblib_error_handler); + dbmsghandle((MHANDLEFUNC) pdo_dblib_msg_handler); #endif return SUCCESS; diff --git a/ext/pdo_dblib/php_pdo_dblib_int.h b/ext/pdo_dblib/php_pdo_dblib_int.h index e247b5c19e..3b341478d7 100644 --- a/ext/pdo_dblib/php_pdo_dblib_int.h +++ b/ext/pdo_dblib/php_pdo_dblib_int.h @@ -37,7 +37,7 @@ # define DBSETOPT(a, b, c) dbsetopt(a, b, c) # define SYBESMSG SQLESMSG # define SYBESEOF SQLESEOF -# define SYBEFCON SQLECONN // SQLEFCON does not exist in MS SQL Server. +# define SYBEFCON SQLECONN /* SQLEFCON does not exist in MS SQL Server. */ # define SYBEMEM SQLEMEM # define SYBEPWD SQLEPWD @@ -89,10 +89,10 @@ typedef unsigned char *LPBYTE; typedef float DBFLT4; #endif -int error_handler(DBPROCESS *dbproc, int severity, int dberr, +int pdo_dblib_error_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr); -int msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, +int pdo_dblib_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, DBUSMALLINT line); extern pdo_driver_t pdo_dblib_driver; diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 5e0ccb57b3..ec64f09c09 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -3310,6 +3310,7 @@ static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type zend_try { failed = 0; + CG(zend_lineno) = 0; res = phar_orig_compile_file(file_handle, type TSRMLS_CC); } zend_catch { failed = 1; diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index ba70ecca9d..361b0824eb 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -267,10 +267,8 @@ static zval *sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, z name = NULL; } else { if (Z_TYPE_P(member) != IS_STRING) { - tmp_zv = *member; - zval_copy_ctor(&tmp_zv); + ZVAL_STR(&tmp_zv, zval_get_string(member)); member = &tmp_zv; - convert_to_string(member); } name = Z_STRVAL_P(member); } @@ -476,9 +474,7 @@ static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool } } else { if (Z_TYPE_P(member) != IS_STRING) { - trim_zv = *member; - zval_copy_ctor(&trim_zv); - convert_to_string(&trim_zv); + ZVAL_STR(&trim_zv, zval_get_string(member)); php_trim(Z_STRVAL(trim_zv), Z_STRLEN(trim_zv), NULL, 0, &tmp_zv, 3 TSRMLS_CC); zval_dtor(&trim_zv); member = &tmp_zv; @@ -736,10 +732,8 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend zval tmp_zv; if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) { - tmp_zv = *member; - zval_copy_ctor(&tmp_zv); + ZVAL_STR(&tmp_zv, zval_get_string(member)); member = &tmp_zv; - convert_to_string(member); } sxe = Z_SXEOBJ_P(object); @@ -866,10 +860,8 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements, int test = 0; if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) { - tmp_zv = *member; - zval_copy_ctor(&tmp_zv); + ZVAL_STR(&tmp_zv, zval_get_string(member)); member = &tmp_zv; - convert_to_string(member); } sxe = Z_SXEOBJ_P(object); diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index b12303ee0e..97191652d6 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -834,13 +834,10 @@ static xmlNodePtr to_xml_string(encodeTypePtr type, zval *data, int style, xmlNo str = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data)); new_len = Z_STRLEN_P(data); } else { - zval tmp = *data; - - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - str = estrndup(Z_STRVAL(tmp), Z_STRLEN(tmp)); - new_len = Z_STRLEN(tmp); - zval_dtor(&tmp); + zend_string *tmp = zval_get_string(data); + str = estrndup(tmp->val, tmp->len); + new_len = tmp->len; + zend_string_release(tmp); } if (SOAP_GLOBAL(encoding) != NULL) { @@ -953,9 +950,7 @@ static xmlNodePtr to_xml_hexbin(encodeTypePtr type, zval *data, int style, xmlNo FIND_ZVAL_NULL(data, ret, style); if (Z_TYPE_P(data) != IS_STRING) { - tmp = *data; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); + ZVAL_STR(&tmp, zval_get_string(data)); data = &tmp; } str = (unsigned char *) safe_emalloc(Z_STRLEN_P(data) * 2, sizeof(char), 1); @@ -1063,9 +1058,9 @@ static xmlNodePtr to_xml_long(encodeTypePtr type, zval *data, int style, xmlNode snprintf(s, sizeof(s), "%0.0F",floor(Z_DVAL_P(data))); xmlNodeSetContent(ret, BAD_CAST(s)); } else { - zval tmp = *data; + zval tmp; - zval_copy_ctor(&tmp); + ZVAL_DUP(&tmp, data); if (Z_TYPE(tmp) != IS_LONG) { convert_to_long(&tmp); } @@ -1090,11 +1085,7 @@ static xmlNodePtr to_xml_double(encodeTypePtr type, zval *data, int style, xmlNo xmlAddChild(parent, ret); FIND_ZVAL_NULL(data, ret, style); - tmp = *data; - if (Z_TYPE(tmp) != IS_DOUBLE) { - zval_copy_ctor(&tmp); - convert_to_double(&tmp); - } + ZVAL_DOUBLE(&tmp, zval_get_double(data)); str = (char *) safe_emalloc(EG(precision), 1, MAX_LENGTH_OF_DOUBLE + 1); php_gcvt(Z_DVAL(tmp), EG(precision), '.', 'E', str); @@ -3032,13 +3023,12 @@ static xmlNodePtr to_xml_list(encodeTypePtr enc, zval *data, int style, xmlNodeP xmlNodeSetContentLen(ret, BAD_CAST(list.s->val), list.s->len); smart_str_free(&list); } else { - zval tmp = *data; + zval tmp; char *str, *start, *next; smart_str list = {0}; if (Z_TYPE_P(data) != IS_STRING) { - zval_copy_ctor(&tmp); - convert_to_string(&tmp); + ZVAL_STR(&tmp, zval_get_string(data)); data = &tmp; } str = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data)); @@ -3144,10 +3134,9 @@ static xmlNodePtr to_xml_any(encodeTypePtr type, zval *data, int style, xmlNodeP if (Z_TYPE_P(data) == IS_STRING) { ret = xmlNewTextLen(BAD_CAST(Z_STRVAL_P(data)), Z_STRLEN_P(data)); } else { - zval tmp = *data; + zval tmp; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); + ZVAL_STR(&tmp, zval_get_string(data)); ret = xmlNewTextLen(BAD_CAST(Z_STRVAL(tmp)), Z_STRLEN(tmp)); zval_dtor(&tmp); } diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 44078733d6..1de8e021dd 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -351,7 +351,9 @@ PHP_FUNCTION(spl_autoload) while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) { ex = ex->prev_execute_data; } - if (ex && ex->opline->opcode != ZEND_FETCH_CLASS) { + if (ex && + ex->opline->opcode != ZEND_FETCH_CLASS && + ex->opline->opcode != ZEND_NEW) { zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Class %s could not be loaded", class_name->val); } else { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s could not be loaded", class_name->val); diff --git a/ext/standard/array.c b/ext/standard/array.c index 98a1c21b3e..57d0065b25 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -728,7 +728,7 @@ static int php_array_user_key_compare(const void *a, const void *b TSRMLS_DC) /* zval_ptr_dtor(&args[0]); zval_ptr_dtor(&args[1]); - return result; + return result < 0 ? -1 : result > 0 ? 1 : 0; } /* }}} */ @@ -1301,9 +1301,10 @@ PHP_FUNCTION(array_search) } /* }}} */ -static int php_valid_var_name(char *var_name, int var_name_len) /* {{{ */ +static int php_valid_var_name(char *var_name, size_t var_name_len) /* {{{ */ { - int i, ch; + size_t i; + int ch; if (!var_name || !var_name_len) { return 0; @@ -1337,7 +1338,7 @@ static int php_valid_var_name(char *var_name, int var_name_len) /* {{{ */ } /* }}} */ -PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, int var_name_len, zend_bool add_underscore TSRMLS_DC) /* {{{ */ +PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, size_t var_name_len, zend_bool add_underscore TSRMLS_DC) /* {{{ */ { ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0) + var_name_len, 0)); memcpy(Z_STRVAL_P(result), Z_STRVAL_P(prefix), Z_STRLEN_P(prefix)); @@ -1569,7 +1570,7 @@ PHP_FUNCTION(array_fill) } /* allocate an array for return */ - array_init_size(return_value, num); + array_init_size(return_value, (uint32_t)num); if (num == 0) { return; @@ -1786,10 +1787,10 @@ err: static void php_array_data_shuffle(zval *array TSRMLS_DC) /* {{{ */ { - uint idx; + uint32_t idx, j, n_elems; Bucket *p, temp; HashTable *hash; - int j, n_elems, rnd_idx, n_left; + zend_long rnd_idx, n_left; n_elems = zend_hash_num_elements(Z_ARRVAL_P(array)); @@ -2222,7 +2223,7 @@ PHP_FUNCTION(array_splice) /* Don't create the array of removed elements if it's not going * to be used; e.g. only removing and/or replacing elements */ if (USED_RET()) { - int size = length; + zend_long size = length; /* Clamp the offset.. */ if (offset > num_in) { @@ -2234,17 +2235,17 @@ PHP_FUNCTION(array_splice) /* ..and the length */ if (length < 0) { size = num_in - offset + length; - } else if (((zend_ulong) offset + (zend_ulong) length) > (unsigned) num_in) { + } else if (((zend_ulong) offset + (zend_ulong) length) > (uint32_t) num_in) { size = num_in - offset; } /* Initialize return value */ - array_init_size(return_value, size > 0 ? size : 0); + array_init_size(return_value, size > 0 ? (uint32_t)size : 0); rem_hash = Z_ARRVAL_P(return_value); } /* Perform splice */ - new_hash = php_splice(Z_ARRVAL_P(array), offset, length, repl, repl_num, rem_hash); + new_hash = php_splice(Z_ARRVAL_P(array), (int)offset, (int)length, repl, (int)repl_num, rem_hash); /* Replace input array's hashtable with the new one */ old_hash = *Z_ARRVAL_P(array); @@ -2314,7 +2315,7 @@ PHP_FUNCTION(array_slice) } /* Initialize returned array */ - array_init_size(return_value, length > 0 ? length : 0); + array_init_size(return_value, length > 0 ? (uint32_t)length : 0); if (length <= 0) { return; @@ -2897,9 +2898,9 @@ PHP_FUNCTION(array_pad) /* Pad on the right or on the left */ if (pad_size > 0) { - new_hash = php_splice(Z_ARRVAL_P(return_value), input_size, 0, pads, num_pads, NULL); + new_hash = php_splice(Z_ARRVAL_P(return_value), (int)input_size, 0, pads, (int)num_pads, NULL); } else { - new_hash = php_splice(Z_ARRVAL_P(return_value), 0, 0, pads, num_pads, NULL); + new_hash = php_splice(Z_ARRVAL_P(return_value), 0, 0, pads, (int)num_pads, NULL); } /* Copy the result hash into return value */ @@ -3971,22 +3972,23 @@ PHPAPI int php_multisort_compare(const void *a, const void *b TSRMLS_DC) /* {{{ Bucket *ab = *(Bucket **)a; Bucket *bb = *(Bucket **)b; int r; - int result = 0; + zend_long result; zval temp; r = 0; do { + php_set_compare_func(ARRAYG(multisort_flags)[MULTISORT_TYPE][r] TSRMLS_CC); ARRAYG(compare_func)(&temp, &ab[r].val, &bb[r].val TSRMLS_CC); result = ARRAYG(multisort_flags)[MULTISORT_ORDER][r] * Z_LVAL(temp); if (result != 0) { - return result; + return result > 0 ? 1 : -1; } r++; } while (Z_TYPE(ab[r].val) != IS_UNDEF); - return result; + return 0; } /* }}} */ @@ -4077,7 +4079,7 @@ PHP_FUNCTION(array_multisort) /* flag allowed here */ if (parse_state[MULTISORT_TYPE] == 1) { /* Save the flag and make sure then next arg is not the current flag. */ - sort_type = Z_LVAL(args[i]); + sort_type = (int)Z_LVAL(args[i]); parse_state[MULTISORT_TYPE] = 0; } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1); @@ -4205,7 +4207,7 @@ PHP_FUNCTION(array_rand) /* Make the return value an array only if we need to pass back more than one result. */ if (num_req > 1) { - array_init_size(return_value, num_req); + array_init_size(return_value, (uint32_t)num_req); } /* We can't use zend_hash_index_find() because the array may have string keys or gaps. */ @@ -4690,14 +4692,14 @@ PHP_FUNCTION(array_chunk) size = num_in > 0 ? num_in : 1; } - array_init_size(return_value, ((num_in - 1) / size) + 1); + array_init_size(return_value, (uint32_t)(((num_in - 1) / size) + 1)); ZVAL_UNDEF(&chunk); ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, str_key, entry) { /* If new chunk, create and initialize it. */ if (Z_TYPE(chunk) == IS_UNDEF) { - array_init_size(&chunk, size); + array_init_size(&chunk, (uint32_t)size); } /* Add entry to the chunk, preserving keys if necessary. */ diff --git a/ext/standard/assert.c b/ext/standard/assert.c index efb708d4a9..9fa5a1178c 100644 --- a/ext/standard/assert.c +++ b/ext/standard/assert.c @@ -25,12 +25,12 @@ /* }}} */ ZEND_BEGIN_MODULE_GLOBALS(assert) - zend_long active; - zend_long bail; - zend_long warning; - zend_long quiet_eval; zval callback; char *cb; + zend_bool active; + zend_bool bail; + zend_bool warning; + zend_bool quiet_eval; ZEND_END_MODULE_GLOBALS(assert) ZEND_DECLARE_MODULE_GLOBALS(assert) @@ -78,11 +78,11 @@ static PHP_INI_MH(OnChangeCallback) /* {{{ */ /* }}} */ PHP_INI_BEGIN() - STD_PHP_INI_ENTRY("assert.active", "1", PHP_INI_ALL, OnUpdateLong, active, zend_assert_globals, assert_globals) - STD_PHP_INI_ENTRY("assert.bail", "0", PHP_INI_ALL, OnUpdateLong, bail, zend_assert_globals, assert_globals) - STD_PHP_INI_ENTRY("assert.warning", "1", PHP_INI_ALL, OnUpdateLong, warning, zend_assert_globals, assert_globals) + STD_PHP_INI_ENTRY("assert.active", "1", PHP_INI_ALL, OnUpdateBool, active, zend_assert_globals, assert_globals) + STD_PHP_INI_ENTRY("assert.bail", "0", PHP_INI_ALL, OnUpdateBool, bail, zend_assert_globals, assert_globals) + STD_PHP_INI_ENTRY("assert.warning", "1", PHP_INI_ALL, OnUpdateBool, warning, zend_assert_globals, assert_globals) PHP_INI_ENTRY("assert.callback", NULL, PHP_INI_ALL, OnChangeCallback) - STD_PHP_INI_ENTRY("assert.quiet_eval", "0", PHP_INI_ALL, OnUpdateLong, quiet_eval, zend_assert_globals, assert_globals) + STD_PHP_INI_ENTRY("assert.quiet_eval", "0", PHP_INI_ALL, OnUpdateBool, quiet_eval, zend_assert_globals, assert_globals) PHP_INI_END() static void php_assert_init_globals(zend_assert_globals *assert_globals_p TSRMLS_DC) /* {{{ */ @@ -258,7 +258,7 @@ PHP_FUNCTION(assert_options) { zval *value = NULL; zend_long what; - int oldint; + zend_bool oldint; int ac = ZEND_NUM_ARGS(); zend_string *key; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 5bcd3d3386..106bc54141 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -3952,7 +3952,7 @@ PHP_FUNCTION(long2ip) /* "It's a long but it's not, PHP ints are signed */ char *ip; size_t ip_len; - zend_ulong n; + uint32_t n; struct in_addr myaddr; #ifdef HAVE_INET_PTON char str[40]; @@ -4076,7 +4076,7 @@ PHP_FUNCTION(putenv) #endif } - pe.key_len = strlen(pe.key); + pe.key_len = (int)strlen(pe.key); #ifdef PHP_WIN32 if (equals) { if (pe.key_len < setting_len - 1) { @@ -4289,7 +4289,7 @@ PHP_FUNCTION(getopt) opts->need_param = 0; opts->opt_name = estrdup(arg_str->val); - len = strlen(opts->opt_name); + len = (int)strlen(opts->opt_name); if ((len > 0) && (opts->opt_name[len - 1] == ':')) { opts->need_param++; opts->opt_name[len - 1] = '\0'; @@ -4345,7 +4345,7 @@ PHP_FUNCTION(getopt) } /* Add this option / argument pair to the result hash. */ - optname_len = strlen(optname); + optname_len = (int)strlen(optname); if (!(optname_len > 1 && optname[0] == '0') && is_numeric_string(optname, optname_len, NULL, NULL, 0) == IS_LONG) { /* numeric string */ int optname_int = atoi(optname); @@ -4400,9 +4400,9 @@ PHP_FUNCTION(sleep) RETURN_FALSE; } #ifdef PHP_SLEEP_NON_VOID - RETURN_LONG(php_sleep(num)); + RETURN_LONG(php_sleep((unsigned int)num)); #else - php_sleep(num); + php_sleep((unsigned int)num); #endif } @@ -4422,7 +4422,7 @@ PHP_FUNCTION(usleep) php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of microseconds must be greater than or equal to 0"); RETURN_FALSE; } - usleep(num); + usleep((unsigned int)num); #endif } /* }}} */ @@ -4449,7 +4449,7 @@ PHP_FUNCTION(time_nanosleep) } php_req.tv_sec = (time_t) tv_sec; - php_req.tv_nsec = tv_nsec; + php_req.tv_nsec = (long)tv_nsec; if (!nanosleep(&php_req, &php_rem)) { RETURN_TRUE; } else if (errno == EINTR) { @@ -4554,7 +4554,7 @@ PHP_FUNCTION(get_cfg_var) return; } - retval = cfg_get_entry(varname, varname_len); + retval = cfg_get_entry(varname, (uint)varname_len); if (retval) { if (Z_TYPE_P(retval) == IS_ARRAY) { @@ -4637,7 +4637,7 @@ PHP_FUNCTION(error_log) } if (argc > 1) { - opt_err = erropt; + opt_err = (int)erropt; } if (_php_error_log_ex(opt_err, message, message_len, opt, headers TSRMLS_CC) == FAILURE) { @@ -4655,7 +4655,7 @@ PHPAPI int _php_error_log(int opt_err, char *message, char *opt, char *headers T } /* }}} */ -PHPAPI int _php_error_log_ex(int opt_err, char *message, int message_len, char *opt, char *headers TSRMLS_DC) /* {{{ */ +PHPAPI int _php_error_log_ex(int opt_err, char *message, size_t message_len, char *opt, char *headers TSRMLS_DC) /* {{{ */ { php_stream *stream = NULL; @@ -5212,7 +5212,7 @@ PHP_FUNCTION(ini_get) return; } - str = zend_ini_string(varname, varname_len, 0); + str = zend_ini_string(varname, (uint)varname_len, 0); if (!str) { RETURN_FALSE; @@ -5322,7 +5322,7 @@ PHP_FUNCTION(ini_set) return; } - old_value = zend_ini_string(varname->val, varname->len, 0); + old_value = zend_ini_string(varname->val, (int)varname->len, 0); /* copy to return here, because alter might free it! */ if (old_value) { @@ -5331,7 +5331,7 @@ PHP_FUNCTION(ini_set) RETVAL_FALSE; } -#define _CHECK_PATH(var, var_len, ini) php_ini_check_path(var, var_len, ini, sizeof(ini)) +#define _CHECK_PATH(var, var_len, ini) php_ini_check_path(var, (int)var_len, ini, sizeof(ini)) /* open basedir check */ if (PG(open_basedir)) { if (_CHECK_PATH(varname->val, varname->len, "error_log") || @@ -5592,7 +5592,7 @@ PHP_FUNCTION(getprotobynumber) return; } - ent = getprotobynumber(proto); + ent = getprotobynumber((int)proto); if (ent == NULL) { RETURN_FALSE; @@ -5790,7 +5790,7 @@ static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int cal } if (!(Z_STRLEN_P(arg1) > 1 && Z_STRVAL_P(arg1)[0] == '0') && is_numeric_string(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), NULL, NULL, 0) == IS_LONG) { - zend_ulong key = (zend_ulong) zend_atol(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1)); + zend_ulong key = (zend_ulong) zend_atol(Z_STRVAL_P(arg1), (int)Z_STRLEN_P(arg1)); if ((find_hash = zend_hash_index_find(Z_ARRVAL_P(arr), key)) == NULL) { array_init(&hash); find_hash = zend_hash_index_update(Z_ARRVAL_P(arr), key, &hash); @@ -5878,7 +5878,7 @@ PHP_FUNCTION(parse_ini_file) fh.type = ZEND_HANDLE_FILENAME; array_init(return_value); - if (zend_parse_ini_file(&fh, 0, scanner_mode, ini_parser_cb, return_value TSRMLS_CC) == FAILURE) { + if (zend_parse_ini_file(&fh, 0, (int)scanner_mode, ini_parser_cb, return_value TSRMLS_CC) == FAILURE) { zval_dtor(return_value); RETURN_FALSE; } @@ -5917,7 +5917,7 @@ PHP_FUNCTION(parse_ini_string) memset(string + str_len, 0, ZEND_MMAP_AHEAD); array_init(return_value); - if (zend_parse_ini_string(string, 0, scanner_mode, ini_parser_cb, return_value TSRMLS_CC) == FAILURE) { + if (zend_parse_ini_string(string, 0, (int)scanner_mode, ini_parser_cb, return_value TSRMLS_CC) == FAILURE) { zval_dtor(return_value); RETVAL_FALSE; } diff --git a/ext/standard/basic_functions.h b/ext/standard/basic_functions.h index 1c142af842..815227118e 100644 --- a/ext/standard/basic_functions.h +++ b/ext/standard/basic_functions.h @@ -142,8 +142,8 @@ PHP_RSHUTDOWN_FUNCTION(browscap); /* Left for BC (not binary safe!) */ PHPAPI int _php_error_log(int opt_err, char *message, char *opt, char *headers TSRMLS_DC); -PHPAPI int _php_error_log_ex(int opt_err, char *message, int message_len, char *opt, char *headers TSRMLS_DC); -PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, int var_name_len, zend_bool add_underscore TSRMLS_DC); +PHPAPI int _php_error_log_ex(int opt_err, char *message, size_t message_len, char *opt, char *headers TSRMLS_DC); +PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, size_t var_name_len, zend_bool add_underscore TSRMLS_DC); #if SIZEOF_INT == 4 /* Most 32-bit and 64-bit systems have 32-bit ints */ diff --git a/ext/standard/crypt.c b/ext/standard/crypt.c index 9599e2f056..7fae04fcbf 100644 --- a/ext/standard/crypt.c +++ b/ext/standard/crypt.c @@ -295,7 +295,7 @@ PHP_FUNCTION(crypt) } salt[salt_in_len] = '\0'; - if ((result = php_crypt(str, str_len, salt, salt_in_len)) == NULL) { + if ((result = php_crypt(str, (int)str_len, salt, (int)salt_in_len)) == NULL) { if (salt[0] == '*' && salt[1] == '0') { RETURN_STRING("*1"); } else { diff --git a/ext/standard/crypt_sha256.c b/ext/standard/crypt_sha256.c index 5f28bd7b9f..d79d14510a 100644 --- a/ext/standard/crypt_sha256.c +++ b/ext/standard/crypt_sha256.c @@ -120,7 +120,7 @@ static void sha256_process_block (const void *buffer, size_t len, struct sha256_ /* First increment the byte count. FIPS 180-2 specifies the possible length of the file up to 2^64 bits. Here we only compute the number of bytes. Do a double word increment. */ - ctx->total[0] += len; + ctx->total[0] += (uint32_t)len; if (ctx->total[0] < len) { ++ctx->total[1]; } @@ -261,7 +261,7 @@ static void sha256_process_bytes(const void *buffer, size_t len, struct sha256_c size_t add = 128 - left_over > len ? len : 128 - left_over; memcpy(&ctx->buffer[left_over], buffer, add); - ctx->buflen += add; + ctx->buflen += (uint32_t)add; if (ctx->buflen > 64) { sha256_process_block(ctx->buffer, ctx->buflen & ~63, ctx); @@ -306,7 +306,7 @@ compilers don't. */ left_over -= 64; memcpy(ctx->buffer, &ctx->buffer[64], left_over); } - ctx->buflen = left_over; + ctx->buflen = (uint32_t)left_over; } } @@ -529,7 +529,7 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b } cp = __php_stpncpy(cp, salt, MIN ((size_t) MAX (0, buflen), salt_len)); - buflen -= MIN((size_t) MAX (0, buflen), salt_len); + buflen -= MIN(MAX (0, buflen), (int)salt_len); if (buflen > 0) { *cp++ = '$'; @@ -600,7 +600,7 @@ char * php_sha256_crypt(const char *key, const char *salt) static int buflen; int needed = (sizeof(sha256_salt_prefix) - 1 + sizeof(sha256_rounds_prefix) + 9 + 1 - + strlen(salt) + 1 + 43 + 1); + + (int)strlen(salt) + 1 + 43 + 1); if (buflen < needed) { char *new_buffer = (char *) realloc(buffer, needed); diff --git a/ext/standard/dir.c b/ext/standard/dir.c index 6f4c70ebba..b0be40ee35 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -87,7 +87,7 @@ static zend_class_entry *dir_class_entry_ptr; } \ ZEND_FETCH_RESOURCE(dirp, php_stream *, tmp, -1, "Directory", php_file_le_stream()); \ } else { \ - ZEND_FETCH_RESOURCE(dirp, php_stream *, 0, DIRG(default_dir)->handle, "Directory", php_file_le_stream()); \ + ZEND_FETCH_RESOURCE(dirp, php_stream *, 0, (int)DIRG(default_dir)->handle, "Directory", php_file_le_stream()); \ } \ } else { \ dirp = (php_stream *) zend_fetch_resource(id TSRMLS_CC, -1, "Directory", NULL, 1, php_file_le_stream()); \ @@ -463,7 +463,7 @@ PHP_FUNCTION(glob) cwd[2] = '\0'; } #endif - cwd_skip = strlen(cwd)+1; + cwd_skip = (int)strlen(cwd)+1; snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern); pattern = work_pattern; diff --git a/ext/standard/dl.c b/ext/standard/dl.c index 6ea69e5b81..a9ca94c0ad 100644 --- a/ext/standard/dl.c +++ b/ext/standard/dl.c @@ -129,7 +129,7 @@ PHPAPI int php_load_extension(char *filename, int type, int start_now TSRMLS_DC) } libpath = estrdup(filename); } else if (extension_dir && extension_dir[0]) { - int extension_dir_len = strlen(extension_dir); + int extension_dir_len = (int)strlen(extension_dir); if (IS_SLASH(extension_dir[extension_dir_len-1])) { spprintf(&libpath, 0, "%s%s", extension_dir, filename); /* SAFE */ diff --git a/ext/standard/dns_win32.c b/ext/standard/dns_win32.c index 865ad30b3e..963d1f7a54 100644 --- a/ext/standard/dns_win32.c +++ b/ext/standard/dns_win32.c @@ -208,7 +208,7 @@ static void php_parserr(PDNS_RECORD pRec, int type_to_fetch, int store, int raw, DWORD count = data_txt->dwStringCount; zend_string *txt; char *txt_dst; - long txt_len = 0; + size_t txt_len = 0; zval entries; add_assoc_string(subarray, "type", "TXT"); @@ -222,7 +222,7 @@ static void php_parserr(PDNS_RECORD pRec, int type_to_fetch, int store, int raw, txt = zend_string_safe_alloc(txt_len, 2, 0, 0); txt_dst = txt->val; for (i = 0; i < count; i++) { - int len = strlen(data_txt->pStringArray[i]); + size_t len = strlen(data_txt->pStringArray[i]); memcpy(txt_dst, data_txt->pStringArray[i], len); add_next_index_stringl(&entries, data_txt->pStringArray[i], len); txt_dst += len; diff --git a/ext/standard/exec.c b/ext/standard/exec.c index 28f01b338f..6106fe2c86 100644 --- a/ext/standard/exec.c +++ b/ext/standard/exec.c @@ -61,7 +61,8 @@ PHPAPI int php_exec(int type, char *cmd, zval *array, zval *return_value TSRMLS_ { FILE *fp; char *buf; - int l = 0, pclose_return; + size_t l = 0; + int pclose_return; char *b, *d=NULL; php_stream *stream; size_t buflen, bufl = 0; @@ -115,8 +116,8 @@ PHPAPI int php_exec(int type, char *cmd, zval *array, zval *return_value TSRMLS_ } else if (type == 2) { /* strip trailing whitespaces */ l = bufl; - while (l-- && isspace(((unsigned char *)buf)[l])); - if (l != (int)(bufl - 1)) { + while (l >= 1 && l-- && isspace(((unsigned char *)buf)[l])); + if (l != (bufl - 1)) { bufl = l + 1; buf[bufl] = '\0'; } @@ -128,8 +129,8 @@ PHPAPI int php_exec(int type, char *cmd, zval *array, zval *return_value TSRMLS_ /* strip trailing whitespaces if we have not done so already */ if ((type == 2 && buf != b) || type != 2) { l = bufl; - while (l-- && isspace(((unsigned char *)buf)[l])); - if (l != (int)(bufl - 1)) { + while (l >= 1 && l-- && isspace(((unsigned char *)buf)[l])); + if (l != (bufl - 1)) { bufl = l + 1; buf[bufl] = '\0'; } @@ -240,7 +241,7 @@ PHP_FUNCTION(passthru) */ PHPAPI zend_string *php_escape_shell_cmd(char *str) { - register int x, y, l = strlen(str); + register int x, y, l = (int)strlen(str); char *p = NULL; size_t estimate = (2 * l) + 1; zend_string *cmd; @@ -333,7 +334,7 @@ PHPAPI zend_string *php_escape_shell_cmd(char *str) */ PHPAPI zend_string *php_escape_shell_arg(char *str) { - int x, y = 0, l = strlen(str); + int x, y = 0, l = (int)strlen(str); zend_string *cmd; size_t estimate = (4 * l) + 3; diff --git a/ext/standard/file.c b/ext/standard/file.c index 446da20fb3..ff7c5433eb 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -1098,7 +1098,7 @@ PHPAPI PHP_FUNCTION(fgetss) php_stream *stream; zend_string *allowed = NULL; char *allowed_tags=NULL; - int allowed_tags_len=0; + size_t allowed_tags_len=0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|lS", &fd, &bytes, &allowed) == FAILURE) { RETURN_FALSE; @@ -1196,8 +1196,8 @@ PHPAPI PHP_FUNCTION(fwrite) zval *arg1; char *arg2; size_t arg2len; - int ret; - int num_bytes; + size_t ret; + size_t num_bytes; zend_long arg3 = 0; char *buffer = NULL; php_stream *stream; @@ -1309,7 +1309,7 @@ PHPAPI PHP_FUNCTION(fseek) PHP_STREAM_TO_ZVAL(stream, arg1); - RETURN_LONG(php_stream_seek(stream, arg2, whence)); + RETURN_LONG(php_stream_seek(stream, arg2, (int)whence)); } /* }}} */ @@ -1355,7 +1355,7 @@ PHP_FUNCTION(mkdir) context = php_stream_context_from_zval(zcontext, 0); - RETURN_BOOL(php_stream_mkdir(dir, mode, (recursive ? PHP_STREAM_MKDIR_RECURSIVE : 0) | REPORT_ERRORS, context)); + RETURN_BOOL(php_stream_mkdir(dir, (int)mode, (recursive ? PHP_STREAM_MKDIR_RECURSIVE : 0) | REPORT_ERRORS, context)); } /* }}} */ @@ -1384,7 +1384,7 @@ PHP_FUNCTION(readfile) { char *filename; size_t filename_len; - int size = 0; + size_t size = 0; zend_bool use_include_path = 0; zval *zcontext = NULL; php_stream *stream; @@ -1427,7 +1427,7 @@ PHP_FUNCTION(umask) if (ZEND_NUM_ARGS() == 0) { umask(oldumask); } else { - umask(arg1); + umask((int)arg1); } RETURN_LONG(oldumask); @@ -1439,7 +1439,7 @@ PHP_FUNCTION(umask) PHPAPI PHP_FUNCTION(fpassthru) { zval *arg1; - int size; + size_t size; php_stream *stream; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) { @@ -1852,7 +1852,7 @@ PHP_FUNCTION(fputcsv) char escape_char = '\\'; /* allow this to be set as parameter */ php_stream *stream; zval *fp = NULL, *fields = NULL; - int ret; + size_t ret; char *delimiter_str = NULL, *enclosure_str = NULL, *escape_str = NULL; size_t delimiter_str_len = 0, enclosure_str_len = 0, escape_str_len = 0; @@ -1908,7 +1908,8 @@ PHP_FUNCTION(fputcsv) /* {{{ PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, char escape_char TSRMLS_DC) */ PHPAPI size_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, char enclosure, char escape_char TSRMLS_DC) { - int count, i = 0, ret; + int count, i = 0; + size_t ret; zval *field_tmp; smart_str csvline = {0}; @@ -2486,7 +2487,7 @@ PHP_FUNCTION(fnmatch) RETURN_FALSE; } - RETURN_BOOL( ! fnmatch( pattern, filename, flags )); + RETURN_BOOL( ! fnmatch( pattern, filename, (int)flags )); } /* }}} */ #endif diff --git a/ext/standard/filestat.c b/ext/standard/filestat.c index 6a06a55d94..53aede1469 100644 --- a/ext/standard/filestat.c +++ b/ext/standard/filestat.c @@ -835,7 +835,7 @@ PHP_FUNCTION(clearstatcache) return; } - php_clear_stat_cache(clear_realpath_cache, filename, filename_len TSRMLS_CC); + php_clear_stat_cache(clear_realpath_cache, filename, (int)filename_len TSRMLS_CC); } /* }}} */ diff --git a/ext/standard/filters.c b/ext/standard/filters.c index f0f49950bb..3fd27afa43 100644 --- a/ext/standard/filters.c +++ b/ext/standard/filters.c @@ -176,14 +176,14 @@ typedef struct _php_strip_tags_filter { int persistent; } php_strip_tags_filter; -static int php_strip_tags_filter_ctor(php_strip_tags_filter *inst, const char *allowed_tags, int allowed_tags_len, int persistent) +static int php_strip_tags_filter_ctor(php_strip_tags_filter *inst, const char *allowed_tags, size_t allowed_tags_len, int persistent) { if (allowed_tags != NULL) { if (NULL == (inst->allowed_tags = pemalloc(allowed_tags_len, persistent))) { return FAILURE; } memcpy((char *)inst->allowed_tags, allowed_tags, allowed_tags_len); - inst->allowed_tags_len = allowed_tags_len; + inst->allowed_tags_len = (int)allowed_tags_len; } else { inst->allowed_tags = NULL; } @@ -861,7 +861,8 @@ static php_conv_err_t php_conv_qprint_encode_convert(php_conv_qprint_encode *ins /* Check to see if this is EOL whitespace. */ if (inst->lbchars != NULL) { unsigned char *ps2; - unsigned int j, lb_cnt2; + unsigned int lb_cnt2; + size_t j; lb_cnt2 = 0; ps2 = ps; @@ -1265,7 +1266,7 @@ static php_conv_err_t php_conv_get_ulong_prop_ex(const HashTable *ht, zend_ulong zval tmp; if (Z_TYPE_P(tmpval) != IS_LONG) { - ZVAL_DUP(&tmp, tmpval);; + ZVAL_DUP(&tmp, tmpval); convert_to_long(&tmp); tmpval = &tmp; } @@ -1318,6 +1319,7 @@ static int php_conv_get_int_prop_ex(const HashTable *ht, int *pretval, char *fie } #endif +/* XXX this might need an additional fix so it uses size_t, whereby unsigned is quite big so leaving as is for now */ static int php_conv_get_uint_prop_ex(const HashTable *ht, unsigned int *pretval, char *field_name, size_t field_name_len) { zend_ulong l; @@ -1326,7 +1328,7 @@ static int php_conv_get_uint_prop_ex(const HashTable *ht, unsigned int *pretval, *pretval = 0; if ((err = php_conv_get_ulong_prop_ex(ht, &l, field_name, field_name_len)) == PHP_CONV_ERR_SUCCESS) { - *pretval = l; + *pretval = (unsigned int)l; } return err; } @@ -1931,12 +1933,12 @@ typedef struct _php_chunked_filter_data { int persistent; } php_chunked_filter_data; -static int php_dechunk(char *buf, int len, php_chunked_filter_data *data) +static size_t php_dechunk(char *buf, size_t len, php_chunked_filter_data *data) { char *p = buf; char *end = p + len; char *out = buf; - int out_len = 0; + size_t out_len = 0; while (p < end) { switch (data->state) { diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index 8f211d0236..f84075440b 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -376,7 +376,7 @@ php_formatted_print(int param_count, int use_array, int format_offset TSRMLS_DC) char *format, padding; zend_string *result; int always_sign; - int format_len; + size_t format_len; if (zend_parse_parameters(param_count TSRMLS_CC, "+", &args, &argc) == FAILURE) { return NULL; diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c index 090d3f8f32..30a6fda5d6 100644 --- a/ext/standard/fsock.c +++ b/ext/standard/fsock.c @@ -35,14 +35,18 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) size_t host_len; zend_long port = -1; zval *zerrno = NULL, *zerrstr = NULL; - double timeout = FG(default_socket_timeout); - zend_ulong conv; + double timeout = (double)FG(default_socket_timeout); +#ifndef PHP_WIN32 + time_t conv; +#else + long conv; +#endif struct timeval tv; char *hashkey = NULL; php_stream *stream = NULL; int err; char *hostname = NULL; - zend_long hostname_len; + size_t hostname_len; zend_string *errstr = NULL; RETVAL_FALSE; @@ -63,8 +67,13 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) } /* prepare the timeout value for use */ - conv = (unsigned long) (timeout * 1000000.0); +#ifndef PHP_WIN32 + conv = (time_t) (timeout * 1000000.0); tv.tv_sec = conv / 1000000; +#else + conv = (long) (timeout * 1000000.0); + tv.tv_sec = conv / 1000000; +#endif tv.tv_usec = conv % 1000000; if (zerrno) { diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 2bf4e02a41..ed93345bac 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -155,7 +155,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char if (resource->port == 0) resource->port = 21; - transport_len = spprintf(&transport, 0, "tcp://%s:%d", resource->host, resource->port); + transport_len = (int)spprintf(&transport, 0, "tcp://%s:%d", resource->host, resource->port); stream = php_stream_xport_create(transport, transport_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, NULL, NULL, context, NULL, NULL); efree(transport); if (stream == NULL) { @@ -245,7 +245,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char /* send the user name */ if (resource->user != NULL) { - tmp_len = php_raw_url_decode(resource->user, strlen(resource->user)); + tmp_len = (int)php_raw_url_decode(resource->user, (int)strlen(resource->user)); PHP_FTP_CNTRL_CHK(resource->user, tmp_len, "Invalid login %s") @@ -262,7 +262,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, tmp_line, 0); if (resource->pass != NULL) { - tmp_len = php_raw_url_decode(resource->pass, strlen(resource->pass)); + tmp_len = (int)php_raw_url_decode(resource->pass, (int)strlen(resource->pass)); PHP_FTP_CNTRL_CHK(resource->pass, tmp_len, "Invalid password %s") @@ -424,8 +424,8 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa php_stream *reuseid=NULL; size_t file_size = 0; zval *tmpzval; - int allow_overwrite = 0; - int read_write = 0; + zend_bool allow_overwrite = 0; + int8_t read_write = 0; char *transport; int transport_len; @@ -498,7 +498,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa } else if (read_write == 2) { /* when writing file (but not appending), it must NOT exist, unless a context option exists which allows it */ if (context && (tmpzval = php_stream_context_get_option(context, "ftp", "overwrite")) != NULL) { - allow_overwrite = Z_LVAL_P(tmpzval); + allow_overwrite = Z_LVAL_P(tmpzval) ? 1 : 0; } if (result <= 299 && result >= 200) { if (allow_overwrite) { @@ -554,7 +554,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa if (hoststart == NULL) { hoststart = resource->host; } - transport_len = spprintf(&transport, 0, "tcp://%s:%d", hoststart, portno); + transport_len = (int)spprintf(&transport, 0, "tcp://%s:%d", hoststart, portno); datastream = php_stream_xport_create(transport, transport_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, NULL, NULL, context, NULL, NULL); efree(transport); if (datastream == NULL) { @@ -855,7 +855,7 @@ static int php_stream_ftp_url_stat(php_stream_wrapper *wrapper, const char *url, gmt->tm_isdst = -1; /* apply the GMT offset */ - tm.tm_sec += stamp - mktime(gmt); + tm.tm_sec += (long)(stamp - mktime(gmt)); tm.tm_isdst = gmt->tm_isdst; ssb->sb.st_mtime = mktime(&tm); diff --git a/ext/standard/head.c b/ext/standard/head.c index 3dd18ee0fd..1417b52bc0 100644 --- a/ext/standard/head.c +++ b/ext/standard/head.c @@ -73,10 +73,10 @@ PHPAPI int php_header(TSRMLS_D) } -PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, time_t expires, char *path, int path_len, char *domain, int domain_len, int secure, int url_encode, int httponly TSRMLS_DC) +PHPAPI int php_setcookie(char *name, size_t name_len, char *value, size_t value_len, time_t expires, char *path, size_t path_len, char *domain, size_t domain_len, int secure, int url_encode, int httponly TSRMLS_DC) { char *cookie; - int len=sizeof("Set-Cookie: "); + size_t len=sizeof("Set-Cookie: "); zend_string *dt; sapi_header_line ctr = {0}; int result; @@ -164,7 +164,7 @@ PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, t } ctr.line = cookie; - ctr.line_len = strlen(cookie); + ctr.line_len = (uint)strlen(cookie); result = sapi_header_op(SAPI_HEADER_ADD, &ctr TSRMLS_CC); efree(cookie); @@ -300,7 +300,7 @@ PHP_FUNCTION(http_response_code) zend_long old_response_code; old_response_code = SG(sapi_headers).http_response_code; - SG(sapi_headers).http_response_code = response_code; + SG(sapi_headers).http_response_code = (int)response_code; if (old_response_code) { RETURN_LONG(old_response_code); diff --git a/ext/standard/head.h b/ext/standard/head.h index e32810a6f3..850a71dc74 100644 --- a/ext/standard/head.h +++ b/ext/standard/head.h @@ -38,6 +38,6 @@ PHP_FUNCTION(headers_list); PHP_FUNCTION(http_response_code); PHPAPI int php_header(TSRMLS_D); -PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, time_t expires, char *path, int path_len, char *domain, int domain_len, int secure, int url_encode, int httponly TSRMLS_DC); +PHPAPI int php_setcookie(char *name, size_t name_len, char *value, size_t value_len, time_t expires, char *path, size_t path_len, char *domain, size_t domain_len, int secure, int url_encode, int httponly TSRMLS_DC); #endif diff --git a/ext/standard/html.c b/ext/standard/html.c index dfe30d9b3e..516bcc4ef7 100644 --- a/ext/standard/html.c +++ b/ext/standard/html.c @@ -377,7 +377,7 @@ static enum entity_charset determine_charset(char *charset_hint TSRMLS_DC) { int i; enum entity_charset charset = cs_utf_8; - int len = 0; + size_t len = 0; const zend_encoding *zenc; /* Default is now UTF-8 */ @@ -1513,7 +1513,7 @@ PHP_FUNCTION(htmlspecialchars_decode) return; } - replaced = php_unescape_html_entities((unsigned char*)str, str_len, 0 /*!all*/, quote_style, NULL TSRMLS_CC); + replaced = php_unescape_html_entities((unsigned char*)str, str_len, 0 /*!all*/, (int)quote_style, NULL TSRMLS_CC); if (replaced) { RETURN_STR(replaced); } @@ -1547,7 +1547,7 @@ PHP_FUNCTION(html_entity_decode) if (!hint_charset) { default_charset = get_default_charset(TSRMLS_C); } - replaced = php_unescape_html_entities((unsigned char*)str->val, str->len, 1 /*all*/, quote_style, (hint_charset ? hint_charset->val : default_charset) TSRMLS_CC); + replaced = php_unescape_html_entities((unsigned char*)str->val, str->len, 1 /*all*/, (int)quote_style, (hint_charset ? hint_charset->val : default_charset) TSRMLS_CC); if (replaced) { RETURN_STR(replaced); @@ -1649,7 +1649,7 @@ PHP_FUNCTION(get_html_translation_table) array_init(return_value); - entity_table = determine_entity_table(all, doctype); + entity_table = determine_entity_table((int)all, doctype); if (all && !CHARSET_UNICODE_COMPAT(charset)) { to_uni_table = enc_to_uni_index[charset]; } diff --git a/ext/standard/http.c b/ext/standard/http.c index 9174163b7d..e5ba87d870 100644 --- a/ext/standard/http.c +++ b/ext/standard/http.c @@ -26,9 +26,9 @@ /* {{{ php_url_encode_hash */ PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, - const char *num_prefix, int num_prefix_len, - const char *key_prefix, int key_prefix_len, - const char *key_suffix, int key_suffix_len, + const char *num_prefix, size_t num_prefix_len, + const char *key_prefix, size_t key_prefix_len, + const char *key_suffix, size_t key_suffix_len, zval *type, char *arg_sep, int enc_type TSRMLS_DC) { zend_string *key = NULL; @@ -107,7 +107,7 @@ PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, *p = '\0'; } else { char *ekey; - int ekey_len; + size_t ekey_len; /* Is an integer key */ ekey_len = spprintf(&ekey, 0, "%pd", idx); newprefix_len = key_prefix_len + num_prefix_len + ekey_len + key_suffix_len + 3 /* %5B */; @@ -194,7 +194,7 @@ PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, case IS_DOUBLE: { char *ekey; - int ekey_len; + size_t ekey_len; ekey_len = spprintf(&ekey, 0, "%.*G", (int) EG(precision), Z_DVAL_P(zdata)); smart_str_appendl(formstr, ekey, ekey_len); efree(ekey); @@ -242,7 +242,7 @@ PHP_FUNCTION(http_build_query) RETURN_FALSE; } - if (php_url_encode_hash_ex(HASH_OF(formdata), &formstr, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL), arg_sep, enc_type TSRMLS_CC) == FAILURE) { + if (php_url_encode_hash_ex(HASH_OF(formdata), &formstr, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL), arg_sep, (int)enc_type TSRMLS_CC) == FAILURE) { if (formstr.s) { smart_str_free(&formstr); } diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 27c6cf6248..e1f8653c8d 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -121,7 +121,7 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, char *tmp = NULL; char *ua_str = NULL; zval *ua_zval = NULL, *tmpzval = NULL, ssl_proxy_peer_name; - int scratch_len = 0; + size_t scratch_len = 0; int body = 0; char location[HTTP_HEADER_BLOCK_SIZE]; zval *response_header = NULL; @@ -132,14 +132,16 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, int eol_detect = 0; char *transport_string; zend_string *errstr = NULL; - int transport_len, have_header = 0, request_fulluri = 0, ignore_errors = 0; + size_t transport_len; + int have_header = 0; + zend_bool request_fulluri = 0, ignore_errors = 0; char *protocol_version = NULL; int protocol_version_len = 3; /* Default: "1.0" */ struct timeval timeout; char *user_headers = NULL; int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0); int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0); - int follow_location = 1; + zend_bool follow_location = 1; php_stream_filter *transfer_encoding = NULL; int response_code; zend_array *symbol_table; @@ -201,10 +203,19 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (context && (tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "timeout")) != NULL) { double d = zval_get_double(tmpzval); +#ifndef PHP_WIN32 timeout.tv_sec = (time_t) d; timeout.tv_usec = (size_t) ((d - timeout.tv_sec) * 1000000); +#else + timeout.tv_sec = (long) d; + timeout.tv_usec = (long) ((d - timeout.tv_sec) * 1000000); +#endif } else { +#ifndef PHP_WIN32 timeout.tv_sec = FG(default_socket_timeout); +#else + timeout.tv_sec = (long)FG(default_socket_timeout); +#endif timeout.tv_usec = 0; } @@ -346,7 +357,7 @@ finish: php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0); if (header_init && context && (tmpzval = php_stream_context_get_option(context, "http", "max_redirects")) != NULL) { - redirect_max = zval_get_long(tmpzval); + redirect_max = (int)zval_get_long(tmpzval); } if (context && (tmpzval = php_stream_context_get_option(context, "http", "method")) != NULL) { @@ -366,7 +377,7 @@ finish: } if (context && (tmpzval = php_stream_context_get_option(context, "http", "protocol_version")) != NULL) { - protocol_version_len = spprintf(&protocol_version, 0, "%.1F", zval_get_double(tmpzval)); + protocol_version_len = (int)spprintf(&protocol_version, 0, "%.1F", zval_get_double(tmpzval)); } if (!scratch) { @@ -378,7 +389,7 @@ finish: /* Should we send the entire path in the request line, default to no. */ if (!request_fulluri && context && (tmpzval = php_stream_context_get_option(context, "http", "request_fulluri")) != NULL) { - request_fulluri = zend_is_true(tmpzval TSRMLS_CC) ? 1 : 0; + request_fulluri = zend_is_true(tmpzval TSRMLS_CC); } if (request_fulluri) { @@ -731,7 +742,7 @@ finish: if (!strncasecmp(http_header_line, "Location: ", 10)) { if (context && (tmpzval = php_stream_context_get_option(context, "http", "follow_location")) != NULL) { - follow_location = zval_get_long(tmpzval); + follow_location = zval_is_true(tmpzval); } else if (!(response_code >= 300 && response_code < 304 || 307 == response_code || 308 == response_code)) { /* we shouldn't redirect automatically if follow_location isn't set and response_code not in (300, 301, 302, 303 and 307) @@ -843,7 +854,7 @@ finish: #define CHECK_FOR_CNTRL_CHARS(val) { \ if (val) { \ unsigned char *s, *e; \ - int l; \ + size_t l; \ l = php_url_decode(val, strlen(val)); \ s = (unsigned char*)val; e = s + l; \ while (s < e) { \ @@ -891,7 +902,7 @@ out: /* Restore original chunk size now that we're done with headers */ if (options & STREAM_WILL_CAST) - php_stream_set_chunk_size(stream, chunk_size); + php_stream_set_chunk_size(stream, (int)chunk_size); /* restore the users auto-detect-line-endings setting */ stream->flags |= eol_detect; diff --git a/ext/standard/info.c b/ext/standard/info.c index bc0ddddcc0..7a118af7b4 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -61,9 +61,9 @@ PHPAPI extern char *php_ini_opened_path; PHPAPI extern char *php_ini_scanned_path; PHPAPI extern char *php_ini_scanned_files; -static int php_info_print_html_esc(const char *str, int len) /* {{{ */ +static int php_info_print_html_esc(const char *str, size_t len) /* {{{ */ { - int written; + size_t written; zend_string *new_str; TSRMLS_FETCH(); @@ -77,7 +77,7 @@ static int php_info_print_html_esc(const char *str, int len) /* {{{ */ static int php_info_printf(const char *fmt, ...) /* {{{ */ { char *buf; - int len, written; + size_t len, written; va_list argv; TSRMLS_FETCH(); @@ -1026,7 +1026,7 @@ PHPAPI void php_info_print_table_colspan_header(int num_cols, char *header) /* { if (!sapi_module.phpinfo_as_text) { php_info_printf("<tr class=\"h\"><th colspan=\"%d\">%s</th></tr>\n", num_cols, header ); } else { - spaces = (74 - strlen(header)); + spaces = (int)(74 - strlen(header)); php_info_printf("%*s%s%*s\n", (int)(spaces/2), " ", header, (int)(spaces/2), " "); } } @@ -1176,7 +1176,7 @@ PHP_FUNCTION(phpinfo) /* Andale! Andale! Yee-Hah! */ php_output_start_default(TSRMLS_C); - php_print_info(flag TSRMLS_CC); + php_print_info((int)flag TSRMLS_CC); php_output_end(TSRMLS_C); RETURN_TRUE; @@ -1218,7 +1218,7 @@ PHP_FUNCTION(phpcredits) return; } - php_print_credits(flag TSRMLS_CC); + php_print_credits((int)flag TSRMLS_CC); RETURN_TRUE; } /* }}} */ diff --git a/ext/standard/levenshtein.c b/ext/standard/levenshtein.c index df822f45d4..e776934e1f 100644 --- a/ext/standard/levenshtein.c +++ b/ext/standard/levenshtein.c @@ -27,10 +27,11 @@ /* {{{ reference_levdist * reference implementation, only optimized for memory usage, not speed */ -static int reference_levdist(const char *s1, int l1, const char *s2, int l2, int cost_ins, int cost_rep, int cost_del ) +static zend_long reference_levdist(const char *s1, size_t l1, const char *s2, size_t l2, zend_long cost_ins, zend_long cost_rep, zend_long cost_del ) { - int *p1, *p2, *tmp; - int i1, i2, c0, c1, c2; + zend_long *p1, *p2, *tmp; + zend_long c0, c1, c2; + size_t i1, i2; if (l1 == 0) { return l2 * cost_ins; @@ -42,8 +43,8 @@ static int reference_levdist(const char *s1, int l1, const char *s2, int l2, int if ((l1 > LEVENSHTEIN_MAX_LENGTH) || (l2 > LEVENSHTEIN_MAX_LENGTH)) { return -1; } - p1 = safe_emalloc((l2 + 1), sizeof(int), 0); - p2 = safe_emalloc((l2 + 1), sizeof(int), 0); + p1 = safe_emalloc((l2 + 1), sizeof(zend_long), 0); + p2 = safe_emalloc((l2 + 1), sizeof(zend_long), 0); for (i2 = 0; i2 <= l2; i2++) { p1[i2] = i2 * cost_ins; @@ -96,7 +97,7 @@ PHP_FUNCTION(levenshtein) char *callback_name; size_t str1_len, str2_len, callback_len; zend_long cost_ins, cost_rep, cost_del; - int distance = -1; + zend_long distance = -1; switch (argc) { case 2: /* just two strings: use maximum performance version */ diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 96363f4cb9..5d2b576c7e 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -251,7 +251,7 @@ PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char if (mail_log && *mail_log) { char *tmp; time_t curtime; - int l; + size_t l; zend_string *date_str; time(&curtime); diff --git a/ext/standard/math.c b/ext/standard/math.c index 7014e6c938..31eb259829 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -382,7 +382,7 @@ PHP_FUNCTION(round) case IS_DOUBLE: return_val = (Z_TYPE_P(value) == IS_LONG) ? (double)Z_LVAL_P(value) : Z_DVAL_P(value); - return_val = _php_math_round(return_val, places, mode); + return_val = _php_math_round(return_val, (int)places, (int)mode); RETURN_DOUBLE(return_val); break; @@ -946,7 +946,7 @@ PHP_FUNCTION(rad2deg) PHPAPI zend_long _php_math_basetolong(zval *arg, int base) { zend_long num = 0, digit, onum; - int i; + zend_long i; char c, *s; if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) { @@ -992,7 +992,7 @@ PHPAPI int _php_math_basetozval(zval *arg, int base, zval *ret) { zend_long num = 0; double fnum = 0; - int i; + zend_long i; int mode = 0; char c, *s; zend_long cutoff; @@ -1029,7 +1029,7 @@ PHPAPI int _php_math_basetozval(zval *arg, int base, zval *ret) num = num * base + c; break; } else { - fnum = num; + fnum = (double)num; mode = 1; } /* fall-through */ @@ -1234,10 +1234,10 @@ PHP_FUNCTION(base_convert) RETURN_FALSE; } - if(_php_math_basetozval(number, frombase, &temp) == FAILURE) { + if(_php_math_basetozval(number, (int)frombase, &temp) == FAILURE) { RETURN_FALSE; } - result = _php_math_zvaltobase(&temp, tobase TSRMLS_CC); + result = _php_math_zvaltobase(&temp, (int)tobase TSRMLS_CC); RETVAL_STR(result); } /* }}} */ @@ -1284,15 +1284,15 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_poin /* calculate the length of the return buffer */ if (dp) { - integral = dp - tmpbuf->val; + integral = (int)(dp - tmpbuf->val); } else { /* no decimal point was found */ - integral = tmpbuf->len; + integral = (int)tmpbuf->len; } /* allow for thousand separators */ if (thousand_sep) { - integral += thousand_sep_len * ((integral-1) / 3); + integral += (int)(thousand_sep_len * ((integral-1) / 3)); } reslen = integral; @@ -1301,7 +1301,7 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_poin reslen += dec; if (dec_point) { - reslen += dec_point_len; + reslen += (int)dec_point_len; } } @@ -1319,7 +1319,7 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_poin * Take care, as the sprintf implementation may return less places than * we requested due to internal buffer limitations */ if (dec) { - int declen = dp ? s - dp : 0; + int declen = (int)(dp ? s - dp : 0); int topad = dec > declen ? dec - declen : 0; /* pad with '0's */ @@ -1391,7 +1391,7 @@ PHP_FUNCTION(number_format) RETURN_STR(_php_math_number_format(num, 0, dec_point_chr, thousand_sep_chr)); break; case 2: - RETURN_STR(_php_math_number_format(num, dec, dec_point_chr, thousand_sep_chr)); + RETURN_STR(_php_math_number_format(num, (int)dec, dec_point_chr, thousand_sep_chr)); break; case 4: if (dec_point == NULL) { @@ -1404,7 +1404,7 @@ PHP_FUNCTION(number_format) thousand_sep_len = 1; } - RETVAL_STR(_php_math_number_format_ex(num, dec, + RETVAL_STR(_php_math_number_format_ex(num, (int)dec, dec_point, dec_point_len, thousand_sep, thousand_sep_len)); break; default: diff --git a/ext/standard/pack.c b/ext/standard/pack.c index 07206c8b7b..4af72c34b8 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -912,7 +912,7 @@ PHP_FUNCTION(unpack) case 'P': { int issigned = 0; int *map = machine_endian_longlong_map; - long v = 0; + zend_long v = 0; if (type == 'q' || type == 'Q') { issigned = input[inputpos + (machine_little_endian ? 7 : 0)] & 0x80; @@ -927,9 +927,9 @@ PHP_FUNCTION(unpack) v = php_unpack(&input[inputpos], 8, issigned, map); if (type == 'q') { - v = (signed long int) v; + v = (zend_long) v; } else { - v = (unsigned long int) v; + v = (zend_ulong) v; } add_assoc_long(return_value, n, v); diff --git a/ext/standard/password.c b/ext/standard/password.c index 0f75272d0e..c58c28ab3c 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -268,7 +268,7 @@ PHP_FUNCTION(password_verify) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &password, &password_len, &hash, &hash_len) == FAILURE) { RETURN_FALSE; } - if ((ret = php_crypt(password, password_len, hash, hash_len)) == NULL) { + if ((ret = php_crypt(password, (int)password_len, hash, (int)hash_len)) == NULL) { RETURN_FALSE; } @@ -298,7 +298,8 @@ PHP_FUNCTION(password_hash) { char *hash_format, *hash, *salt, *password; zend_long algo = 0; - size_t password_len = 0, hash_len; + size_t password_len = 0; + int hash_len; size_t salt_len = 0, required_salt_len = 0, hash_format_len; HashTable *options = 0; zval *option_buffer; @@ -344,7 +345,7 @@ PHP_FUNCTION(password_hash) if (options && (option_buffer = zend_symtable_str_find(options, "salt", sizeof("salt")-1)) != NULL) { char *buffer; - int buffer_len_int = 0; + size_t buffer_len_int = 0; size_t buffer_len; switch (Z_TYPE_P(option_buffer)) { case IS_STRING: @@ -425,7 +426,7 @@ PHP_FUNCTION(password_hash) /* This cast is safe, since both values are defined here in code and cannot overflow */ hash_len = (int) (hash_format_len + salt_len); - if ((result = php_crypt(password, password_len, hash, hash_len)) == NULL) { + if ((result = php_crypt(password, (int)password_len, hash, hash_len)) == NULL) { efree(hash); RETURN_FALSE; } diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index 575e8fff98..1989a2eabc 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -80,7 +80,7 @@ static size_t php_stream_input_read(php_stream *stream, char *buf, size_t count php_stream_input_t *input = stream->abstract; size_t read; - if (!SG(post_read) && SG(read_post_bytes) < input->position + count) { + if (!SG(post_read) && SG(read_post_bytes) < (int64_t)(input->position + count)) { /* read requested data from SAPI */ int read_bytes = sapi_read_post_block(buf, count TSRMLS_CC); @@ -323,7 +323,7 @@ php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const char *pa return NULL; } - fd = dup(fildes_ori); + fd = dup((int)fildes_ori); if (fd == -1) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Error duping file descriptor " ZEND_LONG_FMT "; possibly it doesn't exist: " diff --git a/ext/standard/php_http.h b/ext/standard/php_http.h index 0979348314..712e297fe3 100644 --- a/ext/standard/php_http.h +++ b/ext/standard/php_http.h @@ -25,9 +25,9 @@ #include "zend_smart_str.h" PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, - const char *num_prefix, int num_prefix_len, - const char *key_prefix, int key_prefix_len, - const char *key_suffix, int key_suffix_len, + const char *num_prefix, size_t num_prefix_len, + const char *key_prefix, size_t key_prefix_len, + const char *key_suffix, size_t key_suffix_len, zval *type, char *arg_sep, int enc_type TSRMLS_DC); #define php_url_encode_hash(ht, formstr) php_url_encode_hash_ex((ht), (formstr), NULL, 0, NULL, 0, NULL, 0, NULL TSRMLS_CC) diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 66c0c2e7e3..d6a6f2be50 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -82,7 +82,7 @@ static php_process_env_t _php_array_to_envp(zval *environment, int is_persistent char **ep; #endif char *p; - uint cnt, l, sizeenv=0; + size_t cnt, l, sizeenv=0; HashTable *target_hash; memset(&env, 0, sizeof(env)); @@ -109,7 +109,7 @@ static php_process_env_t _php_array_to_envp(zval *environment, int is_persistent /* first, we have to get the size of all the elements in the hash */ ZEND_HASH_FOREACH_STR_KEY_VAL(target_hash, string_key, element) { zend_string *str = zval_get_string(element); - uint el_len = str->len; + size_t el_len = str->len; zend_string_release(str); if (el_len == 0) { @@ -512,7 +512,7 @@ PHP_FUNCTION(proc_open) goto exit_fail; } - descriptors[ndesc].index = nindex; + descriptors[ndesc].index = (int)nindex; if (Z_TYPE_P(descitem) == IS_RESOURCE) { /* should be a stream - try and dup the descriptor */ @@ -526,7 +526,7 @@ PHP_FUNCTION(proc_open) } #ifdef PHP_WIN32 - descriptors[ndesc].childend = dup_fd_as_handle(fd); + descriptors[ndesc].childend = dup_fd_as_handle((int)fd); if (descriptors[ndesc].childend == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to dup File-Handle for descriptor %d", nindex); goto exit_fail; @@ -621,8 +621,8 @@ PHP_FUNCTION(proc_open) } #ifdef PHP_WIN32 - descriptors[ndesc].childend = dup_fd_as_handle(fd); - _close(fd); + descriptors[ndesc].childend = dup_fd_as_handle((int)fd); + _close((int)fd); /* simulate the append mode by fseeking to the end of the file this introduces a potential race-condition, but it is the best we can do, though */ diff --git a/ext/standard/quot_print.c b/ext/standard/quot_print.c index c7eddc576b..441b65288c 100644 --- a/ext/standard/quot_print.c +++ b/ext/standard/quot_print.c @@ -53,7 +53,7 @@ static char php_hex2int(int c) /* {{{ */ PHPAPI zend_string *php_quot_print_decode(const unsigned char *str, size_t length, int replace_us_by_ws) /* {{{ */ { - register unsigned int i; + register size_t i; register unsigned const char *p1; register unsigned char *p2; register unsigned int h_nbl, l_nbl; diff --git a/ext/standard/soundex.c b/ext/standard/soundex.c index feb9a6780e..d882f5cab6 100644 --- a/ext/standard/soundex.c +++ b/ext/standard/soundex.c @@ -78,7 +78,7 @@ PHP_FUNCTION(soundex) if (code >= 'A' && code <= 'Z') { if (_small == 0) { /* remember first valid char */ - soundex[_small++] = code; + soundex[_small++] = (char)code; last = soundex_table[code - 'A']; } else { @@ -88,7 +88,7 @@ PHP_FUNCTION(soundex) code = soundex_table[code - 'A']; if (code != last) { if (code != 0) { - soundex[_small++] = code; + soundex[_small++] = (char)code; } last = code; } diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index f864994d28..51e3c14e7a 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -60,7 +60,7 @@ PHP_FUNCTION(stream_socket_pair) RETURN_FALSE; } - if (0 != socketpair(domain, type, protocol, pair)) { + if (0 != socketpair((int)domain, (int)type, (int)protocol, pair)) { char errbuf[256]; php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create sockets: [%d]: %s", php_socket_errno(), php_socket_strerror(php_socket_errno(), errbuf, sizeof(errbuf))); @@ -90,7 +90,7 @@ PHP_FUNCTION(stream_socket_client) char *host; size_t host_len; zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL; - double timeout = FG(default_socket_timeout); + double timeout = (double)FG(default_socket_timeout); php_timeout_ull conv; struct timeval tv; char *hashkey = NULL; @@ -206,7 +206,7 @@ PHP_FUNCTION(stream_socket_server) } stream = php_stream_xport_create(host, host_len, REPORT_ERRORS, - STREAM_XPORT_SERVER | flags, + STREAM_XPORT_SERVER | (int)flags, NULL, NULL, context, &errstr, &err); if (stream == NULL) { @@ -239,7 +239,7 @@ PHP_FUNCTION(stream_socket_server) Accept a client connection from a server socket */ PHP_FUNCTION(stream_socket_accept) { - double timeout = FG(default_socket_timeout); + double timeout = (double)FG(default_socket_timeout); zval *zpeername = NULL; zend_string *peername = NULL; php_timeout_ull conv; @@ -340,7 +340,7 @@ PHP_FUNCTION(stream_socket_sendto) } } - RETURN_LONG(php_stream_xport_sendto(stream, data, datalen, flags, target_addr ? &sa : NULL, sl TSRMLS_CC)); + RETURN_LONG(php_stream_xport_sendto(stream, data, datalen, (int)flags, target_addr ? &sa : NULL, sl TSRMLS_CC)); } /* }}} */ @@ -374,7 +374,7 @@ PHP_FUNCTION(stream_socket_recvfrom) read_buf = zend_string_alloc(to_read, 0); - recvd = php_stream_xport_recvfrom(stream, read_buf->val, to_read, flags, NULL, NULL, + recvd = php_stream_xport_recvfrom(stream, read_buf->val, to_read, (int)flags, NULL, NULL, zremote ? &remote_addr : NULL TSRMLS_CC); @@ -410,7 +410,7 @@ PHP_FUNCTION(stream_get_contents) if (desiredpos >= 0) { int seek_res = 0; - off_t position; + zend_off_t position; position = php_stream_tell(stream); if (position >= 0 && desiredpos > position) { @@ -773,6 +773,10 @@ PHP_FUNCTION(stream_select) RETURN_FALSE; } +#ifdef PHP_WIN32 + tv.tv_sec = (long)(Z_LVAL_P(sec) + (usec / 1000000)); + tv.tv_usec = (long)(usec % 1000000); +#else /* Solaris + BSD do not like microsecond values which are >= 1 sec */ if (usec > 999999) { tv.tv_sec = Z_LVAL_P(sec) + (usec / 1000000); @@ -781,7 +785,7 @@ PHP_FUNCTION(stream_select) tv.tv_sec = Z_LVAL_P(sec); tv.tv_usec = usec; } - +#endif tv_p = &tv; } @@ -1275,19 +1279,16 @@ PHP_FUNCTION(stream_get_line) PHP_FUNCTION(stream_set_blocking) { zval *arg1; - int block; - zend_long arg2; + zend_long block; php_stream *stream; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &arg1, &arg2) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &arg1, &block) == FAILURE) { return; } php_stream_from_zval(stream, arg1); - block = arg2; - - if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, block == 0 ? 0 : 1, NULL) == -1) { + if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, block ? 1 : 0, NULL) == -1) { RETURN_FALSE; } @@ -1313,6 +1314,16 @@ PHP_FUNCTION(stream_set_timeout) php_stream_from_zval(stream, socket); +#ifdef PHP_WIN32 + t.tv_sec = (long)seconds; + + if (argc == 3) { + t.tv_usec = (long)(microseconds % 1000000); + t.tv_sec +=(long)(microseconds / 1000000); + } else { + t.tv_usec = 0; + } +#else t.tv_sec = seconds; if (argc == 3) { @@ -1321,6 +1332,7 @@ PHP_FUNCTION(stream_set_timeout) } else { t.tv_usec = 0; } +#endif if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &t)) { RETURN_TRUE; @@ -1485,7 +1497,7 @@ PHP_FUNCTION(stream_resolve_include_path) return; } - resolved_path = zend_resolve_path(filename, filename_len TSRMLS_CC); + resolved_path = zend_resolve_path(filename, (int)filename_len TSRMLS_CC); if (resolved_path) { // TODO: avoid reallocation ??? diff --git a/ext/standard/string.c b/ext/standard/string.c index 706a3eb075..1d9948dcad 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1663,12 +1663,10 @@ static int php_needle_char(zval *needle, char *target TSRMLS_DC) return SUCCESS; case IS_OBJECT: { - zval holder = *needle; - zval_copy_ctor(&(holder)); - convert_to_long(&(holder)); - if(Z_TYPE(holder) != IS_LONG) { - return FAILURE; - } + zval holder; + + ZVAL_LONG(&holder, zval_get_long(needle)); + *target = (char)Z_LVAL(holder); return SUCCESS; } @@ -2766,20 +2764,20 @@ PHP_FUNCTION(ucwords) PHPAPI char *php_strtr(char *str, size_t len, char *str_from, char *str_to, size_t trlen) { size_t i; - unsigned char xlat[256]; + unsigned char xlat[256], j; if ((trlen < 1) || (len < 1)) { return str; } - for (i = 0; i < 256; xlat[i] = i, i++); + for (j = 0; j < 256; xlat[j] = j, j++); for (i = 0; i < trlen; i++) { - xlat[(unsigned char) str_from[i]] = str_to[i]; + xlat[(size_t) str_from[i]] = str_to[i]; } for (i = 0; i < len; i++) { - str[i] = xlat[(unsigned char) str[i]]; + str[i] = xlat[(size_t) str[i]]; } return str; @@ -4185,7 +4183,7 @@ PHP_FUNCTION(setlocale) #ifdef HAVE_SETLOCALE if (Z_TYPE_P(pcategory) == IS_LONG) { - cat = Z_LVAL_P(pcategory); + cat = (int)Z_LVAL_P(pcategory); } else { /* FIXME: The following behaviour should be removed. */ char *category; @@ -4896,14 +4894,14 @@ PHP_FUNCTION(localeconv) localeconv_r( &currlocdata ); /* Grab the grouping data out of the array */ - len = strlen(currlocdata.grouping); + len = (int)strlen(currlocdata.grouping); for (i = 0; i < len; i++) { add_index_long(&grouping, i, currlocdata.grouping[i]); } /* Grab the monetary grouping data out of the array */ - len = strlen(currlocdata.mon_grouping); + len = (int)strlen(currlocdata.mon_grouping); for (i = 0; i < len; i++) { add_index_long(&mon_grouping, i, currlocdata.mon_grouping[i]); @@ -5346,7 +5344,7 @@ PHP_FUNCTION(str_split) return; } - array_init_size(return_value, ((str->len - 1) / split_length) + 1); + array_init_size(return_value, (uint32_t)(((str->len - 1) / split_length) + 1)); n_reg_segments = str->len / split_length; p = str->val; diff --git a/ext/standard/tests/serialize/bug68044.phpt b/ext/standard/tests/serialize/bug68044.phpt index 031e44e149..f8ef937b1e 100644 --- a/ext/standard/tests/serialize/bug68044.phpt +++ b/ext/standard/tests/serialize/bug68044.phpt @@ -6,7 +6,7 @@ Bug #68044 Integer overflow in unserialize() (32-bits only) ?> ===DONE== --EXPECTF-- -Warning: Insufficient data for unserializing - %d required, 1 present in %s/bug68044.php on line 2 +Warning: Insufficient data for unserializing - %d required, 1 present in %s%ebug68044.php on line 2 -Notice: unserialize(): Error at offset 32 of 33 bytes in %s/bug68044.php on line 2 +Notice: unserialize(): Error at offset 32 of 33 bytes in %s%ebug68044.php on line 2 ===DONE== diff --git a/ext/standard/type.c b/ext/standard/type.c index 67d5ed1e75..a773e6c53c 100644 --- a/ext/standard/type.c +++ b/ext/standard/type.c @@ -156,7 +156,7 @@ PHP_FUNCTION(intval) #endif RETVAL_ZVAL(num, 1, 0); - convert_to_long_base(return_value, base); + convert_to_long_base(return_value, (int)base); } /* }}} */ diff --git a/ext/standard/url.c b/ext/standard/url.c index 4fb2c73edb..7d408ef88a 100644 --- a/ext/standard/url.c +++ b/ext/standard/url.c @@ -61,7 +61,7 @@ PHPAPI void php_url_free(php_url *theurl) /* {{{ php_replace_controlchars */ -PHPAPI char *php_replace_controlchars_ex(char *str, int len) +PHPAPI char *php_replace_controlchars_ex(char *str, size_t len) { unsigned char *s = (unsigned char *)str; unsigned char *e = (unsigned char *)str + len; @@ -94,7 +94,7 @@ PHPAPI php_url *php_url_parse(char const *str) /* {{{ php_url_parse */ -PHPAPI php_url *php_url_parse_ex(char const *str, int length) +PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) { char port_buf[6]; php_url *ret = ecalloc(1, sizeof(php_url)); @@ -481,7 +481,7 @@ static unsigned char hexchars[] = "0123456789ABCDEF"; /* {{{ php_url_encode */ -PHPAPI zend_string *php_url_encode(char const *s, int len) +PHPAPI zend_string *php_url_encode(char const *s, size_t len) { register unsigned char c; unsigned char *to; @@ -572,7 +572,7 @@ PHP_FUNCTION(urldecode) /* {{{ php_url_decode */ -PHPAPI int php_url_decode(char *str, int len) +PHPAPI size_t php_url_decode(char *str, size_t len) { char *dest = str; char *data = str; @@ -603,7 +603,7 @@ PHPAPI int php_url_decode(char *str, int len) /* {{{ php_raw_url_encode */ -PHPAPI zend_string *php_raw_url_encode(char const *s, int len) +PHPAPI zend_string *php_raw_url_encode(char const *s, size_t len) { register int x, y; zend_string *str; @@ -679,7 +679,7 @@ PHP_FUNCTION(rawurldecode) /* {{{ php_raw_url_decode */ -PHPAPI int php_raw_url_decode(char *str, int len) +PHPAPI size_t php_raw_url_decode(char *str, size_t len) { char *dest = str; char *data = str; diff --git a/ext/standard/url.h b/ext/standard/url.h index 4d7a1f5b56..ec2676eaee 100644 --- a/ext/standard/url.h +++ b/ext/standard/url.h @@ -33,11 +33,12 @@ typedef struct php_url { PHPAPI void php_url_free(php_url *theurl); PHPAPI php_url *php_url_parse(char const *str); -PHPAPI php_url *php_url_parse_ex(char const *str, int length); -PHPAPI int php_url_decode(char *str, int len); /* return value: length of decoded string */ -PHPAPI int php_raw_url_decode(char *str, int len); /* return value: length of decoded string */ -PHPAPI zend_string *php_url_encode(char const *s, int len); -PHPAPI zend_string *php_raw_url_encode(char const *s, int len); +PHPAPI php_url *php_url_parse_ex(char const *str, size_t length); +PHPAPI size_t php_url_decode(char *str, size_t len); /* return value: length of decoded string */ +PHPAPI size_t php_raw_url_decode(char *str, size_t len); /* return value: length of decoded string */ +PHPAPI zend_string *php_url_encode(char const *s, size_t len); +PHPAPI zend_string *php_raw_url_encode(char const *s, size_t len); +PHPAPI char *php_replace_controlchars_ex(char *str, size_t len); PHP_FUNCTION(parse_url); PHP_FUNCTION(urlencode); diff --git a/ext/standard/uuencode.c b/ext/standard/uuencode.c index 6582e7de65..ea171a658a 100644 --- a/ext/standard/uuencode.c +++ b/ext/standard/uuencode.c @@ -83,7 +83,7 @@ PHPAPI zend_string *php_uuencode(char *src, size_t src_len) /* {{{ */ ee = e; len = ee - s; if (len % 3) { - ee = s + (int) (floor(len / 3) * 3); + ee = s + (int) (floor((double)len / 3) * 3); } } *p++ = PHP_UU_ENC(len); @@ -173,7 +173,8 @@ PHPAPI zend_string *php_uudecode(char *src, size_t src_len) /* {{{ */ s++; } - if ((len = total_len > (p - dest->val))) { + assert(p >= dest->val); + if ((len = total_len > (size_t)(p - dest->val))) { *p++ = PHP_UU_DEC(*s) << 2 | PHP_UU_DEC(*(s + 1)) >> 4; if (len > 1) { *p++ = PHP_UU_DEC(*(s + 1)) << 4 | PHP_UU_DEC(*(s + 2)) >> 2; diff --git a/ext/standard/var.c b/ext/standard/var.c index 6e5bd703d3..4f0bd24bdc 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -389,7 +389,7 @@ PHP_FUNCTION(debug_zval_dump) #define buffer_append_spaces(buf, num_spaces) \ do { \ char *tmp_spaces; \ - int tmp_spaces_len; \ + size_t tmp_spaces_len; \ tmp_spaces_len = spprintf(&tmp_spaces, 0,"%*c", num_spaces, ' '); \ smart_str_appendl(buf, tmp_spaces, tmp_spaces_len); \ efree(tmp_spaces); \ @@ -594,7 +594,7 @@ PHP_FUNCTION(var_export) static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash TSRMLS_DC); -static inline uint32_t php_add_var_hash(php_serialize_data_t data, zval *var TSRMLS_DC) /* {{{ */ +static inline zend_long php_add_var_hash(php_serialize_data_t data, zval *var TSRMLS_DC) /* {{{ */ { zval *zv; zend_ulong key; @@ -772,7 +772,7 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_pt static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ { - uint32_t var_already; + zend_long var_already; HashTable *myht; if (EG(exception)) { @@ -816,7 +816,7 @@ again: smart_str_appendl(buf, "d:", 2); s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); - php_gcvt(Z_DVAL_P(struc), PG(serialize_precision), '.', 'E', s); + php_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', s); smart_str_appends(buf, s); smart_str_appendc(buf, ';'); efree(s); diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index c8f1ec665e..5d334069a1 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -497,7 +497,9 @@ static void TIDY_CALL php_tidy_panic(ctmbstr msg) static int _php_tidy_set_tidy_opt(TidyDoc doc, char *optname, zval *value TSRMLS_DC) { TidyOption opt = tidyGetOptionByName(doc, optname); - zval conv = *value; + zval conv; + + ZVAL_COPY_VALUE(&conv, value); if (!opt) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown Tidy Configuration Option '%s'", optname); diff --git a/main/snprintf.c b/main/snprintf.c index 062ccc4eee..b9f781346c 100644 --- a/main/snprintf.c +++ b/main/snprintf.c @@ -311,7 +311,7 @@ PHPAPI char *php_gcvt(double value, int ndigit, char dec_point, char exponent, c * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) */ /* char * ap_php_conv_10() {{{ */ -char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned, +PHPAPI char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned, register bool_int * is_negative, char *buf_end, register size_t *len) { register char *p = buf_end; @@ -474,7 +474,7 @@ PHPAPI char * php_conv_fp(register char format, register double num, * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) */ -char * ap_php_conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register size_t *len) /* {{{ */ +PHPAPI char * ap_php_conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register size_t *len) /* {{{ */ { register int mask = (1 << nbits) - 1; register char *p = buf_end; diff --git a/main/snprintf.h b/main/snprintf.h index d133ad7aaa..789ab7d41a 100644 --- a/main/snprintf.h +++ b/main/snprintf.h @@ -153,10 +153,10 @@ typedef enum { typedef WIDE_INT wide_int; typedef unsigned WIDE_INT u_wide_int; -extern char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned, +PHPAPI char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned, register bool_int * is_negative, char *buf_end, register size_t *len); -extern char * ap_php_conv_p2(register u_wide_int num, register int nbits, +PHPAPI char * ap_php_conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register size_t *len); /* The maximum precision that's allowed for float conversion. Does not include diff --git a/main/streams/php_stream_transport.h b/main/streams/php_stream_transport.h index 9674314c49..2d076064cf 100644 --- a/main/streams/php_stream_transport.h +++ b/main/streams/php_stream_transport.h @@ -101,13 +101,13 @@ enum php_stream_xport_send_recv_flags { /* Similar to recv() system call; read data from the stream, optionally * peeking, optionally retrieving OOB data */ PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t buflen, - long flags, void **addr, socklen_t *addrlen, + int flags, void **addr, socklen_t *addrlen, zend_string **textaddr TSRMLS_DC); /* Similar to send() system call; send data to the stream, optionally * sending it as OOB data */ PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t buflen, - long flags, void *addr, socklen_t addrlen TSRMLS_DC); + int flags, void *addr, socklen_t addrlen TSRMLS_DC); typedef enum { STREAM_SHUT_RD, @@ -146,9 +146,9 @@ typedef struct _php_stream_xport_param { struct sockaddr *addr; char *buf; size_t buflen; - zend_long flags; socklen_t addrlen; int backlog; + int flags; } inputs; struct { php_stream *client; diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 28328c3cd5..7432b7c49e 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -41,6 +41,7 @@ #include "php_streams_int.h" #ifdef PHP_WIN32 # include "win32/winutil.h" +# include "win32/time.h" #endif #define php_stream_fopen_from_fd_int(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_CC TSRMLS_CC) diff --git a/main/streams/transports.c b/main/streams/transports.c index a75f77c5bd..8fd0b91d35 100644 --- a/main/streams/transports.c +++ b/main/streams/transports.c @@ -393,7 +393,7 @@ PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate TSRML /* Similar to recv() system call; read data from the stream, optionally * peeking, optionally retrieving OOB data */ PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t buflen, - long flags, void **addr, socklen_t *addrlen, zend_string **textaddr + int flags, void **addr, socklen_t *addrlen, zend_string **textaddr TSRMLS_DC) { php_stream_xport_param param; @@ -462,7 +462,7 @@ PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t bufle /* Similar to send() system call; send data to the stream, optionally * sending it as OOB data */ PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t buflen, - long flags, void *addr, socklen_t addrlen TSRMLS_DC) + int flags, void *addr, socklen_t addrlen TSRMLS_DC) { php_stream_xport_param param; int ret = 0; diff --git a/sapi/phpdbg/config.m4 b/sapi/phpdbg/config.m4 index d78a439af0..528abb5822 100644 --- a/sapi/phpdbg/config.m4 +++ b/sapi/phpdbg/config.m4 @@ -3,12 +3,15 @@ dnl $Id$ dnl PHP_ARG_ENABLE(phpdbg, for phpdbg support, -[ --enable-phpdbg Build phpdbg], no, no) +[ --enable-phpdbg Build phpdbg], no, no) + +PHP_ARG_ENABLE(phpdbg-webhelper, for phpdbg web SAPI support, +[ --enable-phpdbg-webhelper Build phpdbg web SAPI support], yes, yes) PHP_ARG_ENABLE(phpdbg-debug, for phpdbg debug build, -[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no) +[ --enable-phpdbg-debug Build phpdbg in debug mode], no, no) -if test "$PHP_PHPDBG" != "no"; then +if test "$BUILD_PHPDBG" == "" && test "$PHP_PHPDBG" != "no"; then AC_HEADER_TIOCGWINSZ AC_DEFINE(HAVE_PHPDBG, 1, [ ]) @@ -18,8 +21,19 @@ if test "$PHP_PHPDBG" != "no"; then AC_DEFINE(PHPDBG_DEBUG, 0, [ ]) fi + if test "$PHP_PHPDBG_WEBHELPER" != "no"; then + if ! test -d ext/phpdbg_webhelper; then + ln -s ../sapi/phpdbg ext/phpdbg_webhelper + fi + if test "$PHP_JSON" != "no"; then + PHP_NEW_EXTENSION(phpdbg_webhelper, phpdbg_rinit_hook.c phpdbg_webdata_transfer.c, $ext_shared) + else + AC_MSG_ERROR(Webhelper extension of phpdbg needs json enabled) + fi + fi + PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE" - PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c" + PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c phpdbg_sigsafe.c phpdbg_wait.c phpdbg_io.c phpdbg_eol.c phpdbg_out.c" if test "$PHP_READLINE" != "no" -o "$PHP_LIBEDIT" != "no"; then PHPDBG_EXTRA_LIBS="$PHP_READLINE_LIBS" diff --git a/sapi/phpdbg/config.w32 b/sapi/phpdbg/config.w32 index 17e15b6ced..6f0bd8f811 100644 --- a/sapi/phpdbg/config.w32 +++ b/sapi/phpdbg/config.w32 @@ -1,7 +1,11 @@ ARG_ENABLE('phpdbg', 'Build phpdbg', 'no'); ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no'); -PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c phpdbg_parser.c phpdbg_lexer.c'; +PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c ' + + 'phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c ' + + 'phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c '+ + 'phpdbg_parser.c phpdbg_lexer.c phpdbg_sigsafe.c phpdbg_wait.c phpdbg_io.c ' + + 'phpdbg_sigio_win32.c phpdbg_eol.c phpdbg_out.c'; PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll'; PHPDBG_EXE='phpdbg.exe'; @@ -9,6 +13,7 @@ if (PHP_PHPDBG == "yes") { SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE); ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib"); ADD_FLAG("CFLAGS_PHPDBG", "/D YY_NO_UNISTD_H"); + ADD_FLAG("LDFLAGS_PHPDBG", "/stack:8388608"); } if (PHP_PHPDBGS == "yes") { diff --git a/sapi/phpdbg/phpdbg.1 b/sapi/phpdbg/phpdbg.1 index b6c26df565..5e4d144c83 100644 --- a/sapi/phpdbg/phpdbg.1 +++ b/sapi/phpdbg/phpdbg.1 @@ -7,7 +7,7 @@ phpdbg \- The interactive PHP debugger [\fB\-e\fIFILE\fR] .SH DESCRIPTION .B phpdbg -a lightweight, powerful, easy to use debugging platform for PHP7. +a lightweight, powerful, easy to use debugging platform for PHP5. .SH OPTIONS The following switches are implemented (just like cli SAPI): .TP diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 4388b4f86d..d70e512751 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -28,7 +28,9 @@ #include "phpdbg_list.h" #include "phpdbg_utils.h" #include "phpdbg_set.h" +#include "phpdbg_io.h" #include "zend_alloc.h" +#include "phpdbg_eol.h" /* {{{ remote console headers */ #ifndef _WIN32 @@ -36,6 +38,7 @@ # include <sys/select.h> # include <sys/time.h> # include <sys/types.h> +# include <sys/poll.h> # include <netinet/in.h> # include <unistd.h> # include <arpa/inet.h> @@ -43,6 +46,20 @@ ZEND_DECLARE_MODULE_GLOBALS(phpdbg); +static PHP_INI_MH(OnUpdateEol) +{ + if (!new_value) { + return FAILURE; + } + + return phpdbg_eol_global_update(new_value->val TSRMLS_CC); +} + +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, socket_path, zend_phpdbg_globals, phpdbg_globals) + STD_PHP_INI_ENTRY("phpdbg.eol", "2", PHP_INI_ALL, OnUpdateEol, socket_path, zend_phpdbg_globals, phpdbg_globals) +PHP_INI_END() + static zend_bool phpdbg_booted = 0; #if PHP_VERSION_ID >= 50500 @@ -63,20 +80,40 @@ static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */ pg->exec = NULL; pg->exec_len = 0; pg->buffer = NULL; + pg->last_was_newline = 1; pg->ops = NULL; pg->vmret = 0; + pg->in_execution = 0; pg->bp_count = 0; pg->flags = PHPDBG_DEFAULT_FLAGS; pg->oplog = NULL; - pg->io[PHPDBG_STDIN] = NULL; - pg->io[PHPDBG_STDOUT] = NULL; - pg->io[PHPDBG_STDERR] = NULL; + memset(pg->io, 0, sizeof(pg->io)); pg->frame.num = 0; + pg->sapi_name_ptr = NULL; + pg->socket_fd = -1; + pg->socket_server_fd = -1; + + pg->req_id = 0; + pg->err_buf.active = 0; + pg->err_buf.type = 0; + + pg->input_buflen = 0; + pg->sigsafe_mem.mem = NULL; + pg->sigsegv_bailout = NULL; + +#ifdef PHP_WIN32 + pg->sigio_watcher_thread = INVALID_HANDLE_VALUE; + memset(&pg->swd, 0, sizeof(struct win32_sigio_watcher_data)); +#endif + + pg->eol = PHPDBG_EOL_LF; } /* }}} */ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */ { ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL); + REGISTER_INI_ENTRIES(); + #if PHP_VERSION_ID >= 50500 zend_execute_old = zend_execute_ex; zend_execute_ex = phpdbg_execute_ex; @@ -86,7 +123,7 @@ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */ #endif REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT); - + REGISTER_LONG_CONSTANT("PHPDBG_FILE", FILE_PARAM, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT); @@ -99,50 +136,49 @@ static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */ return SUCCESS; } /* }}} */ -static void php_phpdbg_destroy_bp_file(void *brake) /* {{{ */ +static void php_phpdbg_destroy_bp_file(zval *brake) /* {{{ */ { - zend_hash_destroy((HashTable*)brake); + zend_hash_destroy(Z_ARRVAL_P(brake)); } /* }}} */ -static void php_phpdbg_destroy_bp_symbol(void *brake) /* {{{ */ +static void php_phpdbg_destroy_bp_symbol(zval *brake) /* {{{ */ { - efree((char*)((phpdbg_breaksymbol_t*)brake)->symbol); + efree((char *) ((phpdbg_breaksymbol_t *) Z_PTR_P(brake))->symbol); } /* }}} */ -static void php_phpdbg_destroy_bp_opcode(void *brake) /* {{{ */ +static void php_phpdbg_destroy_bp_opcode(zval *brake) /* {{{ */ { - efree((char*)((phpdbg_breakop_t*)brake)->name); + efree((char *) ((phpdbg_breakop_t *) Z_PTR_P(brake))->name); } /* }}} */ -static void php_phpdbg_destroy_bp_methods(void *brake) /* {{{ */ +static void php_phpdbg_destroy_bp_methods(zval *brake) /* {{{ */ { - zend_hash_destroy((HashTable*)brake); + zend_hash_destroy(Z_ARRVAL_P(brake)); } /* }}} */ -static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */ +static void php_phpdbg_destroy_bp_condition(zval *data) /* {{{ */ { - phpdbg_breakcond_t *brake = (phpdbg_breakcond_t*) data; + phpdbg_breakcond_t *brake = (phpdbg_breakcond_t *) Z_PTR_P(data); if (brake) { if (brake->ops) { TSRMLS_FETCH(); - destroy_op_array( - brake->ops TSRMLS_CC); + destroy_op_array(brake->ops TSRMLS_CC); efree(brake->ops); } - efree((char*)brake->code); + efree((char*) brake->code); } } /* }}} */ -static void php_phpdbg_destroy_registered(void *data) /* {{{ */ +static void php_phpdbg_destroy_registered(zval *data) /* {{{ */ { - zend_function *function = (zend_function*) data; + zend_function *function = (zend_function *) Z_PTR_P(data); + TSRMLS_FETCH(); - destroy_zend_function( - function TSRMLS_CC); + destroy_zend_function(function TSRMLS_CC); } /* }}} */ @@ -179,6 +215,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]); zend_hash_destroy(&PHPDBG_G(seek)); zend_hash_destroy(&PHPDBG_G(registered)); + zend_hash_destroy(&PHPDBG_G(file_sources)); zend_hash_destroy(&PHPDBG_G(watchpoints)); zend_llist_destroy(&PHPDBG_G(watchlist_mem)); @@ -186,7 +223,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ efree(PHPDBG_G(buffer)); PHPDBG_G(buffer) = NULL; } - + if (PHPDBG_G(exec)) { efree(PHPDBG_G(exec)); PHPDBG_G(exec) = NULL; @@ -224,10 +261,9 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ If the request to set the context fails, boolean false is returned, and an E_WARNING raised */ static PHP_FUNCTION(phpdbg_exec) { - char *exec = NULL; - int exec_len = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) { + zend_string *exec; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S", &exec) == FAILURE) { return; } @@ -235,27 +271,26 @@ static PHP_FUNCTION(phpdbg_exec) struct stat sb; zend_bool result = 1; - if (VCWD_STAT(exec, &sb) != FAILURE) { + if (VCWD_STAT(exec->val, &sb) != FAILURE) { if (sb.st_mode & (S_IFREG|S_IFLNK)) { if (PHPDBG_G(exec)) { - ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len), 1); + ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len)); efree(PHPDBG_G(exec)); result = 0; } - PHPDBG_G(exec) = estrndup(exec, exec_len); - PHPDBG_G(exec_len) = exec_len; + PHPDBG_G(exec) = estrndup(exec->val, exec->len); + PHPDBG_G(exec_len) = exec->len; - if (result) + if (result) { ZVAL_BOOL(return_value, 1); + } } else { - zend_error( - E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec); + zend_error(E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec); ZVAL_BOOL(return_value, 0); } } else { - zend_error( - E_WARNING, "Failed to set execution context (%s) the file does not exist", exec); + zend_error(E_WARNING, "Failed to set execution context (%s) the file does not exist", exec); ZVAL_BOOL(return_value, 0); } @@ -279,13 +314,8 @@ static PHP_FUNCTION(phpdbg_break) phpdbg_parse_param(expr, expr_len, ¶m TSRMLS_CC); phpdbg_do_break(¶m TSRMLS_CC); phpdbg_clear_param(¶m TSRMLS_CC); - - } else if (EG(current_execute_data) && EG(active_op_array)) { - zend_ulong opline_num = (EG(current_execute_data)->opline - - EG(active_op_array)->opcodes); - - phpdbg_set_breakpoint_opline_ex( - &EG(active_op_array)->opcodes[opline_num+1] TSRMLS_CC); + } else if (EG(current_execute_data) && EG(current_execute_data)->func->type != ZEND_INTERNAL_FUNCTION) { + phpdbg_set_breakpoint_opline_ex((phpdbg_opline_ptr_t) EG(current_execute_data)->opline + 1 TSRMLS_CC); } } /* }}} */ @@ -426,7 +456,12 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ * We must not request TSRM before being boot */ if (phpdbg_booted) { - phpdbg_error("%s", message); + if (PHPDBG_G(flags) & PHPDBG_IN_EVAL) { + phpdbg_error("eval", "msg=\"%s\"", "%s", message); + return; + } + + phpdbg_error("php", "msg=\"%s\"", "%s", message); switch (PG(last_error_type)) { case E_ERROR: @@ -436,17 +471,14 @@ static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */ case E_PARSE: case E_RECOVERABLE_ERROR: if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { - phpdbg_list_file( - zend_get_executed_filename(TSRMLS_C), - 3, - zend_get_executed_lineno(TSRMLS_C)-1, - zend_get_executed_lineno(TSRMLS_C) - TSRMLS_CC - ); + const char *file_char = zend_get_executed_filename(TSRMLS_C); + zend_string *file = zend_string_init(file_char, strlen(file_char), 0); + phpdbg_list_file(file, 3, zend_get_executed_lineno(TSRMLS_C) - 1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); + efree(file); } do { - switch (phpdbg_interactive(TSRMLS_C)) { + switch (phpdbg_interactive(1 TSRMLS_CC)) { case PHPDBG_LEAVE: case PHPDBG_FINISH: case PHPDBG_UNTIL: @@ -473,8 +505,8 @@ static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */ static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* {{{ */ { - unsigned int len; - char *docroot = ""; + size_t len; + char *docroot = ""; /* In phpdbg mode, we consider the environment to be a part of the server variables */ @@ -482,43 +514,67 @@ static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* { if (PHPDBG_G(exec)) { len = PHPDBG_G(exec_len); - if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", - &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { - php_register_variable("PHP_SELF", PHPDBG_G(exec), - track_vars_array TSRMLS_CC); + if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { + php_register_variable("PHP_SELF", PHPDBG_G(exec), track_vars_array TSRMLS_CC); } - if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", - &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { - php_register_variable("SCRIPT_NAME", PHPDBG_G(exec), - track_vars_array TSRMLS_CC); + if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { + php_register_variable("SCRIPT_NAME", PHPDBG_G(exec), track_vars_array TSRMLS_CC); } - if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", - &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { - php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec), - track_vars_array TSRMLS_CC); + if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { + php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec), track_vars_array TSRMLS_CC); } - if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", - &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { - php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec), - track_vars_array TSRMLS_CC); + if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) { + php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec), track_vars_array TSRMLS_CC); } } - /* any old docroot will doo */ - len = 0U; - if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", - &docroot, len, &len TSRMLS_CC)) { + /* any old docroot will do */ + len = 0; + if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", &docroot, len, &len TSRMLS_CC)) { php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array TSRMLS_CC); } } /* }}} */ -static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */ +static inline size_t php_sapi_phpdbg_ub_write(const char *message, size_t length TSRMLS_DC) /* {{{ */ { - return phpdbg_write("%s", message); + if (PHPDBG_G(socket_fd) != -1 && !(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { + send(PHPDBG_G(socket_fd), message, length, 0); + } + return phpdbg_script(P_STDOUT, "%.*s", length, message); } /* }}} */ +/* beginning of struct, see main/streams/plain_wrapper.c line 111 */ +typedef struct { + FILE *file; + int fd; +} php_stdio_stream_data; + +static size_t phpdbg_stdiop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) { + php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; + + while (data->fd >= 0) { + struct stat stat[3]; + memset(stat, 0, sizeof(stat)); + if (((fstat(fileno(stderr), &stat[2]) < 0) & (fstat(fileno(stdout), &stat[0]) < 0)) | (fstat(data->fd, &stat[1]) < 0)) { + break; + } + + if (stat[0].st_dev == stat[1].st_dev && stat[0].st_ino == stat[1].st_ino) { + phpdbg_script(P_STDOUT, "%.*s", (int) count, buf); + return count; + } + if (stat[2].st_dev == stat[1].st_dev && stat[2].st_ino == stat[1].st_ino) { + phpdbg_script(P_STDERR, "%.*s", (int) count, buf); + return count; + } + break; + } + + return PHPDBG_G(php_stdiop_write)(stream, buf, count TSRMLS_CC); +} + #if PHP_VERSION_ID >= 50700 static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC) /* {{{ */ { @@ -528,29 +584,24 @@ static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */ TSRMLS_FETCH(); #endif - fflush(PHPDBG_G(io)[PHPDBG_STDOUT]); + if (!phpdbg_active_sigsafe_mem(TSRMLS_C)) { + fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr); + } } /* }}} */ /* copied from sapi/cli/php_cli.c cli_register_file_handles */ static void phpdbg_register_file_handles(TSRMLS_D) /* {{{ */ { - zval *zin, *zout, *zerr; + zval zin, zout, zerr; php_stream *s_in, *s_out, *s_err; php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL; zend_constant ic, oc, ec; - MAKE_STD_ZVAL(zin); - MAKE_STD_ZVAL(zout); - MAKE_STD_ZVAL(zerr); - s_in = php_stream_open_wrapper_ex("php://stdin", "rb", 0, NULL, sc_in); s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out); s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err); if (s_in==NULL || s_out==NULL || s_err==NULL) { - FREE_ZVAL(zin); - FREE_ZVAL(zout); - FREE_ZVAL(zerr); if (s_in) php_stream_close(s_in); if (s_out) php_stream_close(s_out); if (s_err) php_stream_close(s_err); @@ -563,34 +614,27 @@ static void phpdbg_register_file_handles(TSRMLS_D) /* {{{ */ s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE; #endif - php_stream_to_zval(s_in, zin); - php_stream_to_zval(s_out, zout); - php_stream_to_zval(s_err, zerr); + php_stream_to_zval(s_in, &zin); + php_stream_to_zval(s_out, &zout); + php_stream_to_zval(s_err, &zerr); - ic.value = *zin; + ic.value = zin; ic.flags = CONST_CS; - ic.name = zend_strndup(ZEND_STRL("STDIN")); - ic.name_len = sizeof("STDIN"); + ic.name = zend_string_init(ZEND_STRL("STDIN"), 0); ic.module_number = 0; zend_register_constant(&ic TSRMLS_CC); - oc.value = *zout; + oc.value = zout; oc.flags = CONST_CS; - oc.name = zend_strndup(ZEND_STRL("STDOUT")); - oc.name_len = sizeof("STDOUT"); + oc.name = zend_string_init(ZEND_STRL("STDOUT"), 0); oc.module_number = 0; zend_register_constant(&oc TSRMLS_CC); - ec.value = *zerr; + ec.value = zerr; ec.flags = CONST_CS; - ec.name = zend_strndup(ZEND_STRL("STDERR")); - ec.name_len = sizeof("STDERR"); + ec.name = zend_string_init(ZEND_STRL("STDERR"), 0); ec.module_number = 0; zend_register_constant(&ec TSRMLS_CC); - - FREE_ZVAL(zin); - FREE_ZVAL(zout); - FREE_ZVAL(zerr); } /* }}} */ @@ -648,6 +692,7 @@ const opt_struct OPTIONS[] = { /* {{{ */ {'l', 1, "listen"}, {'a', 1, "address-or-any"}, #endif + {'x', 0, "xml output"}, {'V', 0, "version"}, {'-', 0, NULL} }; /* }}} */ @@ -664,10 +709,9 @@ const char phpdbg_ini_hardcoded[] = /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */ #define INI_DEFAULT(name, value) \ + ZVAL_STRINGL(&tmp, value, sizeof(value) - 1); \ Z_SET_REFCOUNT(tmp, 0); \ - Z_UNSET_ISREF(tmp); \ - ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \ - zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL); + zend_hash_str_update(configuration_hash, name, sizeof(name) - 1, &tmp); void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */ { @@ -679,17 +723,25 @@ static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */ { /* print blurb */ if (!cleaning) { - phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", - PHPDBG_VERSION); - phpdbg_writeln("To get help using phpdbg type \"help\" and press enter"); - phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES); + phpdbg_xml("<intros>"); + phpdbg_notice("intro", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); + phpdbg_writeln("intro", "help=\"help\"", "To get help using phpdbg type \"help\" and press enter"); + phpdbg_notice("intro", "report=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES); + phpdbg_xml("</intros>"); } else { - phpdbg_notice("Clean Execution Environment"); + if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) { + phpdbg_notice(NULL, NULL, "Clean Execution Environment"); + } - phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table))); - phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants))); - phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files))); + phpdbg_write("cleaninfo", "classes=\"%d\" functions=\"%d\" constants=\"%d\" includes=\"%d\"", + "Classes %d\n" + "Functions %d\n" + "Constants %d\n" + "Includes %d\n", + zend_hash_num_elements(EG(class_table)), + zend_hash_num_elements(EG(function_table)), + zend_hash_num_elements(EG(zend_constants)), + zend_hash_num_elements(&EG(included_files))); } } /* }}} */ @@ -697,163 +749,129 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */ { TSRMLS_FETCH(); - if (EG(in_execution)) { - /* set signalled only when not interactive */ - if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { - PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; - } - } else { + if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) { /* we quit remote consoles on recv SIGINT */ if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; zend_bailout(); } - } -} /* }}} */ - -#ifndef _WIN32 -int phpdbg_open_socket(const char *interface, short port) /* {{{ */ -{ - int fd = socket(AF_INET, SOCK_STREAM, 0); - - switch (fd) { - case -1: - return -1; - - default: { - int reuse = 1; - - switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) { - case -1: - close(fd); - return -2; - - default: { - struct sockaddr_in address; - - memset(&address, 0, sizeof(address)); - - address.sin_port = htons(port); - address.sin_family = AF_INET; - - if ((*interface == '*')) { - address.sin_addr.s_addr = htonl(INADDR_ANY); - } else if (!inet_pton(AF_INET, interface, &address.sin_addr)) { - close(fd); - return -3; - } - - switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) { - case -1: - close(fd); - return -4; - - default: { - listen(fd, 5); - } - } - } + } else { + /* set signalled only when not interactive */ + if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { + if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { + char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1]; + + phpdbg_set_sigsafe_mem(mem TSRMLS_CC); + zend_try { + phpdbg_force_interruption(TSRMLS_C); + } zend_end_try() + phpdbg_clear_sigsafe_mem(TSRMLS_C); + return; } + PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; } } - - return fd; } /* }}} */ -static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */ -{ - if ((*socket)[0] >= 0) { - shutdown( - (*socket)[0], SHUT_RDWR); - close((*socket)[0]); +static void phpdbg_remote_close(int socket, FILE *stream) { + if (socket >= 0) { + phpdbg_close_socket(socket); } - if (streams[0]) { - fclose(streams[0]); + if (stream) { + fclose(stream); } +} - if ((*socket)[1] >= 0) { - shutdown( - (*socket)[1], SHUT_RDWR); - close((*socket)[1]); - } +/* don't inline this, want to debug it easily, will inline when done */ +static int phpdbg_remote_init(const char* address, unsigned short port, int server, int *socket, FILE **stream TSRMLS_DC) { + phpdbg_remote_close(*socket, *stream); + + if (server < 0) { + phpdbg_rlog(fileno(stderr), "Initializing connection on %s:%u failed", address, port); - if (streams[1]) { - fclose(streams[1]); + return FAILURE; } -} /* }}} */ -/* don't inline this, want to debug it easily, will inline when done */ + phpdbg_rlog(fileno(stderr), "accepting connections on %s:%u", address, port); + { + struct sockaddr_storage address; + socklen_t size = sizeof(address); + char buffer[20] = {0}; + /* XXX error checks */ + memset(&address, 0, size); + *socket = accept(server, (struct sockaddr *) &address, &size); + inet_ntop(AF_INET, &(((struct sockaddr_in *)&address)->sin_addr), buffer, sizeof(buffer)); -int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */ -{ - if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) { - ((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]); - ((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]); + phpdbg_rlog(fileno(stderr), "connection established from %s", buffer); } - streams[0] = NULL; - streams[1] = NULL; - - if ((*listen)[0] < 0 || (*listen)[1] < 0) { - if ((*listen)[0] < 0) { - phpdbg_rlog(stderr, - "console failed to initialize (stdin) on %s:%d", address, port[0]); - } +#ifndef _WIN32 + dup2(*socket, fileno(stdout)); + dup2(*socket, fileno(stdin)); - if ((*listen)[1] < 0) { - phpdbg_rlog(stderr, - "console failed to initialize (stdout) on %s:%d", address, port[1]); - } + setbuf(stdout, NULL); - if ((*listen)[0] >= 0) { - close((*listen)[0]); - } + *stream = fdopen(*socket, "r+"); - if ((*listen)[1] >= 0) { - close((*listen)[1]); - } + phpdbg_set_async_io(*socket); +#endif + return SUCCESS; +} - return FAILURE; - } +#ifndef _WIN32 +/* This function *strictly* assumes that SIGIO is *only* used on the remote connection stream */ +void phpdbg_sigio_handler(int sig, siginfo_t *info, void *context) /* {{{ */ +{ + int flags; + size_t newlen; + size_t i/*, last_nl*/; + TSRMLS_FETCH(); - phpdbg_close_sockets(socket, streams); +// if (!(info->si_band & POLLIN)) { +// return; /* Not interested in writeablility etc., just interested in incoming data */ +// } - phpdbg_rlog(stderr, - "accepting connections on %s:%d/%d", address, port[0], port[1]); - { - struct sockaddr_in address; - socklen_t size = sizeof(address); - char buffer[20] = {0}; + /* only non-blocking reading, avoid non-blocking writing */ + flags = fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_GETFL, 0); + fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags | O_NONBLOCK); - { - memset(&address, 0, size); - (*socket)[0] = accept( - (*listen)[0], (struct sockaddr *) &address, &size); - inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer)); + do { + char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1]; + size_t off = 0; - phpdbg_rlog(stderr, "connection (stdin) from %s", buffer); + if ((newlen = recv(PHPDBG_G(io)[PHPDBG_STDIN].fd, mem, PHPDBG_SIGSAFE_MEM_SIZE, MSG_PEEK)) == (size_t) -1) { + break; } - - { - memset(&address, 0, size); - (*socket)[1] = accept( - (*listen)[1], (struct sockaddr *) &address, &size); - inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer)); - - phpdbg_rlog(stderr, "connection (stdout) from %s", buffer); + for (i = 0; i < newlen; i++) { + switch (mem[off + i]) { + case '\x03': /* ^C char */ + if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) { + break; /* or quit ??? */ + } + if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { + phpdbg_set_sigsafe_mem(mem TSRMLS_CC); + zend_try { + phpdbg_force_interruption(TSRMLS_C); + } zend_end_try(); + phpdbg_clear_sigsafe_mem(TSRMLS_C); + break; + } + if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) { + PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED; + } + break; +/* case '\n': + zend_llist_add_element(PHPDBG_G(stdin), strndup() + last_nl = PHPDBG_G(stdin_buf).len + i; + break; +*/ } } - } + off += i; + } while (0); - dup2((*socket)[0], fileno(stdin)); - dup2((*socket)[1], fileno(stdout)); - - setbuf(stdout, NULL); - streams[0] = fdopen((*socket)[0], "r"); - streams[1] = fdopen((*socket)[1], "w"); - - return SUCCESS; + fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags); } /* }}} */ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */ @@ -864,6 +882,9 @@ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */ switch (sig) { case SIGBUS: case SIGSEGV: + if (PHPDBG_G(sigsegv_bailout)) { + LONGJMP(*PHPDBG_G(sigsegv_bailout), FAILURE); + } is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC); if (is_handled == FAILURE) { #ifdef ZEND_SIGNALS @@ -938,10 +959,10 @@ int main(int argc, char **argv) /* {{{ */ #ifndef _WIN32 char *address; - int listen[2]; - int server[2]; - int socket[2]; - FILE* streams[2] = {NULL, NULL}; + int listen = -1; + int server = -1; + int socket = -1; + FILE* stream = NULL; #endif #ifdef ZTS @@ -949,19 +970,15 @@ int main(int argc, char **argv) /* {{{ */ #endif #ifndef _WIN32 + struct sigaction sigio_struct; struct sigaction signal_struct; signal_struct.sa_sigaction = phpdbg_signal_handler; signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER; + sigio_struct.sa_sigaction = phpdbg_sigio_handler; + sigio_struct.sa_flags = SA_SIGINFO; + address = strdup("127.0.0.1"); - socket[0] = -1; - socket[1] = -1; - listen[0] = -1; - listen[1] = -1; - server[0] = -1; - server[1] = -1; - streams[0] = NULL; - streams[1] = NULL; #endif #ifdef PHP_WIN32 @@ -991,7 +1008,7 @@ phpdbg_main: } if (!bp_tmp_file) { - phpdbg_error("Unable to create temporary file"); + phpdbg_error("tmpfile", "", "Unable to create temporary file"); return 1; } #else @@ -1126,20 +1143,12 @@ phpdbg_main: break; #ifndef _WIN32 - /* if you pass a listen port, we will accept input on listen port */ - /* and write output to listen port * 2 */ - - case 'l': { /* set listen ports */ - if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) { - if (sscanf(php_optarg, "%d", &listen[0]) != 1) { - /* default to hardcoded ports */ - listen[0] = 4000; - listen[1] = 8000; - } else { - listen[1] = (listen[0] * 2); - } + /* if you pass a listen port, we will read and write on listen port */ + case 'l': /* set listen ports */ + if (sscanf(php_optarg, "%d", &listen) != 1) { + listen = 8000; } - } break; + break; case 'a': { /* set bind address */ free(address); @@ -1149,6 +1158,10 @@ phpdbg_main: } break; #endif + case 'x': + flags |= PHPDBG_WRITE_XML; + break; + case 'V': { sapi_startup(phpdbg); phpdbg->startup(phpdbg); @@ -1180,19 +1193,6 @@ phpdbg_main: php_optind++; } -#ifndef _WIN32 - /* setup remote server if necessary */ - if (!cleaning && - (listen[0] > 0 && listen[1] > 0)) { - if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) { - remote = 0; - exit(0); - } - /* set remote flag to stop service shutting down upon quit */ - remote = 1; - } -#endif - if (sapi_name) { phpdbg->name = sapi_name; } @@ -1247,19 +1247,47 @@ phpdbg_main: EXCEPTION_POINTERS *xp; __try { #endif - zend_mm_heap *mm_heap = phpdbg_mm_get_heap(); + zend_mm_heap *mm_heap; + void* (*_malloc)(size_t); + void (*_free)(void*); + void* (*_realloc)(void*, size_t); - if (mm_heap->use_zend_alloc) { - mm_heap->_malloc = phpdbg_malloc_wrapper; - mm_heap->_realloc = phpdbg_realloc_wrapper; - mm_heap->_free = phpdbg_free_wrapper; - mm_heap->use_zend_alloc = 0; +#ifndef _WIN32 + /* setup remote server if necessary */ + if (!cleaning && listen > 0) { + server = phpdbg_open_socket(address, listen TSRMLS_CC); + if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC) == FAILURE) { + exit(0); + } + + sigaction(SIGIO, &sigio_struct, NULL); + + /* set remote flag to stop service shutting down upon quit */ + remote = 1; + } +#endif + + mm_heap = phpdbg_mm_get_heap(); + zend_mm_get_custom_handlers(mm_heap, &_malloc, &_free, &_realloc); + + if (!_malloc) { + _malloc = phpdbg_malloc_wrapper; + } + if (!_realloc) { + _realloc = phpdbg_realloc_wrapper; + } + if (!_free) { + _free = phpdbg_free_wrapper; } zend_activate(TSRMLS_C); - PHPDBG_G(original_free_function) = mm_heap->_free; - mm_heap->_free = phpdbg_watch_efree; + phpdbg_init_list(TSRMLS_C); + + PHPDBG_G(original_free_function) = _free; + _free = phpdbg_watch_efree; + + zend_mm_set_custom_handlers(mm_heap, _malloc, _free, _realloc); phpdbg_setup_watchpoints(TSRMLS_C); @@ -1277,10 +1305,17 @@ phpdbg_main: sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); #endif + PHPDBG_G(sapi_name_ptr) = sapi_name; + + php_output_activate(TSRMLS_C); + php_output_deactivate(TSRMLS_C); + + php_output_activate(TSRMLS_C); + if (php_request_startup(TSRMLS_C) == SUCCESS) { int i; - - SG(request_info).argc = argc - php_optind + 1; + + SG(request_info).argc = argc - php_optind + 1; SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *)); for (i = SG(request_info).argc; --i;) { SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]); @@ -1290,14 +1325,10 @@ phpdbg_main: php_hash_environment(TSRMLS_C); } - /* make sure to turn off buffer for ev command */ - php_output_activate(TSRMLS_C); - php_output_deactivate(TSRMLS_C); - /* do not install sigint handlers for remote consoles */ /* sending SIGINT then provides a decent way of shutting down the server */ #ifndef _WIN32 - if (listen[0] < 0) { + if (listen < 0) { #endif #if defined(ZEND_SIGNALS) && !defined(_WIN32) zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try(); @@ -1315,16 +1346,43 @@ phpdbg_main: #ifndef _WIN32 /* setup io here */ - if (streams[0] && streams[1]) { + if (remote) { PHPDBG_G(flags) |= PHPDBG_IS_REMOTE; signal(SIGPIPE, SIG_IGN); } #endif - PHPDBG_G(io)[PHPDBG_STDIN] = stdin; - PHPDBG_G(io)[PHPDBG_STDOUT] = stdout; - PHPDBG_G(io)[PHPDBG_STDERR] = stderr; +#ifndef _WIN32 + PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin; + PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin); + PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout; + PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout); +#else + /* XXX this is a complete mess here with FILE/fd/SOCKET, + we should let only one to survive probably. Need + a clean separation whether it's a remote or local + prompt. And what is supposed to go as user interaction, + error log, etc. */ + if (remote) { + PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin; + PHPDBG_G(io)[PHPDBG_STDIN].fd = socket; + PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout; + PHPDBG_G(io)[PHPDBG_STDOUT].fd = socket; + } else { + PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin; + PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin); + PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout; + PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout); + } +#endif + PHPDBG_G(io)[PHPDBG_STDERR].ptr = stderr; + PHPDBG_G(io)[PHPDBG_STDERR].fd = fileno(stderr); + +#ifndef _WIN32 + PHPDBG_G(php_stdiop_write) = php_stream_stdio_ops.write; + php_stream_stdio_ops.write = phpdbg_stdiop_write; +#endif if (exec) { /* set execution context */ PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC); @@ -1336,8 +1394,7 @@ phpdbg_main: if (oplog_file) { /* open oplog */ PHPDBG_G(oplog) = fopen(oplog_file, "w+"); if (!PHPDBG_G(oplog)) { - phpdbg_error( - "Failed to open oplog %s", oplog_file); + phpdbg_error("oplog", "path=\"%s\"", "Failed to open oplog %s", oplog_file); } free(oplog_file); } @@ -1348,7 +1405,7 @@ phpdbg_main: phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green") TSRMLS_CC); /* set default prompt */ - phpdbg_set_prompt(PROMPT TSRMLS_CC); + phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT TSRMLS_CC); /* Make stdin, stdout and stderr accessible from PHP scripts */ phpdbg_register_file_handles(TSRMLS_C); @@ -1397,7 +1454,7 @@ phpdbg_interact: /* phpdbg main() */ do { zend_try { - phpdbg_interactive(TSRMLS_C); + phpdbg_interactive(1 TSRMLS_CC); } zend_catch { if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) { FILE *bp_tmp_fp = fopen(bp_tmp_file, "w"); @@ -1415,11 +1472,10 @@ phpdbg_interact: if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { /* renegociate connections */ - phpdbg_open_sockets( - address, listen, &server, &socket, streams); + phpdbg_remote_init(address, listen, server, &socket, &stream TSRMLS_CC); /* set streams */ - if (streams[0] && streams[1]) { + if (stream) { PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING; } @@ -1451,11 +1507,11 @@ phpdbg_out: #ifdef _WIN32 } __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) { - phpdbg_error("Access violation (Segementation fault) encountered\ntrying to abort cleanly..."); + phpdbg_error("segfault", "", "Access violation (Segementation fault) encountered\ntrying to abort cleanly..."); } phpdbg_out: #endif - + { int i; /* free argv */ @@ -1468,8 +1524,7 @@ phpdbg_out: #ifndef ZTS /* force cleanup of auto and core globals */ zend_hash_clean(CG(auto_globals)); - memset( - &core_globals, 0, sizeof(php_core_globals)); + memset( &core_globals, 0, sizeof(php_core_globals)); #endif if (ini_entries) { free(ini_entries); @@ -1478,15 +1533,17 @@ phpdbg_out: if (ini_override) { free(ini_override); } - + /* this must be forced */ CG(unclean_shutdown) = 0; - + /* this is just helpful */ PG(report_memleaks) = 0; php_request_shutdown((void*)0); + php_output_deactivate(TSRMLS_C); + zend_try { php_module_shutdown(TSRMLS_C); } zend_end_try(); @@ -1498,7 +1555,7 @@ phpdbg_out: if (cleaning || remote) { goto phpdbg_main; } - + #ifdef ZTS /* bugggy */ /* tsrm_shutdown(); */ @@ -1510,10 +1567,10 @@ phpdbg_out: } #endif - if (sapi_name) { - free(sapi_name); + if (PHPDBG_G(sapi_name_ptr)) { + free(PHPDBG_G(sapi_name_ptr)); } - + #ifdef _WIN32 free(bp_tmp_file); #else diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h index 364ef7d176..f3e8ba3107 100644 --- a/sapi/phpdbg/phpdbg.h +++ b/sapi/phpdbg/phpdbg.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -29,6 +29,8 @@ # define PHPDBG_API #endif +#include <stdint.h> +#include <stddef.h> #include "php.h" #include "php_globals.h" #include "php_variables.h" @@ -40,20 +42,21 @@ #include "zend_ini_scanner.h" #include "zend_stream.h" #ifndef _WIN32 -# include "zend_signal.h" +# include "zend_signal.h" #endif #include "SAPI.h" #include <fcntl.h> #include <sys/types.h> #if defined(_WIN32) && !defined(__MINGW32__) -# include <windows.h> -# include "config.w32.h" -# undef strcasecmp -# undef strncasecmp -# define strcasecmp _stricmp -# define strncasecmp _strnicmp +# include <windows.h> +# include "config.w32.h" +# include "win32/php_stdint.h" +# undef strcasecmp +# undef strncasecmp +# define strcasecmp _stricmp +# define strncasecmp _strnicmp #else -# include "php_config.h" +# include "php_config.h" #endif #ifndef O_BINARY # define O_BINARY 0 @@ -64,21 +67,64 @@ # include "TSRM.h" #endif -#ifdef LIBREADLINE -# include <readline/readline.h> -# include <readline/history.h> +#define ZEND_HASH_FOREACH_NUM_KEY_PTR(ht, _h, _ptr) \ + ZEND_HASH_FOREACH(ht, 0); \ + _h = _p->h; \ + _ptr = Z_PTR_P(_z); + +#undef zend_hash_str_add +#define zend_hash_str_add_tmp(ht, key, len, pData) \ + _zend_hash_str_add(ht, key, len, pData ZEND_FILE_LINE_CC) +#define zend_hash_str_add(...) zend_hash_str_add_tmp(__VA_ARGS__) + +static zend_always_inline void *zend_hash_index_add_mem(HashTable *ht, zend_ulong h, void *pData, size_t size) +{ + zval tmp, *zv; + + ZVAL_PTR(&tmp, NULL); + if ((zv = zend_hash_index_add(ht, h, &tmp))) { + Z_PTR_P(zv) = pemalloc(size, ht->u.flags & HASH_FLAG_PERSISTENT); + memcpy(Z_PTR_P(zv), pData, size); + return Z_PTR_P(zv); + } + return NULL; +} + +#ifdef HAVE_LIBREADLINE +# include <readline/readline.h> +# include <readline/history.h> #endif #ifdef HAVE_LIBEDIT -# include <editline/readline.h> +# include <editline/readline.h> #endif -#include "phpdbg_lexer.h" -#include "phpdbg_cmd.h" -#include "phpdbg_utils.h" -#include "phpdbg_btree.h" -#include "phpdbg_watch.h" +/* {{{ remote console headers */ +#ifndef _WIN32 +# include <sys/socket.h> +# include <sys/un.h> +# include <sys/select.h> +# include <sys/types.h> +# include <netdb.h> +#endif /* }}} */ -int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); +/* {{{ strings */ +#define PHPDBG_NAME "phpdbg" +#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ +#define PHPDBG_URL "http://phpdbg.com" +#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" +#define PHPDBG_VERSION "0.4.0" +#define PHPDBG_INIT_FILENAME ".phpdbginit" +#define PHPDBG_DEFAULT_PROMPT "prompt>" +/* }}} */ + +/* Hey, apple. One shouldn't define *functions* from the standard C library as marcos. */ +#ifdef memcpy +#define memcpy_tmp(...) memcpy(__VA_ARGS__) +#undef memcpy +#define memcpy(...) memcpy_tmp(__VA_ARGS__) +#endif + +#if !defined(PHPDBG_WEBDATA_TRANSFER_H) && !defined(PHPDBG_WEBHELPER_H) #ifdef ZTS # define PHPDBG_G(v) TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v) @@ -86,6 +132,19 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); # define PHPDBG_G(v) (phpdbg_globals.v) #endif +#include "phpdbg_sigsafe.h" +#include "phpdbg_out.h" +#include "phpdbg_lexer.h" +#include "phpdbg_cmd.h" +#include "phpdbg_utils.h" +#include "phpdbg_btree.h" +#include "phpdbg_watch.h" +#ifdef PHP_WIN32 +# include "phpdbg_sigio_win32.h" +#endif + +int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); + #define PHPDBG_NEXT 2 #define PHPDBG_UNTIL 3 #define PHPDBG_FINISH 4 @@ -145,11 +204,14 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); #define PHPDBG_IS_BP_ENABLED (1<<26) #define PHPDBG_IS_REMOTE (1<<27) #define PHPDBG_IS_DISCONNECTED (1<<28) +#define PHPDBG_WRITE_XML (1<<29) + +#define PHPDBG_SHOW_REFCOUNTS (1<<30) -#define PHPDBG_SHOW_REFCOUNTS (1<<29) +#define PHPDBG_IN_SIGNAL_HANDLER (1<<30) #define PHPDBG_SEEK_MASK (PHPDBG_IN_UNTIL|PHPDBG_IN_FINISH|PHPDBG_IN_LEAVE) -#define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP) +#define PHPDBG_BP_RESOLVE_MASK (PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP) #define PHPDBG_BP_MASK (PHPDBG_HAS_FILE_BP|PHPDBG_HAS_SYM_BP|PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_OPLINE_BP|PHPDBG_HAS_COND_BP|PHPDBG_HAS_OPCODE_BP|PHPDBG_HAS_FUNCTION_OPLINE_BP|PHPDBG_HAS_METHOD_OPLINE_BP|PHPDBG_HAS_FILE_OPLINE_BP) #ifndef _WIN32 @@ -158,21 +220,27 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC); # define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET|PHPDBG_IS_BP_ENABLED) #endif /* }}} */ -/* {{{ strings */ -#define PHPDBG_NAME "phpdbg" -#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */ -#define PHPDBG_URL "http://phpdbg.com" -#define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues" -#define PHPDBG_VERSION "0.4.0" -#define PHPDBG_INIT_FILENAME ".phpdbginit" -/* }}} */ - /* {{{ output descriptors */ #define PHPDBG_STDIN 0 #define PHPDBG_STDOUT 1 #define PHPDBG_STDERR 2 #define PHPDBG_IO_FDS 3 /* }}} */ +#define phpdbg_try_access \ + { \ + JMP_BUF *__orig_bailout = PHPDBG_G(sigsegv_bailout); \ + JMP_BUF __bailout; \ + \ + PHPDBG_G(sigsegv_bailout) = &__bailout; \ + if (SETJMP(__bailout) == 0) { +#define phpdbg_catch_access \ + } else { \ + PHPDBG_G(sigsegv_bailout) = __orig_bailout; +#define phpdbg_end_try_access() \ + } \ + PHPDBG_G(sigsegv_bailout) = __orig_bailout; \ + } + /* {{{ structs */ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) @@ -180,7 +248,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) HashTable registered; /* registered */ HashTable seek; /* seek oplines */ phpdbg_frame_t frame; /* frame */ - uint32_t last_line; /* last executed line */ + uint32_t last_line; /* last executed line */ phpdbg_lexer_data lexer; /* lexer data */ phpdbg_param_t *parser_stack; /* param stack during lexer / parser phase */ @@ -191,6 +259,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) phpdbg_btree watchpoint_tree; /* tree with watchpoints */ phpdbg_btree watch_HashTables; /* tree with original dtors of watchpoints */ HashTable watchpoints; /* watchpoints */ + HashTable watch_collisions; /* collision table to check if multiple watches share the same recursive watchpoint */ zend_llist watchlist_mem; /* triggered watchpoints */ zend_bool watchpoint_hit; /* a watchpoint was hit */ void (*original_free_function)(void *); /* the original AG(mm_heap)->_free function */ @@ -198,33 +267,57 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) char *exec; /* file to execute */ size_t exec_len; /* size of exec */ zend_op_array *ops; /* op_array */ - zval *retval; /* return value */ + zval retval; /* return value */ int bp_count; /* breakpoint count */ int vmret; /* return from last opcode handler execution */ + zend_bool in_execution; /* in execution? */ + + zend_op_array *(*compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC); + HashTable file_sources; FILE *oplog; /* opline log */ - FILE *io[PHPDBG_IO_FDS]; /* io */ + struct { + FILE *ptr; + int fd; + } io[PHPDBG_IO_FDS]; /* io */ + size_t (*php_stdiop_write)(php_stream *, const char *, size_t TSRMLS_DC); + int in_script_xml; /* in <stream> output mode */ + struct { + zend_bool active; + int type; + int fd; + char *tag; + char *msg; + int msglen; + char *xml; + int xmllen; + } err_buf; /* error buffer */ + zend_ulong req_id; /* "request id" to keep track of commands */ char *prompt[2]; /* prompt */ const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */ char *buffer; /* buffer */ + zend_bool last_was_newline; /* check if we don't need to output a newline upon next phpdbg_error or phpdbg_notice */ + + char input_buffer[PHPDBG_MAX_CMD]; /* stdin input buffer */ + int input_buflen; /* length of stdin input buffer */ + phpdbg_signal_safe_mem sigsafe_mem; /* memory to use in async safe environment (only once!) */ + + JMP_BUF *sigsegv_bailout; /* bailout address for accesibility probing */ zend_ulong flags; /* phpdbg flags */ + + char *socket_path; /* phpdbg.path ini setting */ + char *sapi_name_ptr; /* store sapi name to free it if necessary to not leak memory */ + int socket_fd; /* file descriptor to socket (wait command) (-1 if unused) */ + int socket_server_fd; /* file descriptor to master socket (wait command) (-1 if unused) */ +#ifdef PHP_WIN32 + HANDLE sigio_watcher_thread; /* sigio watcher thread handle */ + struct win32_sigio_watcher_data swd; +#endif + int8_t eol; ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */ -/* the beginning (= the important part) of the _zend_mm_heap struct defined in Zend/zend_alloc.c - Needed for realizing watchpoints */ -struct _zend_mm_heap { - int use_zend_alloc; - void *(*_malloc)(size_t); - void (*_free)(void *); - void *(*_realloc)(void *, size_t); - size_t free_bitmap; - size_t large_free_bitmap; - size_t block_size; - size_t compact_size; - zend_mm_segment *segments_list; - zend_mm_storage *storage; -}; +#endif #endif /* PHPDBG_H */ diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index e30b87c313..aaeaee13fd 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -43,8 +43,7 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut */ static inline void _phpdbg_break_mapping(int id, HashTable *table TSRMLS_DC) { - zend_hash_index_update( - &PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (id), (void**) &table, sizeof(void*), NULL); + zend_hash_index_update_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], id, table); } #define PHPDBG_BREAK_MAPPING(id, table) _phpdbg_break_mapping(id, table TSRMLS_CC) @@ -58,29 +57,29 @@ static inline void _phpdbg_break_mapping(int id, HashTable *table TSRMLS_DC) b.hits = 0; \ } while(0) -static void phpdbg_file_breaks_dtor(void *data) /* {{{ */ +static void phpdbg_file_breaks_dtor(zval *data) /* {{{ */ { - phpdbg_breakfile_t *bp = (phpdbg_breakfile_t*) data; + phpdbg_breakfile_t *bp = (phpdbg_breakfile_t*) Z_PTR_P(data); efree((char*)bp->filename); } /* }}} */ -static void phpdbg_class_breaks_dtor(void *data) /* {{{ */ +static void phpdbg_class_breaks_dtor(zval *data) /* {{{ */ { - phpdbg_breakmethod_t *bp = (phpdbg_breakmethod_t*) data; + phpdbg_breakmethod_t *bp = (phpdbg_breakmethod_t *) Z_PTR_P(data); efree((char*)bp->class_name); efree((char*)bp->func_name); } /* }}} */ -static void phpdbg_opline_class_breaks_dtor(void *data) /* {{{ */ +static void phpdbg_opline_class_breaks_dtor(zval *data) /* {{{ */ { - zend_hash_destroy((HashTable *)data); + zend_hash_destroy((HashTable *) Z_PTR_P(data)); } /* }}} */ -static void phpdbg_opline_breaks_dtor(void *data) /* {{{ */ +static void phpdbg_opline_breaks_dtor(zval *data) /* {{{ */ { - phpdbg_breakopline_t *bp = (phpdbg_breakopline_t *) data; + phpdbg_breakopline_t *bp = (phpdbg_breakopline_t *) Z_PTR_P(data); if (bp->class_name) { efree((char*)bp->class_name); @@ -92,45 +91,30 @@ static void phpdbg_opline_breaks_dtor(void *data) /* {{{ */ PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D) /* {{{ */ { - if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) { - HashPosition position[2]; - HashTable **table = NULL; + HashTable *table; - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) { - phpdbg_breakbase_t *brake; + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], table) { + phpdbg_breakbase_t *brake; - for (zend_hash_internal_pointer_reset_ex((*table), &position[1]); - zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS; - zend_hash_move_forward_ex((*table), &position[1])) { - brake->hits = 0; - } - } - } + ZEND_HASH_FOREACH_PTR(table, brake) { + brake->hits = 0; + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); } /* }}} */ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ { - HashPosition position[2]; - HashTable **table = NULL; + HashTable *table; zend_ulong id = 0L; if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) { - phpdbg_notice( - "Exporting %d breakpoints", - zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])); + phpdbg_notice("exportbreakpoint", "count=\"%d\"", "Exporting %d breakpoints", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])); + /* this only looks like magic, it isn't */ - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) { + ZEND_HASH_FOREACH_NUM_KEY_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], id, table) { phpdbg_breakbase_t *brake; - zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], NULL, NULL, &id, 0, &position[0]); - - for (zend_hash_internal_pointer_reset_ex((*table), &position[1]); - zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS; - zend_hash_move_forward_ex((*table), &position[1])) { + ZEND_HASH_FOREACH_PTR(table, brake) { if (brake->id == id) { switch (brake->type) { case PHPDBG_BREAK_FILE: { @@ -155,7 +139,7 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ case PHPDBG_BREAK_METHOD_OPLINE: { fprintf(handle, - "break %s::%s#%ld\n", + "break %s::%s#%llu\n", ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num); @@ -163,14 +147,14 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ case PHPDBG_BREAK_FUNCTION_OPLINE: { fprintf(handle, - "break %s#%ld\n", + "break %s#%llu\n", ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; case PHPDBG_BREAK_FILE_OPLINE: { fprintf(handle, - "break %s:#%ld\n", + "break %s:#%llu\n", ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; @@ -214,8 +198,8 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ } break; } } - } - } + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); } } /* }}} */ @@ -223,27 +207,24 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML { php_stream_statbuf ssb; char realpath[MAXPATHLEN]; - + if (php_stream_stat_path(path, &ssb) != FAILURE) { if (ssb.sb.st_mode & (S_IFREG|S_IFLNK)) { HashTable *broken; phpdbg_breakfile_t new_break; size_t path_len = 0L; - + if (VCWD_REALPATH(path, realpath)) { path = realpath; } path_len = strlen(path); - - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], - path, path_len, (void**)&broken) == FAILURE) { + + if (!(broken = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len))) { HashTable breaks; zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0); - zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], - path, path_len, &breaks, sizeof(HashTable), - (void**)&broken); + broken = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len, &breaks, sizeof(HashTable)); } if (!zend_hash_index_exists(broken, line_num)) { @@ -253,28 +234,26 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML new_break.filename = estrndup(path, path_len); new_break.line = line_num; - zend_hash_index_update( - broken, line_num, (void**)&new_break, sizeof(phpdbg_breakfile_t), NULL); + zend_hash_index_update_mem(broken, line_num, &new_break, sizeof(phpdbg_breakfile_t)); - phpdbg_notice("Breakpoint #%d added at %s:%ld", - new_break.id, new_break.filename, new_break.line); + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line); PHPDBG_BREAK_MAPPING(new_break.id, broken); } else { - phpdbg_error("Breakpoint at %s:%ld exists", path, line_num); + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num); } } else { - phpdbg_error("Cannot set breakpoint in %s, it is not a regular file", path); + phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path); } } else { - phpdbg_error("Cannot stat %s, it does not exist", path); + phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", path); } } /* }}} */ PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len TSRMLS_DC) /* {{{ */ { - if (!zend_hash_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], name, name_len)) { + if (!zend_hash_str_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], name, name_len)) { phpdbg_breaksymbol_t new_break; PHPDBG_G(flags) |= PHPDBG_HAS_SYM_BP; @@ -282,15 +261,13 @@ PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len T PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_SYM); new_break.symbol = estrndup(name, name_len); - zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], new_break.symbol, - name_len, &new_break, sizeof(phpdbg_breaksymbol_t), NULL); + zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], new_break.symbol, name_len, &new_break, sizeof(phpdbg_breaksymbol_t)); - phpdbg_notice("Breakpoint #%d added at %s", - new_break.id, new_break.symbol); + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" function=\"%s\"", "Breakpoint #%d added at %s", new_break.id, new_break.symbol); PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_SYM]); } else { - phpdbg_notice("Breakpoint exists at %s", name); + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" function=\"%s\"", "Breakpoint exists at %s", name); } } /* }}} */ @@ -301,16 +278,12 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char size_t func_len = strlen(func_name); char *lcname = zend_str_tolower_dup(func_name, func_len); - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name, - class_len, (void**)&class_table) != SUCCESS) { + if (!(class_table = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name, class_len))) { zend_hash_init(&class_breaks, 8, NULL, phpdbg_class_breaks_dtor, 0); - zend_hash_update( - &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], - class_name, class_len, - (void**)&class_breaks, sizeof(HashTable), (void**)&class_table); + class_table = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name, class_len, &class_breaks, sizeof(HashTable)); } - if (!zend_hash_exists(class_table, lcname, func_len)) { + if (!zend_hash_str_exists(class_table, lcname, func_len)) { phpdbg_breakmethod_t new_break; PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_BP; @@ -321,15 +294,13 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char new_break.func_name = estrndup(func_name, func_len); new_break.func_len = func_len; - zend_hash_update(class_table, lcname, func_len, - &new_break, sizeof(phpdbg_breakmethod_t), NULL); + zend_hash_str_update_mem(class_table, lcname, func_len, &new_break, sizeof(phpdbg_breakmethod_t)); - phpdbg_notice("Breakpoint #%d added at %s::%s", - new_break.id, class_name, func_name); + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" method=\"%s::%s\"", "Breakpoint #%d added at %s::%s", new_break.id, class_name, func_name); PHPDBG_BREAK_MAPPING(new_break.id, class_table); } else { - phpdbg_notice("Breakpoint exists at %s::%s", class_name, func_name); + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" method=\"%s::%s\"", "Breakpoint exists at %s::%s", class_name, func_name); } efree(lcname); @@ -347,14 +318,12 @@ PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{ new_break.opline = opline; new_break.base = NULL; - zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline, - &new_break, sizeof(phpdbg_breakline_t), NULL); + zend_hash_index_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline, &new_break, sizeof(phpdbg_breakline_t)); - phpdbg_notice("Breakpoint #%d added at %#lx", - new_break.id, new_break.opline); + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" opline=\"%#lx\"", "Breakpoint #%d added at %#lx", new_break.id, new_break.opline); PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); } else { - phpdbg_notice("Breakpoint exists at %#lx", opline); + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" opline=\"%#lx\"", "Breakpoint exists at %#lx", opline); } } /* }}} */ @@ -363,11 +332,11 @@ PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_o phpdbg_breakline_t opline_break; if (op_array->last <= brake->opline_num) { if (brake->class_name == NULL) { - phpdbg_error("There are only %d oplines in function %s (breaking at opline %ld impossible)", op_array->last, brake->func_name, brake->opline_num); + phpdbg_error("breakpoint", "type=\"maxoplines\" add=\"fail\" maxoplinenum=\"%d\" function=\"%s\" usedoplinenum=\"%ld\"", "There are only %d oplines in function %s (breaking at opline %ld impossible)", op_array->last, brake->func_name, brake->opline_num); } else if (brake->func_name == NULL) { - phpdbg_error("There are only %d oplines in file %s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->opline_num); + phpdbg_error("breakpoint", "type=\"maxoplines\" add=\"fail\" maxoplinenum=\"%d\" file=\"%s\" usedoplinenum=\"%ld\"", "There are only %d oplines in file %s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->opline_num); } else { - phpdbg_error("There are only %d oplines in method %s::%s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline_num); + phpdbg_error("breakpoint", "type=\"maxoplines\" add=\"fail\" maxoplinenum=\"%d\" method=\"%s::%s\" usedoplinenum=\"%ld\"", "There are only %d oplines in method %s::%s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline_num); } return FAILURE; @@ -389,7 +358,7 @@ PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_o PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP; - zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline_break.opline, &opline_break, sizeof(phpdbg_breakline_t), NULL); + zend_hash_index_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline_break.opline, &opline_break, sizeof(phpdbg_breakline_t)); return SUCCESS; } /* }}} */ @@ -398,40 +367,36 @@ PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC { HashTable *func_table = &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]; HashTable *oplines_table; - HashPosition position; phpdbg_breakopline_t *brake; - if (op_array->scope != NULL && - zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], op_array->scope->name, op_array->scope->name_length, (void **)&func_table) == FAILURE) { + if (op_array->scope != NULL && !(func_table = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], op_array->scope->name))) { return; } if (op_array->function_name == NULL) { - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], op_array->filename, strlen(op_array->filename), (void **)&oplines_table) == FAILURE) { + if (!(oplines_table = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], op_array->filename))) { return; } - } else if (zend_hash_find(func_table, op_array->function_name?op_array->function_name:"", op_array->function_name?strlen(op_array->function_name):0, (void **)&oplines_table) == FAILURE) { + } else if (!op_array->function_name || !(oplines_table = zend_hash_find_ptr(func_table, op_array->function_name))) { return; } - for (zend_hash_internal_pointer_reset_ex(oplines_table, &position); - zend_hash_get_current_data_ex(oplines_table, (void**) &brake, &position) == SUCCESS; - zend_hash_move_forward_ex(oplines_table, &position)) { + ZEND_HASH_FOREACH_PTR(oplines_table, brake) { if (phpdbg_resolve_op_array_break(brake, op_array TSRMLS_CC) == SUCCESS) { phpdbg_breakline_t *opline_break; zend_hash_internal_pointer_end(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); - zend_hash_get_current_data(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void **)&opline_break); + opline_break = zend_hash_get_current_data_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); - phpdbg_notice("Breakpoint #%d resolved at %s%s%s#%ld (opline %#lx)", + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" symbol=\"%s\" num=\"%ld\" opline=\"%#lx\"", "Breakpoint #%d resolved at %s%s%s#%ld (opline %#lx)", brake->id, - brake->class_name?brake->class_name:"", - brake->class_name&&brake->func_name?"::":"", - brake->func_name?brake->func_name:"", + brake->class_name ? brake->class_name : "", + brake->class_name && brake->func_name ? "::" : "", + brake->func_name ? brake->func_name : "", brake->opline_num, brake->opline); } - } + } ZEND_HASH_FOREACH_END(); } /* }}} */ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC) /* {{{ */ @@ -452,8 +417,9 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRML } else { zend_execute_data *execute_data = EG(current_execute_data); do { - if (execute_data->op_array->function_name == NULL && execute_data->op_array->scope == NULL && !memcmp(execute_data->op_array->filename, new_break->class_name, new_break->class_len)) { - if (phpdbg_resolve_op_array_break(new_break, execute_data->op_array TSRMLS_CC) == SUCCESS) { + zend_op_array *op_array = &execute_data->func->op_array; + if (op_array->function_name == NULL && op_array->scope == NULL && new_break->class_len == op_array->filename->len && !memcmp(op_array->filename->val, new_break->class_name, new_break->class_len)) { + if (phpdbg_resolve_op_array_break(new_break, op_array TSRMLS_CC) == SUCCESS) { return SUCCESS; } else { return 2; @@ -465,16 +431,16 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRML } if (new_break->class_name != NULL) { - zend_class_entry **ce; - if (zend_hash_find(EG(class_table), zend_str_tolower_dup(new_break->class_name, new_break->class_len), new_break->class_len + 1, (void **)&ce) == FAILURE) { + zend_class_entry *ce; + if (!(ce = zend_hash_str_find_ptr(EG(class_table), zend_str_tolower_dup(new_break->class_name, new_break->class_len), new_break->class_len))) { return FAILURE; } - func_table = &(*ce)->function_table; + func_table = &ce->function_table; } - if (zend_hash_find(func_table, zend_str_tolower_dup(new_break->func_name, new_break->func_len), new_break->func_len + 1, (void **)&func) == FAILURE) { + if (!(func = zend_hash_str_find_ptr(func_table, zend_str_tolower_dup(new_break->func_name, new_break->func_len), new_break->func_len))) { if (new_break->class_name != NULL && new_break->func_name != NULL) { - phpdbg_error("Method %s doesn't exist in class %s", new_break->func_name, new_break->class_name); + phpdbg_error("breakpoint", "type=\"nomethod\" method=\"%s::%s\"", "Method %s doesn't exist in class %s", new_break->func_name, new_break->class_name); return 2; } return FAILURE; @@ -482,9 +448,9 @@ PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRML if (func->type != ZEND_USER_FUNCTION) { if (new_break->class_name == NULL) { - phpdbg_error("%s is not an user defined function, no oplines exist", new_break->func_name); + phpdbg_error("breakpoint", "type=\"internalfunction\" function=\"%s\"", "%s is not an user defined function, no oplines exist", new_break->func_name); } else { - phpdbg_error("%s::%s is not an user defined method, no oplines exist", new_break->class_name, new_break->func_name); + phpdbg_error("breakpoint", "type=\"internalfunction\" method=\"%s::%s\"", "%s::%s is not an user defined method, no oplines exist", new_break->class_name, new_break->func_name); } return 2; } @@ -512,37 +478,29 @@ PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const cha switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { case FAILURE: - phpdbg_notice("Pending breakpoint #%d at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); + phpdbg_notice("breakpoint", "pending=\"pending\" id=\"%d\" method=\"%::%s\" num=\"%ld\"", "Pending breakpoint #%d at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); break; case SUCCESS: - phpdbg_notice("Breakpoint #%d added at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); + phpdbg_notice("breakpoint", "id=\"%d\" method=\"%::%s\" num=\"%ld\"", "Breakpoint #%d added at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline); break; case 2: return; } - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], new_break.class_name, new_break.class_len, (void **)&class_table) == FAILURE) { + if (!(class_table = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], new_break.class_name, new_break.class_len))) { zend_hash_init(&class_breaks, 8, NULL, phpdbg_opline_class_breaks_dtor, 0); - zend_hash_update( - &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], - new_break.class_name, - new_break.class_len, - (void **)&class_breaks, sizeof(HashTable), (void **)&class_table); + class_table = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], new_break.class_name, new_break.class_len, &class_breaks, sizeof(HashTable)); } - if (zend_hash_find(class_table, new_break.func_name, new_break.func_len, (void **)&method_table) == FAILURE) { + if (!(method_table = zend_hash_str_find_ptr(class_table, new_break.func_name, new_break.func_len))) { zend_hash_init(&method_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0); - zend_hash_update( - class_table, - new_break.func_name, - new_break.func_len, - (void **)&method_breaks, sizeof(HashTable), (void **)&method_table); + method_table = zend_hash_str_update_mem(class_table, new_break.func_name, new_break.func_len, &method_breaks, sizeof(HashTable)); } if (zend_hash_index_exists(method_table, opline)) { - phpdbg_notice("Breakpoint already exists for %s::%s#%ld", new_break.class_name, new_break.func_name, opline); + phpdbg_error("breakpoint", "type=\"exists\" method=\"%s\" num=\"%ld\"", "Breakpoint already exists for %s::%s#%ld", new_break.class_name, new_break.func_name, opline); efree((char*)new_break.func_name); efree((char*)new_break.class_name); PHPDBG_G(bp_count)--; @@ -553,7 +511,7 @@ PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const cha PHPDBG_BREAK_MAPPING(new_break.id, method_table); - zend_hash_index_update(method_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); + zend_hash_index_update_mem(method_table, opline, &new_break, sizeof(phpdbg_breakopline_t)); } PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC) /* {{{ */ @@ -571,28 +529,24 @@ PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { case FAILURE: - phpdbg_notice("Pending breakpoint #%d at %s#%ld", new_break.id, new_break.func_name, opline); + phpdbg_notice("breakpoint", "pending=\"pending\" id=\"%d\" function=\"%s\" num=\"%ld\"", "Pending breakpoint #%d at %s#%ld", new_break.id, new_break.func_name, opline); break; case SUCCESS: - phpdbg_notice("Breakpoint #%d added at %s#%ld", new_break.id, new_break.func_name, opline); + phpdbg_notice("breakpoint", "id=\"%d\" function=\"%s\" num=\"%ld\"", "Breakpoint #%d added at %s#%ld", new_break.id, new_break.func_name, opline); break; case 2: return; } - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], new_break.func_name, new_break.func_len, (void **)&func_table) == FAILURE) { + if (!(func_table = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], new_break.func_name, new_break.func_len))) { zend_hash_init(&func_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0); - zend_hash_update( - &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], - new_break.func_name, - new_break.func_len, - (void **)&func_breaks, sizeof(HashTable), (void **)&func_table); + func_table = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], new_break.func_name, new_break.func_len, &func_breaks, sizeof(HashTable)); } if (zend_hash_index_exists(func_table, opline)) { - phpdbg_notice("Breakpoint already exists for %s#%ld", new_break.func_name, opline); + phpdbg_error("breakpoint", "type=\"exists\" function=\"%s\" num=\"%ld\"", "Breakpoint already exists for %s#%ld", new_break.func_name, opline); efree((char*)new_break.func_name); PHPDBG_G(bp_count)--; return; @@ -602,7 +556,7 @@ PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend PHPDBG_G(flags) |= PHPDBG_HAS_FUNCTION_OPLINE_BP; - zend_hash_index_update(func_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); + zend_hash_index_update_mem(func_table, opline, &new_break, sizeof(phpdbg_breakopline_t)); } PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC) /* {{{ */ @@ -620,28 +574,24 @@ PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong o switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) { case FAILURE: - phpdbg_notice("Pending breakpoint #%d at %s:%ld", new_break.id, new_break.class_name, opline); + phpdbg_notice("breakpoint", "pending=\"pending\" id=\"%d\" file=\"%s\" num=\"%ld\"", "Pending breakpoint #%d at %s:%ld", new_break.id, new_break.class_name, opline); break; case SUCCESS: - phpdbg_notice("Breakpoint #%d added at %s:%ld", new_break.id, new_break.class_name, opline); + phpdbg_notice("breakpoint", "id=\"%d\" file=\"%s\" num=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.class_name, opline); break; case 2: return; } - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], new_break.class_name, new_break.class_len, (void **)&file_table) == FAILURE) { + if (!(file_table = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], new_break.class_name, new_break.class_len))) { zend_hash_init(&file_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0); - zend_hash_update( - &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], - new_break.class_name, - new_break.class_len, - (void **)&file_breaks, sizeof(HashTable), (void **)&file_table); + file_table = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], new_break.class_name, new_break.class_len, &file_breaks, sizeof(HashTable)); } if (zend_hash_index_exists(file_table, opline)) { - phpdbg_notice("Breakpoint already exists for %s:%ld", new_break.class_name, opline); + phpdbg_error("breakpoint", "type=\"exists\" file=\"%s\" num=\"%d\"", "Breakpoint already exists for %s:%ld", new_break.class_name, opline); efree((char*)new_break.class_name); PHPDBG_G(bp_count)--; return; @@ -651,7 +601,7 @@ PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong o PHPDBG_G(flags) |= PHPDBG_HAS_FILE_OPLINE_BP; - zend_hash_index_update(file_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL); + zend_hash_index_update_mem(file_table, opline, &new_break, sizeof(phpdbg_breakopline_t)); } PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len TSRMLS_DC) /* {{{ */ @@ -660,8 +610,7 @@ PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len T zend_ulong hash = zend_hash_func(name, name_len); if (zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash)) { - phpdbg_notice( - "Breakpoint exists for %s", name); + phpdbg_error("breakpoint", "type=\"exists\" opcode=\"%s\"", "Breakpoint exists for %s", name); return; } @@ -669,12 +618,11 @@ PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len T new_break.hash = hash; new_break.name = estrndup(name, name_len); - zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash, - &new_break, sizeof(phpdbg_breakop_t), NULL); + zend_hash_index_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash, &new_break, sizeof(phpdbg_breakop_t)); PHPDBG_G(flags) |= PHPDBG_HAS_OPCODE_BP; - phpdbg_notice("Breakpoint #%d added at %s", new_break.id, name); + phpdbg_notice("breakpoint", "id=\"%d\" opcode=\"%s\"", "Breakpoint #%d added at %s", new_break.id, name); PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]); } /* }}} */ @@ -688,12 +636,12 @@ PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRML PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE); new_break.opline = (zend_ulong) opline; - zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], - (zend_ulong) opline, &new_break, sizeof(phpdbg_breakline_t), NULL); + zend_hash_index_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (zend_ulong) opline, &new_break, sizeof(phpdbg_breakline_t)); - phpdbg_notice("Breakpoint #%d added at %#lx", - new_break.id, new_break.opline); + phpdbg_notice("breakpoint", "id=\"%d\" opline=\"%#lx\"", "Breakpoint #%d added at %#lx", new_break.id, new_break.opline); PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); + } else { + phpdbg_error("breakpoint", "type=\"exists\" opline=\"%#lx\"", "Breakpoint exists for opline %#lx", (zend_ulong) opline); } } /* }}} */ @@ -721,35 +669,30 @@ static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, co new_break.code = estrndup(expr, expr_len); new_break.code_len = expr_len; - Z_STRLEN(pv) = expr_len + sizeof("return ;") - 1; - Z_STRVAL(pv) = emalloc(Z_STRLEN(pv) + 1); + Z_STR(pv) = zend_string_alloc(expr_len + sizeof("return ;") - 1, 0); memcpy(Z_STRVAL(pv), "return ", sizeof("return ") - 1); memcpy(Z_STRVAL(pv) + sizeof("return ") - 1, expr, expr_len); Z_STRVAL(pv)[Z_STRLEN(pv) - 1] = ';'; Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0'; - Z_TYPE(pv) = IS_STRING; + Z_TYPE_INFO(pv) = IS_STRING; - new_break.ops = zend_compile_string( - &pv, "Conditional Breakpoint Code" TSRMLS_CC); + new_break.ops = zend_compile_string(&pv, "Conditional Breakpoint Code" TSRMLS_CC); zval_dtor(&pv); if (new_break.ops) { - zend_hash_index_update( - &PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash, &new_break, - sizeof(phpdbg_breakcond_t), (void**)&brake); + brake = zend_hash_index_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash, &new_break, sizeof(phpdbg_breakcond_t)); - phpdbg_notice("Conditional breakpoint #%d added %s/%p", - brake->id, brake->code, brake->ops); + phpdbg_notice("breakpoint", "id=\"%d\" expression=\"%s\" ptr=\"%p\"", "Conditional breakpoint #%d added %s/%p", brake->id, brake->code, brake->ops); PHPDBG_G(flags) |= PHPDBG_HAS_COND_BP; PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_COND]); } else { - phpdbg_error( - "Failed to compile code for expression %s", expr); + phpdbg_error("compile", "expression=\"%s\"", "Failed to compile code for expression %s", expr); efree((char*)new_break.code); PHPDBG_G(bp_count)--; } + CG(compiler_options) = cops; } /* }}} */ @@ -762,7 +705,7 @@ PHPDBG_API void phpdbg_set_breakpoint_expression(const char *expr, size_t expr_l phpdbg_create_conditional_break( &new_break, NULL, expr, expr_len, expr_hash TSRMLS_CC); } else { - phpdbg_notice("Conditional break %s exists", expr); + phpdbg_error("breakpoint", "type=\"exists\" expression=\"%s\"", "Conditional break %s exists", expr); } } /* }}} */ @@ -771,35 +714,30 @@ PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param TSRMLS_DC) phpdbg_breakcond_t new_break; phpdbg_param_t *condition; zend_ulong hash = 0L; - + if (param->next) { condition = param->next; hash = zend_inline_hash_func(condition->str, condition->len); - + if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash)) { - phpdbg_create_conditional_break( - &new_break, param, - condition->str, condition->len, hash TSRMLS_CC); + phpdbg_create_conditional_break(&new_break, param, condition->str, condition->len, hash TSRMLS_CC); } else { - phpdbg_notice( - "Conditional break %s exists at the specified location", condition->str); - } + phpdbg_notice("breakpoint", "type=\"exists\" arg=\"%s\"", "Conditional break %s exists at the specified location", condition->str); + } } - + } /* }}} */ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_array TSRMLS_DC) /* {{{ */ { HashTable *breaks; phpdbg_breakbase_t *brake; - size_t name_len = strlen(op_array->filename); - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename, - name_len, (void**)&breaks) == FAILURE) { + if (!(breaks = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename))) { return NULL; } - if (zend_hash_index_find(breaks, (*EG(opline_ptr))->lineno, (void**)&brake) == SUCCESS) { + if (EG(current_execute_data) && (brake = zend_hash_index_find_ptr(breaks, EG(current_execute_data)->opline->lineno))) { return brake; } @@ -809,88 +747,73 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function *fbc TSRMLS_DC) /* {{{ */ { const char *fname; + size_t flen; zend_op_array *ops; - phpdbg_breakbase_t *brake; if (fbc->type != ZEND_USER_FUNCTION) { return NULL; } - ops = (zend_op_array*)fbc; + ops = (zend_op_array *) fbc; if (ops->scope) { /* find method breaks here */ return phpdbg_find_breakpoint_method(ops TSRMLS_CC); } - fname = ops->function_name; - - if (!fname) { + if (ops->function_name) { + fname = ops->function_name->val; + flen = ops->function_name->len; + } else { fname = "main"; + flen = 4; } - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname, strlen(fname), (void**)&brake) == SUCCESS) { - return brake; - } - - return NULL; + return zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname, flen); } /* }}} */ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array *ops TSRMLS_DC) /* {{{ */ { HashTable *class_table; - phpdbg_breakbase_t *brake; + phpdbg_breakbase_t *brake = NULL; - if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], ops->scope->name, - ops->scope->name_length, (void**)&class_table) == SUCCESS) { - char *lcname = zend_str_tolower_dup(ops->function_name, strlen(ops->function_name)); - size_t lcname_len = strlen(lcname); - - if (zend_hash_find( - class_table, - lcname, - lcname_len, (void**)&brake) == SUCCESS) { - efree(lcname); - return brake; - } + if ((class_table = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], ops->scope->name))) { + size_t lcname_len = ops->function_name->len; + char *lcname = zend_str_tolower_dup(ops->function_name->val, lcname_len); + + brake = zend_hash_str_find_ptr(class_table, lcname, lcname_len); efree(lcname); } - return NULL; + return brake; } /* }}} */ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t opline TSRMLS_DC) /* {{{ */ { phpdbg_breakline_t *brake; - if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], - (zend_ulong) opline, (void**)&brake) == SUCCESS) { - return (brake->base?(phpdbg_breakbase_t *)brake->base:(phpdbg_breakbase_t *)brake); + if ((brake = zend_hash_index_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (zend_ulong) opline)) && brake->base) { + return (phpdbg_breakbase_t *)brake->base; } - return NULL; + return (phpdbg_breakbase_t *) brake; } /* }}} */ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar opcode TSRMLS_DC) /* {{{ */ { - phpdbg_breakbase_t *brake; const char *opname = phpdbg_decode_opcode(opcode); if (memcmp(opname, PHPDBG_STRL("UNKNOWN")) == 0) { return NULL; } - if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], - zend_hash_func(opname, strlen(opname)), (void**)&brake) == SUCCESS) { - return brake; - } - return NULL; + return zend_hash_index_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], zend_hash_func(opname, strlen(opname))); } /* }}} */ static inline zend_bool phpdbg_find_breakpoint_param(phpdbg_param_t *param, zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ { - zend_function *function = (zend_function*) execute_data->function_state.function; + zend_function *function = execute_data->func; switch (param->type) { case NUMERIC_FUNCTION_PARAM: @@ -905,8 +828,8 @@ static inline zend_bool phpdbg_find_breakpoint_param(phpdbg_param_t *param, zend const char *str = NULL; size_t len = 0L; zend_op_array *ops = (zend_op_array*)function; - str = ops->function_name ? ops->function_name : "main"; - len = strlen(str); + str = ops->function_name ? ops->function_name->val : "main"; + len = ops->function_name ? ops->function_name->len : strlen(str); if (len == param->len && memcmp(param->str, str, len) == SUCCESS) { return param->type == STR_PARAM || execute_data->opline - ops->opcodes == param->num; @@ -936,10 +859,10 @@ static inline zend_bool phpdbg_find_breakpoint_param(phpdbg_param_t *param, zend zend_op_array *ops = (zend_op_array*) function; if (ops->scope) { - size_t lengths[2] = {strlen(param->method.class), ops->scope->name_length}; + size_t lengths[2] = { strlen(param->method.class), ops->scope->name->len }; if (lengths[0] == lengths[1] && memcmp(param->method.class, ops->scope->name, lengths[0]) == SUCCESS) { lengths[0] = strlen(param->method.name); - lengths[1] = strlen(ops->function_name); + lengths[1] = ops->function_name->len; if (lengths[0] == lengths[1] && memcmp(param->method.name, ops->function_name, lengths[0]) == SUCCESS) { return param->type == METHOD_PARAM || (execute_data->opline - ops->opcodes) == param->num; @@ -963,16 +886,13 @@ static inline zend_bool phpdbg_find_breakpoint_param(phpdbg_param_t *param, zend static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ { phpdbg_breakcond_t *bp; - HashPosition position; int breakpoint = FAILURE; - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void*)&bp, &position) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) { - zval *retval = NULL; - zval **orig_retval = EG(return_value_ptr_ptr); - zend_op_array *orig_ops = EG(active_op_array); - zend_op **orig_opline = EG(opline_ptr); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], bp) { + zval retval; + const zend_op *orig_opline = EG(current_execute_data)->opline; + zend_function *orig_func = EG(current_execute_data)->func; + zval *orig_retval = EG(current_execute_data)->return_value; if (((phpdbg_breakbase_t*)bp)->disabled) { continue; @@ -984,49 +904,37 @@ static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execut } } - ALLOC_INIT_ZVAL(retval); - - EG(return_value_ptr_ptr) = &retval; - EG(active_op_array) = bp->ops; EG(no_extensions) = 1; - if (!EG(active_symbol_table)) { - zend_rebuild_symbol_table(TSRMLS_C); - } + zend_rebuild_symbol_table(TSRMLS_C); zend_try { PHPDBG_G(flags) |= PHPDBG_IN_COND_BP; - zend_execute(EG(active_op_array) TSRMLS_CC); + zend_execute(bp->ops, &retval TSRMLS_CC); #if PHP_VERSION_ID >= 50700 - if (zend_is_true(retval TSRMLS_CC)) { + if (zend_is_true(&retval TSRMLS_CC)) { #else - if (zend_is_true(retval)) { + if (zend_is_true(&retval)) { #endif breakpoint = SUCCESS; } - } zend_catch { - EG(no_extensions)=1; - EG(return_value_ptr_ptr) = orig_retval; - EG(active_op_array) = orig_ops; - EG(opline_ptr) = orig_opline; - PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP; } zend_end_try(); - EG(no_extensions)=1; - EG(return_value_ptr_ptr) = orig_retval; - EG(active_op_array) = orig_ops; - EG(opline_ptr) = orig_opline; + EG(no_extensions) = 1; + EG(current_execute_data)->opline = orig_opline; + EG(current_execute_data)->func = orig_func; + EG(current_execute_data)->return_value = orig_retval; PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP; if (breakpoint == SUCCESS) { break; } - } + } ZEND_HASH_FOREACH_END(); - return (breakpoint == SUCCESS) ? ((phpdbg_breakbase_t*)bp) : NULL; + return (breakpoint == SUCCESS) ? ((phpdbg_breakbase_t *) bp) : NULL; } /* }}} */ -PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakpoint(zend_execute_data* execute_data TSRMLS_DC) /* {{{ */ +PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakpoint(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ { phpdbg_breakbase_t *base = NULL; @@ -1041,28 +949,24 @@ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakpoint(zend_execute_data* execute goto result; } - if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP) && - (base = phpdbg_find_breakpoint_file(execute_data->op_array TSRMLS_CC))) { + if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP) && (base = phpdbg_find_breakpoint_file(&execute_data->func->op_array TSRMLS_CC))) { goto result; } if (PHPDBG_G(flags) & (PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_SYM_BP)) { /* check we are at the beginning of the stack */ - if (execute_data->opline == EG(active_op_array)->opcodes) { - if ((base = phpdbg_find_breakpoint_symbol( - execute_data->function_state.function TSRMLS_CC))) { + if (execute_data->opline == execute_data->func->op_array.opcodes) { + if ((base = phpdbg_find_breakpoint_symbol(execute_data->func TSRMLS_CC))) { goto result; } } } - if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP) && - (base = phpdbg_find_breakpoint_opline(execute_data->opline TSRMLS_CC))) { + if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP) && (base = phpdbg_find_breakpoint_opline((phpdbg_opline_ptr_t) execute_data->opline TSRMLS_CC))) { goto result; } - if ((PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) && - (base = phpdbg_find_breakpoint_opcode(execute_data->opline->opcode TSRMLS_CC))) { + if ((PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) && (base = phpdbg_find_breakpoint_opcode(execute_data->opline->opcode TSRMLS_CC))) { goto result; } @@ -1079,14 +983,12 @@ result: PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */ { - HashTable **table; - HashPosition position; + HashTable *table; phpdbg_breakbase_t *brake; + zend_string *strkey; + zend_ulong numkey; - if ((brake = phpdbg_find_breakbase_ex(num, &table, &position TSRMLS_CC))) { - char *key; - uint32_t klen; - zend_ulong idx; + if ((brake = phpdbg_find_breakbase_ex(num, &table, &numkey, &strkey TSRMLS_CC))) { int type = brake->type; char *name = NULL; size_t name_len = 0L; @@ -1094,7 +996,7 @@ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */ switch (type) { case PHPDBG_BREAK_FILE: case PHPDBG_BREAK_METHOD: - if (zend_hash_num_elements((*table)) == 1) { + if (zend_hash_num_elements(table) == 1) { name = estrdup(brake->name); name_len = strlen(name); if (zend_hash_num_elements(&PHPDBG_G(bp)[type]) == 1) { @@ -1104,7 +1006,7 @@ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */ break; default: { - if (zend_hash_num_elements((*table)) == 1) { + if (zend_hash_num_elements(table) == 1) { PHPDBG_G(flags) &= ~(1<<(brake->type+1)); } } @@ -1117,34 +1019,29 @@ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */ if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]) == 1) { PHPDBG_G(flags) &= PHPDBG_HAS_OPLINE_BP; } - zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], ((phpdbg_breakopline_t*)brake)->opline); + zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], ((phpdbg_breakopline_t *) brake)->opline); } - switch (zend_hash_get_current_key_ex( - (*table), &key, &klen, &idx, 0, &position)) { - - case HASH_KEY_IS_STRING: - zend_hash_del((*table), key, klen); - break; - - default: - zend_hash_index_del((*table), idx); + if (strkey) { + zend_hash_del(table, strkey); + } else { + zend_hash_index_del(table, numkey); } switch (type) { case PHPDBG_BREAK_FILE: case PHPDBG_BREAK_METHOD: if (name) { - zend_hash_del(&PHPDBG_G(bp)[type], name, name_len); + zend_hash_str_del(&PHPDBG_G(bp)[type], name, name_len); efree(name); } break; } - phpdbg_notice("Deleted breakpoint #%ld", num); + phpdbg_notice("breakpoint", "deleted=\"success\" id=\"%ld\"", "Deleted breakpoint #%ld", num); PHPDBG_BREAK_UNMAPPING(num); } else { - phpdbg_error("Failed to find breakpoint #%ld", num); + phpdbg_error("breakpoint", "type=\"nobreakpoint\" deleted=\"fail\" id=\"%ld\"", "Failed to find breakpoint #%ld", num); } } /* }}} */ @@ -1182,7 +1079,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* switch (brake->type) { case PHPDBG_BREAK_FILE: { - phpdbg_notice("Breakpoint #%d at %s:%ld, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d at %s:%ld, hits: %lu", ((phpdbg_breakfile_t*)brake)->id, ((phpdbg_breakfile_t*)brake)->filename, ((phpdbg_breakfile_t*)brake)->line, @@ -1190,7 +1087,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_SYM: { - phpdbg_notice("Breakpoint #%d in %s() at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" function=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s() at %s:%u, hits: %lu", ((phpdbg_breaksymbol_t*)brake)->id, ((phpdbg_breaksymbol_t*)brake)->symbol, zend_get_executed_filename(TSRMLS_C), @@ -1199,7 +1096,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_OPLINE: { - phpdbg_notice("Breakpoint #%d in %#lx at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" opline=\"%#lx\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %#lx at %s:%u, hits: %lu", ((phpdbg_breakline_t*)brake)->id, ((phpdbg_breakline_t*)brake)->opline, zend_get_executed_filename(TSRMLS_C), @@ -1208,7 +1105,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_METHOD_OPLINE: { - phpdbg_notice("Breakpoint #%d in %s::%s()#%lu at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" method=\"%s::%s\" num=\"%lu\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s::%s()#%lu at %s:%u, hits: %lu", ((phpdbg_breakopline_t*)brake)->id, ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->func_name, @@ -1219,7 +1116,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_FUNCTION_OPLINE: { - phpdbg_notice("Breakpoint #%d in %s()#%lu at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" num=\"%lu\" function=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s()#%lu at %s:%u, hits: %lu", ((phpdbg_breakopline_t*)brake)->id, ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num, @@ -1229,9 +1126,8 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_FILE_OPLINE: { - phpdbg_notice("Breakpoint #%d in %s:%lu at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" num=\"%lu\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in #%lu at %s:%u, hits: %lu", ((phpdbg_breakopline_t*)brake)->id, - ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->opline_num, zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C), @@ -1239,7 +1135,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_OPCODE: { - phpdbg_notice("Breakpoint #%d in %s at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" opcode=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s at %s:%u, hits: %lu", ((phpdbg_breakop_t*)brake)->id, ((phpdbg_breakop_t*)brake)->name, zend_get_executed_filename(TSRMLS_C), @@ -1248,7 +1144,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* } break; case PHPDBG_BREAK_METHOD: { - phpdbg_notice("Breakpoint #%d in %s::%s() at %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" method=\"%s::%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Breakpoint #%d in %s::%s() at %s:%u, hits: %lu", ((phpdbg_breakmethod_t*)brake)->id, ((phpdbg_breakmethod_t*)brake)->class_name, ((phpdbg_breakmethod_t*)brake)->func_name, @@ -1260,7 +1156,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* case PHPDBG_BREAK_COND: { if (((phpdbg_breakcond_t*)brake)->paramed) { char *param; - phpdbg_notice("Conditional breakpoint #%d: at %s if %s %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" location=\"%s\" eval=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Conditional breakpoint #%d: at %s if %s at %s:%u, hits: %lu", ((phpdbg_breakcond_t*)brake)->id, phpdbg_param_tostring(&((phpdbg_breakcond_t*)brake)->param, ¶m TSRMLS_CC), ((phpdbg_breakcond_t*)brake)->code, @@ -1270,7 +1166,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* if (param) free(param); } else { - phpdbg_notice("Conditional breakpoint #%d: on %s == true %s:%u, hits: %lu", + phpdbg_notice("breakpoint", "id=\"%d\" eval=\"%s\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Conditional breakpoint #%d: on %s == true at %s:%u, hits: %lu", ((phpdbg_breakcond_t*)brake)->id, ((phpdbg_breakcond_t*)brake)->code, zend_get_executed_filename(TSRMLS_C), @@ -1282,7 +1178,7 @@ PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* default: { unknown: - phpdbg_notice("Unknown breakpoint at %s:%u", + phpdbg_notice("breakpoint", "id=\"\" file=\"%s\" line=\"%ld\" hits=\"%lu\"", "Unknown breakpoint at %s:%u", zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C)); } @@ -1318,313 +1214,236 @@ PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D) { /* {{{ */ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC) /* {{{ */ { - HashTable **table; - HashPosition position; + HashTable *table; + zend_string *strkey; + zend_ulong numkey; - return phpdbg_find_breakbase_ex(id, &table, &position TSRMLS_CC); + return phpdbg_find_breakbase_ex(id, &table, &numkey, &strkey TSRMLS_CC); } /* }}} */ -PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC) /* {{{ */ +PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable **table, zend_ulong *numkey, zend_string **strkey TSRMLS_DC) /* {{{ */ { - if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], id, (void**)table) == SUCCESS) { + if ((*table = zend_hash_index_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], id))) { phpdbg_breakbase_t *brake; - for (zend_hash_internal_pointer_reset_ex((**table), position); - zend_hash_get_current_data_ex((**table), (void**)&brake, position) == SUCCESS; - zend_hash_move_forward_ex((**table), position)) { - + ZEND_HASH_FOREACH_KEY_PTR(*table, *numkey, *strkey, brake) { if (brake->id == id) { return brake; } - } + } ZEND_HASH_FOREACH_END(); } + return NULL; } /* }}} */ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ { + phpdbg_xml("<breakpoints %r>"); + switch (type) { case PHPDBG_BREAK_SYM: if ((PHPDBG_G(flags) & PHPDBG_HAS_SYM_BP)) { - HashPosition position; phpdbg_breaksymbol_t *brake; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Function Breakpoints:"); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], (void**) &brake, &position) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position)) { - phpdbg_writeln("#%d\t\t%s%s", + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Function Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], brake) { + phpdbg_writeln("function", "id=\"%d\" name=\"%s\" disabled=\"%s\"", "#%d\t\t%s%s", brake->id, brake->symbol, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); - } + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); + } ZEND_HASH_FOREACH_END(); } break; case PHPDBG_BREAK_METHOD: if ((PHPDBG_G(flags) & PHPDBG_HAS_METHOD_BP)) { - HashPosition position[2]; HashTable *class_table; - char *class_name = NULL; - uint32_t class_len = 0; - zend_ulong class_idx = 0L; - - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Method Breakpoints:"); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0]); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], (void**) &class_table, &position[0]) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0])) { - - if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], - &class_name, &class_len, &class_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { - phpdbg_breakmethod_t *brake; - - for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]); - zend_hash_get_current_data_ex(class_table, (void**)&brake, &position[1]) == SUCCESS; - zend_hash_move_forward_ex(class_table, &position[1])) { - phpdbg_writeln("#%d\t\t%s::%s%s", - brake->id, brake->class_name, brake->func_name, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); - } - } - } + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Method Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_table) { + phpdbg_breakmethod_t *brake; + + ZEND_HASH_FOREACH_PTR(class_table, brake) { + phpdbg_writeln("method", "id=\"%d\" name=\"%s::%s\" disabled=\"%s\"", "#%d\t\t%s::%s%s", + brake->id, brake->class_name, brake->func_name, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); } break; case PHPDBG_BREAK_FILE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP)) { - HashPosition position[2]; HashTable *points; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("File Breakpoints:"); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0]); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], (void**) &points, &position[0]) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0])) { + phpdbg_out(SEPARATE "\n"); + phpdbg_out("File Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], points) { phpdbg_breakfile_t *brake; - for (zend_hash_internal_pointer_reset_ex(points, &position[1]); - zend_hash_get_current_data_ex(points, (void**)&brake, &position[1]) == SUCCESS; - zend_hash_move_forward_ex(points, &position[1])) { - phpdbg_writeln("#%d\t\t%s:%lu%s", + ZEND_HASH_FOREACH_PTR(points, brake) { + phpdbg_writeln("file", "id=\"%d\" name=\"%s\" line=\"%lu\" disabled=\"%s\"", "#%d\t\t%s:%lu%s", brake->id, brake->filename, brake->line, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); - } - } + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); } break; case PHPDBG_BREAK_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP)) { - HashPosition position; phpdbg_breakline_t *brake; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Opline Breakpoints:"); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void**) &brake, &position) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position)) { + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Opline Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], brake) { + const char *type; switch (brake->type) { case PHPDBG_BREAK_METHOD_OPLINE: + type = "method"; + goto print_opline; case PHPDBG_BREAK_FUNCTION_OPLINE: + type = "function"; + goto print_opline; case PHPDBG_BREAK_FILE_OPLINE: - phpdbg_writeln("#%d\t\t%#lx\t\t(%s breakpoint)%s", brake->id, brake->opline, - brake->type == PHPDBG_BREAK_METHOD_OPLINE?"method": - brake->type == PHPDBG_BREAK_FUNCTION_OPLINE?"function": - brake->type == PHPDBG_BREAK_FILE_OPLINE?"file": - "--- error ---", - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); - break; + type = "method"; + + print_opline: { + if (brake->type == PHPDBG_BREAK_METHOD_OPLINE) { + type = "method"; + } else if (brake->type == PHPDBG_BREAK_FUNCTION_OPLINE) { + type = "function"; + } else if (brake->type == PHPDBG_BREAK_FILE_OPLINE) { + type = "file"; + } + + phpdbg_writeln("opline", "id=\"%d\" num=\"%#lx\" type=\"%s\" disabled=\"%s\"", "#%d\t\t%#lx\t\t(%s breakpoint)%s", + brake->id, brake->opline, type, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); + } break; default: - phpdbg_writeln("#%d\t\t%#lx", brake->id, brake->opline); + phpdbg_writeln("opline", "id=\"%d\" num=\"%#lx\" disabled=\"%s\"", "#%d\t\t%#lx%s", + brake->id, brake->opline, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); break; } - } + } ZEND_HASH_FOREACH_END(); } break; case PHPDBG_BREAK_METHOD_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_METHOD_OPLINE_BP)) { - HashPosition position[3]; HashTable *class_table, *method_table; - char *class_name = NULL, *method_name = NULL; - uint32_t class_len = 0, method_len = 0; - zend_ulong class_idx = 0L, method_idx = 0L; - - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Method opline Breakpoints:"); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0]); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], (void**) &class_table, &position[0]) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0])) { - - if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], - &class_name, &class_len, &class_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { - - for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]); - zend_hash_get_current_data_ex(class_table, (void**) &method_table, &position[1]) == SUCCESS; - zend_hash_move_forward_ex(class_table, &position[1])) { - - if (zend_hash_get_current_key_ex(class_table, - &method_name, &method_len, &method_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { - - phpdbg_breakopline_t *brake; - - for (zend_hash_internal_pointer_reset_ex(method_table, &position[2]); - zend_hash_get_current_data_ex(method_table, (void**)&brake, &position[2]) == SUCCESS; - zend_hash_move_forward_ex(method_table, &position[2])) { - phpdbg_writeln("#%d\t\t%s::%s opline %ld%s", - brake->id, brake->class_name, brake->func_name, brake->opline_num, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); - } - } - } - } - } + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Method opline Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], class_table) { + ZEND_HASH_FOREACH_PTR(class_table, method_table) { + phpdbg_breakopline_t *brake; + + ZEND_HASH_FOREACH_PTR(method_table, brake) { + phpdbg_writeln("methodopline", "id=\"%d\" name=\"%s::%s\" num=\"%ld\" disabled=\"%s\"", "#%d\t\t%s::%s opline %ld%s", + brake->id, brake->class_name, brake->func_name, brake->opline_num, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); } break; case PHPDBG_BREAK_FUNCTION_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FUNCTION_OPLINE_BP)) { - HashPosition position[2]; HashTable *function_table; - char *function_name = NULL; - uint32_t function_len = 0; - zend_ulong function_idx = 0L; - - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Function opline Breakpoints:"); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0]); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], (void**) &function_table, &position[0]) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0])) { - if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], - &function_name, &function_len, &function_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { - - phpdbg_breakopline_t *brake; - - for (zend_hash_internal_pointer_reset_ex(function_table, &position[1]); - zend_hash_get_current_data_ex(function_table, (void**)&brake, &position[1]) == SUCCESS; - zend_hash_move_forward_ex(function_table, &position[1])) { - phpdbg_writeln("#%d\t\t%s opline %ld%s", - brake->id, brake->func_name, brake->opline_num, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); - } - } - - } + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Function opline Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], function_table) { + phpdbg_breakopline_t *brake; + + ZEND_HASH_FOREACH_PTR(function_table, brake) { + phpdbg_writeln("functionopline", "id=\"%d\" name=\"%s\" num=\"%ld\" disabled=\"%s\"", "#%d\t\t%s opline %ld%s", + brake->id, brake->func_name, brake->opline_num, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); } break; case PHPDBG_BREAK_FILE_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_OPLINE_BP)) { - HashPosition position[2]; HashTable *file_table; - char *file_name = NULL; - uint32_t file_len = 0; - zend_ulong file_idx = 0L; - - phpdbg_writeln(SEPARATE); - phpdbg_writeln("File opline Breakpoints:"); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0]); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], (void**) &file_table, &position[0]) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0])) { - - if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], - &file_name, &file_len, &file_idx, 0, &position[0]) == HASH_KEY_IS_STRING) { - - phpdbg_breakopline_t *brake; - for (zend_hash_internal_pointer_reset_ex(file_table, &position[1]); - zend_hash_get_current_data_ex(file_table, (void**)&brake, &position[1]) == SUCCESS; - zend_hash_move_forward_ex(file_table, &position[1])) { - phpdbg_writeln("#%d\t\t%s opline %ld%s", - brake->id, brake->class_name, brake->opline_num, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); - } - } - } + phpdbg_out(SEPARATE "\n"); + phpdbg_out("File opline Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], file_table) { + phpdbg_breakopline_t *brake; + + ZEND_HASH_FOREACH_PTR(file_table, brake) { + phpdbg_writeln("fileopline", "id=\"%d\" name=\"%s\" num=\"%ld\" disabled=\"%s\"", "#%d\t\t%s opline %ld%s", + brake->id, brake->class_name, brake->opline_num, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); } break; case PHPDBG_BREAK_COND: if ((PHPDBG_G(flags) & PHPDBG_HAS_COND_BP)) { - HashPosition position; phpdbg_breakcond_t *brake; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Conditional Breakpoints:"); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void**) &brake, &position) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) { + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Conditional Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], brake) { if (brake->paramed) { switch (brake->param.type) { case STR_PARAM: - phpdbg_writeln("#%d\t\tat %s if %s%s", - brake->id, - brake->param.str, - brake->code, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + phpdbg_writeln("evalfunction", "id=\"%d\" name=\"%s\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s if %s%s", + brake->id, brake->param.str, brake->code, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); break; case NUMERIC_FUNCTION_PARAM: - phpdbg_writeln("#%d\t\tat %s#%ld if %s%s", - brake->id, - brake->param.str, - brake->param.num, - brake->code, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + phpdbg_writeln("evalfunctionopline", "id=\"%d\" name=\"%s\" num=\"%ld\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s#%ld if %s%s", + brake->id, brake->param.str, brake->param.num, brake->code, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); break; case METHOD_PARAM: - phpdbg_writeln("#%d\t\tat %s::%s if %s%s", - brake->id, - brake->param.method.class, - brake->param.method.name, - brake->code, + phpdbg_writeln("evalmethod", "id=\"%d\" name=\"%s::%s\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s::%s if %s%s", + brake->id, brake->param.method.class, brake->param.method.name, brake->code, ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); break; case NUMERIC_METHOD_PARAM: - phpdbg_writeln("#%d\t\tat %s::%s#%ld if %s%s", - brake->id, - brake->param.method.class, - brake->param.method.name, - brake->param.num, - brake->code, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + phpdbg_writeln("evalmethodopline", "id=\"%d\" name=\"%s::%s\" num=\"%d\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s::%s#%ld if %s%s", + brake->id, brake->param.method.class, brake->param.method.name, brake->param.num, brake->code, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); break; case FILE_PARAM: - phpdbg_writeln("#%d\t\tat %s:%lu if %s%s", - brake->id, - brake->param.file.name, - brake->param.file.line, - brake->code, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + phpdbg_writeln("evalfile", "id=\"%d\" name=\"%s\" line=\"%d\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat %s:%lu if %s%s", + brake->id, brake->param.file.name, brake->param.file.line, brake->code, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); break; case ADDR_PARAM: - phpdbg_writeln("#%d\t\tat #%lx if %s%s", - brake->id, - brake->param.addr, - brake->code, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + phpdbg_writeln("evalopline", "id=\"%d\" opline=\"%#lx\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tat #%lx if %s%s", + brake->id, brake->param.addr, brake->code, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); break; default: - phpdbg_error("Invalid parameter type for conditional breakpoint"); + phpdbg_error("eval", "type=\"invalidparameter\"", "Invalid parameter type for conditional breakpoint"); return; } } else { - phpdbg_writeln("#%d\t\tif %s%s", + phpdbg_writeln("eval", "id=\"%d\" eval=\"%s\" disabled=\"%s\"", "#%d\t\tif %s%s", brake->id, brake->code, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); } - } + } ZEND_HASH_FOREACH_END(); } break; case PHPDBG_BREAK_OPCODE: if (PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) { - HashPosition position; phpdbg_breakop_t *brake; - phpdbg_writeln(SEPARATE); - phpdbg_writeln("Opcode Breakpoints:"); - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position); - zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], (void**) &brake, &position) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position)) { - phpdbg_writeln("#%d\t\t%s%s", + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Opcode Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], brake) { + phpdbg_writeln("opcode", "id=\"%d\" name=\"%s\" disabled=\"%s\"", "#%d\t\t%s%s", brake->id, brake->name, - ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : ""); - } + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); + } ZEND_HASH_FOREACH_END(); } break; } + + phpdbg_xml("</breakpoints>"); } /* }}} */ diff --git a/sapi/phpdbg/phpdbg_bp.h b/sapi/phpdbg/phpdbg_bp.h index 9c3f097d78..4090d90f91 100644 --- a/sapi/phpdbg/phpdbg_bp.h +++ b/sapi/phpdbg/phpdbg_bp.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -21,6 +21,19 @@ #ifndef PHPDBG_BP_H #define PHPDBG_BP_H +/* {{{ defines */ +#define PHPDBG_BREAK_FILE 0 +#define PHPDBG_BREAK_SYM 1 +#define PHPDBG_BREAK_OPLINE 2 +#define PHPDBG_BREAK_METHOD 3 +#define PHPDBG_BREAK_COND 4 +#define PHPDBG_BREAK_OPCODE 5 +#define PHPDBG_BREAK_FUNCTION_OPLINE 6 +#define PHPDBG_BREAK_METHOD_OPLINE 7 +#define PHPDBG_BREAK_FILE_OPLINE 8 +#define PHPDBG_BREAK_MAP 9 +#define PHPDBG_BREAK_TABLES 10 /* }}} */ + /* {{{ */ typedef struct _zend_op *phpdbg_opline_ptr_t; /* }}} */ @@ -138,7 +151,7 @@ PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D); /* }}} */ /* {{{ Breakbase API */ PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC); -PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC); /* }}} */ +PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable **table, zend_ulong *numkey, zend_string **strkey TSRMLS_DC); /* }}} */ /* {{{ Breakpoint Exportation API */ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC); /* }}} */ diff --git a/sapi/phpdbg/phpdbg_break.c b/sapi/phpdbg/phpdbg_break.c index d04f2f8bb4..386d4d9562 100644 --- a/sapi/phpdbg/phpdbg_break.c +++ b/sapi/phpdbg/phpdbg_break.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -28,15 +28,15 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_BREAK_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[10]) +#define PHPDBG_BREAK_COMMAND_D(f, h, a, m, l, s, flags) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[10], flags) /** * Commands */ const phpdbg_command_t phpdbg_break_commands[] = { - PHPDBG_BREAK_COMMAND_D(at, "specify breakpoint by location and condition", '@', break_at, NULL, "*c"), - PHPDBG_BREAK_COMMAND_D(del, "delete breakpoint by identifier number", '~', break_del, NULL, "n"), + PHPDBG_BREAK_COMMAND_D(at, "specify breakpoint by location and condition", '@', break_at, NULL, "*c", 0), + PHPDBG_BREAK_COMMAND_D(del, "delete breakpoint by identifier number", '~', break_del, NULL, "n", 0), PHPDBG_END_COMMAND }; diff --git a/sapi/phpdbg/phpdbg_break.h b/sapi/phpdbg/phpdbg_break.h index de1eff1b56..dc06da62b7 100644 --- a/sapi/phpdbg/phpdbg_break.h +++ b/sapi/phpdbg/phpdbg_break.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ diff --git a/sapi/phpdbg/phpdbg_btree.c b/sapi/phpdbg/phpdbg_btree.c index a155efbf9a..918bc0d68f 100644 --- a/sapi/phpdbg/phpdbg_btree.c +++ b/sapi/phpdbg/phpdbg_btree.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -219,3 +219,18 @@ check_branch_existence: return SUCCESS; } + +void phpdbg_btree_branch_dump(phpdbg_btree_branch *branch, zend_ulong depth) { + if (branch) { + if (depth--) { + phpdbg_btree_branch_dump(branch->branches[0], depth); + phpdbg_btree_branch_dump(branch->branches[1], depth); + } else { + fprintf(stderr, "%p: %p\n", (void *) branch->result.idx, branch->result.ptr); + } + } +} + +void phpdbg_btree_dump(phpdbg_btree *tree) { + phpdbg_btree_branch_dump(tree->branch, tree->depth); +} diff --git a/sapi/phpdbg/phpdbg_btree.h b/sapi/phpdbg/phpdbg_btree.h index c714d8dc4c..27230572f7 100644 --- a/sapi/phpdbg/phpdbg_btree.h +++ b/sapi/phpdbg/phpdbg_btree.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -62,4 +62,9 @@ int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr, #define phpdbg_btree_update(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_UPDATE) #define phpdbg_btree_overwrite(tree, idx, ptr) phpdbg_btree_insert_or_update(tree, idx, ptr, PHPDBG_BTREE_OWERWRITE) + +/* debugging functions */ +void phpdbg_btree_branch_dump(phpdbg_btree_branch *branch, zend_ulong depth); +void phpdbg_btree_dump(phpdbg_btree *tree); + #endif diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c index 0437455054..729babefca 100644 --- a/sapi/phpdbg/phpdbg_cmd.c +++ b/sapi/phpdbg/phpdbg_cmd.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -23,6 +23,7 @@ #include "phpdbg_utils.h" #include "phpdbg_set.h" #include "phpdbg_prompt.h" +#include "phpdbg_io.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -39,7 +40,7 @@ static inline const char *phpdbg_command_name(const phpdbg_command_t *command, c memcpy(&buffer[pos], command->name, command->name_len); pos += command->name_len; buffer[pos] = 0; - + return buffer; } @@ -167,59 +168,39 @@ PHPDBG_API char* phpdbg_param_tostring(const phpdbg_param_t *param, char **point { switch (param->type) { case STR_PARAM: - asprintf(pointer, - "%s", param->str); + asprintf(pointer, "%s", param->str); break; case ADDR_PARAM: - asprintf(pointer, - "%#lx", param->addr); + asprintf(pointer, "%#llx", param->addr); break; case NUMERIC_PARAM: - asprintf(pointer, - "%li", - param->num); + asprintf(pointer, "%li", param->num); break; case METHOD_PARAM: - asprintf(pointer, - "%s::%s", - param->method.class, - param->method.name); + asprintf(pointer, "%s::%s", param->method.class, param->method.name); break; case FILE_PARAM: if (param->num) { - asprintf(pointer, - "%s:%lu#%lu", - param->file.name, - param->file.line, - param->num); + asprintf(pointer, "%s:%lu#%lu", param->file.name, param->file.line, param->num); } else { - asprintf(pointer, - "%s:%lu", - param->file.name, - param->file.line); + asprintf(pointer, "%s:%lu", param->file.name, param->file.line); } break; case NUMERIC_FUNCTION_PARAM: - asprintf(pointer, - "%s#%lu", param->str, param->num); + asprintf(pointer, "%s#%lu", param->str, param->num); break; case NUMERIC_METHOD_PARAM: - asprintf(pointer, - "%s::%s#%lu", - param->method.class, - param->method.name, - param->num); + asprintf(pointer, "%s::%s#%lu", param->method.class, param->method.name, param->num); break; default: - asprintf(pointer, - "%s", "unknown"); + *pointer = strdup("unknown"); } return *pointer; @@ -231,12 +212,12 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des case STACK_PARAM: /* nope */ break; - + case STR_PARAM: dest->str = estrndup(src->str, src->len); dest->len = src->len; break; - + case OP_PARAM: dest->str = estrndup(src->str, src->len); dest->len = src->len; @@ -276,7 +257,7 @@ PHPDBG_API void phpdbg_copy_param(const phpdbg_param_t* src, phpdbg_param_t* des break; case EMPTY_PARAM: { /* do nothing */ } break; - + default: { /* not yet */ } @@ -291,7 +272,7 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) / case STACK_PARAM: /* nope */ break; - + case STR_PARAM: hash += zend_inline_hash_func(param->str, param->len); break; @@ -329,7 +310,7 @@ PHPDBG_API zend_ulong phpdbg_hash_param(const phpdbg_param_t *param TSRMLS_DC) / break; case EMPTY_PARAM: { /* do nothing */ } break; - + default: { /* not yet */ } @@ -347,7 +328,7 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa /* nope, or yep */ return 1; break; - + case NUMERIC_FUNCTION_PARAM: if (l->num != r->num) { break; @@ -402,7 +383,7 @@ PHPDBG_API zend_bool phpdbg_match_param(const phpdbg_param_t *l, const phpdbg_pa case EMPTY_PARAM: return 1; - + default: { /* not yet */ } @@ -419,43 +400,43 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg) case STR_PARAM: fprintf(stderr, "%s STR_PARAM(%s=%lu)\n", msg, param->str, param->len); break; - + case ADDR_PARAM: - fprintf(stderr, "%s ADDR_PARAM(%lu)\n", msg, param->addr); + fprintf(stderr, "%s ADDR_PARAM(%llu)\n", msg, param->addr); break; - + case NUMERIC_FILE_PARAM: fprintf(stderr, "%s NUMERIC_FILE_PARAM(%s:#%lu)\n", msg, param->file.name, param->file.line); break; - + case FILE_PARAM: fprintf(stderr, "%s FILE_PARAM(%s:%lu)\n", msg, param->file.name, param->file.line); break; - + case METHOD_PARAM: fprintf(stderr, "%s METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name); break; - + case NUMERIC_METHOD_PARAM: fprintf(stderr, "%s NUMERIC_METHOD_PARAM(%s::%s)\n", msg, param->method.class, param->method.name); break; - + case NUMERIC_FUNCTION_PARAM: fprintf(stderr, "%s NUMERIC_FUNCTION_PARAM(%s::%ld)\n", msg, param->str, param->num); break; - + case NUMERIC_PARAM: fprintf(stderr, "%s NUMERIC_PARAM(%ld)\n", msg, param->num); break; - + case COND_PARAM: fprintf(stderr, "%s COND_PARAM(%s=%lu)\n", msg, param->str, param->len); break; - + case OP_PARAM: fprintf(stderr, "%s OP_PARAM(%s=%lu)\n", msg, param->str, param->len); break; - + default: { /* not yet */ } @@ -467,13 +448,13 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg) PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) { if (stack && stack->next) { phpdbg_param_t *remove = stack->next; - + while (remove) { phpdbg_param_t *next = NULL; - + if (remove->next) next = remove->next; - + switch (remove->type) { case NUMERIC_METHOD_PARAM: case METHOD_PARAM: @@ -487,29 +468,30 @@ PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack) { case STR_PARAM: case OP_PARAM: if (remove->str) - free(remove->str); + free(remove->str); break; - + case NUMERIC_FILE_PARAM: case FILE_PARAM: if (remove->file.name) free(remove->file.name); break; - + default: { /* nothing */ } } - + free(remove); remove = NULL; - + if (next) - remove = next; + remove = next; else break; } } - + + stack->next = NULL; } /* }}} */ @@ -537,30 +519,29 @@ PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param) stack->len++; } /* }}} */ -PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC) { +PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack TSRMLS_DC) { if (command) { char buffer[128] = {0,}; const phpdbg_param_t *top = (stack != NULL) ? *stack : NULL; const char *arg = command->args; size_t least = 0L, - received = 0L, - current = 0L; + received = 0L, + current = 0L; zend_bool optional = 0; - + /* check for arg spec */ if (!(arg) || !(*arg)) { if (!top) { return SUCCESS; } - - asprintf(why, - "The command \"%s\" expected no arguments", + + phpdbg_error("command", "type=\"toomanyargs\" command=\"%s\" expected=\"0\"", "The command \"%s\" expected no arguments", phpdbg_command_name(command, buffer)); return FAILURE; } - + least = 0L; - + /* count least amount of arguments */ while (arg && *arg) { if (arg[0] == '|') { @@ -569,21 +550,19 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param least++; arg++; } - + arg = command->args; #define verify_arg(e, a, t) if (!(a)) { \ if (!optional) { \ - asprintf(why, \ - "The command \"%s\" expected %s and got nothing at parameter %lu", \ + phpdbg_error("command", "type=\"noarg\" command=\"%s\" expected=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got nothing at parameter %lu", \ phpdbg_command_name(command, buffer), \ (e), \ current); \ return FAILURE;\ } \ } else if ((a)->type != (t)) { \ - asprintf(why, \ - "The command \"%s\" expected %s and got %s at parameter %lu", \ + phpdbg_error("command", "type=\"wrongarg\" command=\"%s\" expected=\"%s\" got=\"%s\" num=\"%lu\"", "The command \"%s\" expected %s and got %s at parameter %lu", \ phpdbg_command_name(command, buffer), \ (e),\ phpdbg_get_param_type((a) TSRMLS_CC), \ @@ -593,14 +572,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param while (arg && *arg) { current++; - + switch (*arg) { case '|': { current--; optional = 1; arg++; } continue; - + case 'i': verify_arg("raw input", top, STR_PARAM); break; case 's': verify_arg("string", top, STR_PARAM); break; case 'n': verify_arg("number", top, NUMERIC_PARAM); break; @@ -610,14 +589,14 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param case 'c': verify_arg("condition", top, COND_PARAM); break; case 'o': verify_arg("opcode", top, OP_PARAM); break; case 'b': verify_arg("boolean", top, NUMERIC_PARAM); break; - + case '*': { /* do nothing */ } break; } - + if (top ) { top = top->next; } else break; - + received++; arg++; } @@ -625,28 +604,27 @@ PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param #undef verify_arg if ((received < least)) { - asprintf(why, - "The command \"%s\" expected at least %lu arguments (%s) and received %lu", + phpdbg_error("command", "type=\"toofewargs\" command=\"%s\" expected=\"%d\" argtypes=\"%s\" got=\"%d\"", "The command \"%s\" expected at least %lu arguments (%s) and received %lu", phpdbg_command_name(command, buffer), least, - command->args, + command->args, received); return FAILURE; } } - + return SUCCESS; } /* {{{ */ -PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why) { +PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top TSRMLS_DC) { const phpdbg_command_t *command = commands; phpdbg_param_t *name = *top; const phpdbg_command_t *matched[3] = {NULL, NULL, NULL}; ulong matches = 0L; - + while (command && command->name && command->handler) { - if ((name->len == 1) || (command->name_len >= name->len)) { + if (name->len == 1 || command->name_len >= name->len) { /* match single letter alias */ if (command->alias && (name->len == 1)) { if (command->alias == (*name->str)) { @@ -654,85 +632,76 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t * matches++; } } else { - /* match full, case insensitive, command name */ if (strncasecmp(command->name, name->str, name->len) == SUCCESS) { if (matches < 3) { - /* only allow abbreviating commands that can be aliased */ - if (((name->len != command->name_len) && command->alias) || - (name->len == command->name_len)) { + if ((name->len != command->name_len && command->alias) || name->len == command->name_len) { matched[matches] = command; matches++; } - - + /* exact match */ - if (name->len == command->name_len) + if (name->len == command->name_len) { break; - } else break; + } + } else { + break; + } } } } - + command++; } - + switch (matches) { - case 0: { + case 0: if (parent) { - asprintf( - why, - "The command \"%s %s\" could not be found", - parent->name, name->str); - } else asprintf( - why, - "The command \"%s\" could not be found", - name->str); - } return parent; - - case 1: { + phpdbg_error("command", "type=\"notfound\" command=\"%s\" subcommand=\"%s\"", "The command \"%s %s\" could not be found", parent->name, name->str); + } else { + phpdbg_error("command", "type=\"notfound\" command=\"%s\"", "The command \"%s\" could not be found", name->str); + } + return parent; + + case 1: (*top) = (*top)->next; command = matched[0]; - } break; - + break; + default: { char *list = NULL; uint32_t it = 0; size_t pos = 0; - + while (it < matches) { if (!list) { - list = malloc( - matched[it]->name_len + 1 + - ((it+1) < matches ? sizeof(", ")-1 : 0)); + list = emalloc(matched[it]->name_len + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0)); } else { - list = realloc(list, - (pos + matched[it]->name_len) + 1 + - ((it+1) < matches ? sizeof(", ")-1 : 0)); + list = erealloc(list, (pos + matched[it]->name_len) + 1 + (it + 1 < matches ? sizeof(", ") - 1 : 0)); } memcpy(&list[pos], matched[it]->name, matched[it]->name_len); pos += matched[it]->name_len; - if ((it+1) < matches) { - memcpy(&list[pos], ", ", sizeof(", ")-1); + if ((it + 1) < matches) { + memcpy(&list[pos], ", ", sizeof(", ") - 1); pos += (sizeof(", ") - 1); } - + list[pos] = 0; it++; } - - asprintf( - why, - "The command \"%s\" is ambigious, matching %lu commands (%s)", - name->str, matches, list); - free(list); - } return NULL; + + /* ", " separated matches */ + phpdbg_error("command", "type=\"ambiguous\" command=\"%s\" matches=\"%lu\" matched=\"%s\"", "The command \"%s\" is ambigious, matching %lu commands (%s)", name->str, matches, list); + efree(list); + + return NULL; + } } if (command->subs && (*top) && ((*top)->type == STR_PARAM)) { - return phpdbg_stack_resolve(command->subs, command, top, why); + return phpdbg_stack_resolve(command->subs, command, top TSRMLS_CC); } else { return command; } @@ -741,103 +710,148 @@ PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t * } /* }}} */ /* {{{ */ -PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC) { +PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe TSRMLS_DC) { phpdbg_param_t *top = NULL; const phpdbg_command_t *handler = NULL; - + if (stack->type != STACK_PARAM) { - asprintf( - why, "The passed argument was not a stack !!"); + phpdbg_error("command", "type=\"nostack\"", "The passed argument was not a stack !"); return FAILURE; } - + if (!stack->len) { - asprintf( - why, "The stack contains nothing !!"); + phpdbg_error("command", "type=\"emptystack\"", "The stack contains nothing !"); return FAILURE; } - - top = (phpdbg_param_t*) stack->next; - + + top = (phpdbg_param_t *) stack->next; + switch (top->type) { case EVAL_PARAM: + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); return PHPDBG_COMMAND_HANDLER(ev)(top TSRMLS_CC); case RUN_PARAM: + if (!allow_async_unsafe) { + phpdbg_error("signalsegv", "command=\"run\"", "run command is disallowed during hard interrupt"); + } + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); return PHPDBG_COMMAND_HANDLER(run)(top TSRMLS_CC); - + case SHELL_PARAM: + if (!allow_async_unsafe) { + phpdbg_error("signalsegv", "command=\"sh\"", "sh command is disallowed during hard interrupt"); + return FAILURE; + } + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); return PHPDBG_COMMAND_HANDLER(sh)(top TSRMLS_CC); - + case STR_PARAM: { - handler = phpdbg_stack_resolve( - phpdbg_prompt_commands, NULL, &top, why); - + handler = phpdbg_stack_resolve(phpdbg_prompt_commands, NULL, &top TSRMLS_CC); + if (handler) { - if (phpdbg_stack_verify(handler, &top, why TSRMLS_CC) == SUCCESS) { + if (!allow_async_unsafe && !(handler->flags & PHPDBG_ASYNC_SAFE)) { + phpdbg_error("signalsegv", "command=\"%s\"", "%s command is disallowed during hard interrupt", handler->name); + return FAILURE; + } + + if (phpdbg_stack_verify(handler, &top TSRMLS_CC) == SUCCESS) { + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); return handler->handler(top TSRMLS_CC); } } } return FAILURE; - + default: - asprintf( - why, "The first parameter makes no sense !!"); + phpdbg_error("command", "type=\"invalidcommand\"", "The first parameter makes no sense !"); return FAILURE; } - + return SUCCESS; } /* }}} */ -PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ +PHPDBG_API char *phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ { char *cmd = NULL; -#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) - char buf[PHPDBG_MAX_CMD]; -#endif char *buffer = NULL; if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && - (buffered == NULL)) { - fflush(PHPDBG_G(io)[PHPDBG_STDOUT]); + if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) && (buffered == NULL) && !phpdbg_active_sigsafe_mem(TSRMLS_C)) { + fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr); } if (buffered == NULL) { -disconnect: if (0) { +disconnect: PHPDBG_G(flags) |= (PHPDBG_IS_QUITTING|PHPDBG_IS_DISCONNECTED); zend_bailout(); return NULL; } -#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) - if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { - if (!phpdbg_write("%s", phpdbg_get_prompt(TSRMLS_C))) { +#define USE_LIB_STAR (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)) + + /* note: EOF makes readline write prompt again in local console mode - and ignored if compiled without readline */ + /* strongly assuming to be in blocking mode... */ +#if USE_LIB_STAR +readline: + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) +#endif + { + char buf[PHPDBG_MAX_CMD]; + int bytes = PHPDBG_G(input_buflen), len = 0; + if (PHPDBG_G(input_buflen)) { + memcpy(buf, PHPDBG_G(input_buffer), bytes); + } + + phpdbg_write("prompt", "", "%s", phpdbg_get_prompt(TSRMLS_C)); + PHPDBG_G(last_was_newline) = 1; + + do { + int i; + if (bytes <= 0) { + continue; + } + + for (i = len; i < len + bytes; i++) { + if (buf[i] == '\x03') { + if (i != len + bytes - 1) { + memmove(buf + i, buf + i + 1, len + bytes - i - 1); + } + len--; + i--; + continue; + } + if (buf[i] == '\n') { + PHPDBG_G(input_buflen) = len + bytes - 1 - i; + if (PHPDBG_G(input_buflen)) { + memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen)); + } + if (i != PHPDBG_MAX_CMD - 1) { + buf[i + 1] = 0; + } + cmd = buf; + goto end; + } + } + len += bytes; + /* XXX export the timeout through INI??*/ + } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1 TSRMLS_CC)) > 0); + + if (bytes <= 0) { goto disconnect; } + + cmd = buf; } - - /* note: EOF is ignored */ -readline: - if (!fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { - /* the user has gone away */ - if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { - goto disconnect; - } else goto readline; +#if USE_LIB_STAR + else { + cmd = readline(phpdbg_get_prompt(TSRMLS_C)); } - cmd = buf; -#else - /* note: EOF makes readline write prompt again in local console mode */ -readline: - if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { - char buf[PHPDBG_MAX_CMD]; - if (fgets(buf, PHPDBG_MAX_CMD, PHPDBG_G(io)[PHPDBG_STDIN])) { - cmd = buf; - } else goto disconnect; - } else cmd = readline(phpdbg_get_prompt(TSRMLS_C)); - if (!cmd) { goto readline; } @@ -846,13 +860,15 @@ readline: add_history(cmd); } #endif - } else cmd = buffered; - + } else { + cmd = buffered; + } +end: + PHPDBG_G(last_was_newline) = 1; buffer = estrdup(cmd); -#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) - if (!buffered && cmd && - !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { +#if USE_LIB_STAR + if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { free(cmd); } #endif @@ -878,7 +894,7 @@ readline: buffer = estrdup(PHPDBG_G(buffer)); } } - + return buffer; } /* }}} */ @@ -886,4 +902,3 @@ PHPDBG_API void phpdbg_destroy_input(char **input TSRMLS_DC) /*{{{ */ { efree(*input); } /* }}} */ - diff --git a/sapi/phpdbg/phpdbg_cmd.h b/sapi/phpdbg/phpdbg_cmd.h index 08b50de39e..3896551c9a 100644 --- a/sapi/phpdbg/phpdbg_cmd.h +++ b/sapi/phpdbg/phpdbg_cmd.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -86,6 +86,8 @@ struct _phpdbg_param { #define YYSTYPE phpdbg_param_t #endif +#define PHPDBG_ASYNC_SAFE 1 + typedef int (*phpdbg_command_handler_t)(const phpdbg_param_t* TSRMLS_DC); typedef struct _phpdbg_command_t phpdbg_command_t; @@ -97,8 +99,9 @@ struct _phpdbg_command_t { char alias; /* Alias */ phpdbg_command_handler_t handler; /* Command handler */ const phpdbg_command_t *subs; /* Sub Commands */ - char *args; /* Argument Spec */ - const phpdbg_command_t *parent; /* Parent Command */ + char *args; /* Argument Spec */ + const phpdbg_command_t *parent; /* Parent Command */ + zend_bool flags; /* General flags */ }; /* }}} */ @@ -106,7 +109,7 @@ struct _phpdbg_command_t { #define PHPDBG_STRL(s) s, sizeof(s)-1 #define PHPDBG_MAX_CMD 500 #define PHPDBG_FRAME(v) (PHPDBG_G(frame).v) -#define PHPDBG_EX(v) (EG(current_execute_data)->v) +#define PHPDBG_EX(v) (EG(current_execute_data)->v) typedef struct { int num; @@ -133,9 +136,9 @@ PHPDBG_API void phpdbg_destroy_input(char** TSRMLS_DC); * Stack Management */ PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param); -PHPDBG_API const phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why); -PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack, char **why TSRMLS_DC); -PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC); +PHPDBG_API const phpdbg_command_t *phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top TSRMLS_DC); +PHPDBG_API int phpdbg_stack_verify(const phpdbg_command_t *command, phpdbg_param_t **stack TSRMLS_DC); +PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, zend_bool allow_async_unsafe TSRMLS_DC); PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack); /* @@ -155,27 +158,27 @@ PHPDBG_API void phpdbg_param_debug(const phpdbg_param_t *param, const char *msg) */ #define PHPDBG_COMMAND_HANDLER(name) phpdbg_do_##name -#define PHPDBG_COMMAND_D_EXP(name, tip, alias, handler, children, args, parent) \ - {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, parent} +#define PHPDBG_COMMAND_D_EXP(name, tip, alias, handler, children, args, parent, flags) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, parent, flags} -#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, args) \ - {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, NULL} +#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, args, flags) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args, NULL, flags} -#define PHPDBG_COMMAND_D(name, tip, alias, children, args) \ - {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, args, NULL} +#define PHPDBG_COMMAND_D(name, tip, alias, children, args, flags) \ + {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, args, NULL, flags} #define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param TSRMLS_DC) #define PHPDBG_COMMAND_ARGS param TSRMLS_CC -#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0', NULL} +#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, NULL, NULL, 0} /* * Default Switch Case */ #define phpdbg_default_switch_case() \ default: \ - phpdbg_error("Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \ + phpdbg_error("command", "type=\"wrongarg\" got=\"%s\"", "Unsupported parameter type (%s) for command", phpdbg_get_param_type(param TSRMLS_CC)); \ break #endif /* PHPDBG_CMD_H */ diff --git a/sapi/phpdbg/phpdbg_eol.c b/sapi/phpdbg/phpdbg_eol.c new file mode 100644 index 0000000000..fc20d567bc --- /dev/null +++ b/sapi/phpdbg/phpdbg_eol.c @@ -0,0 +1,172 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "phpdbg.h" +#include "phpdbg_eol.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +#define EOL_LIST_LEN 4 +struct phpdbg_eol_rep phpdbg_eol_list[EOL_LIST_LEN] = { + {"CRLF", "\r\n", PHPDBG_EOL_CRLF}, +/* {"LFCR", "\n\r", PHPDBG_EOL_LFCR},*/ + {"LF", "\n", PHPDBG_EOL_LF}, + {"CR", "\r", PHPDBG_EOL_CR}, +}; + +int phpdbg_eol_global_update(char *name TSRMLS_DC) +{ + + if (0 == memcmp(name, "CRLF", 4) || 0 == memcmp(name, "crlf", 4) || 0 == memcmp(name, "DOS", 3) || 0 == memcmp(name, "dos", 3)) { + PHPDBG_G(eol) = PHPDBG_EOL_CRLF; + } else if (0 == memcmp(name, "LF", 2) || 0 == memcmp(name, "lf", 2) || 0 == memcmp(name, "UNIX", 4) || 0 == memcmp(name, "unix", 4)) { + PHPDBG_G(eol) = PHPDBG_EOL_LF; + } else if (0 == memcmp(name, "CR", 2) || 0 == memcmp(name, "cr", 2) || 0 == memcmp(name, "MAC", 3) || 0 == memcmp(name, "mac", 3)) { + PHPDBG_G(eol) = PHPDBG_EOL_CR; + } else { + return FAILURE; + } + + return SUCCESS; +} + +char *phpdbg_eol_name(int id) +{ + size_t i = 0; + + while (i < EOL_LIST_LEN) { + + if (id == phpdbg_eol_list[i].id) { + return phpdbg_eol_list[i].name; + } + + i++; + } + + return NULL; +} + +char *phpdbg_eol_rep(int id) +{ + size_t i = 0; + + while (i < EOL_LIST_LEN) { + + if (id == phpdbg_eol_list[i].id) { + return phpdbg_eol_list[i].rep; + } + + i++; + } + + return NULL; +} + + +/* Inspired by https://ccrma.stanford.edu/~craig/utility/flip/flip.cpp */ +void phpdbg_eol_convert(char **str, int *len TSRMLS_DC) +{ + char *in = *str, *out ; + int in_len = *len, out_len, cursor, i; + char last, cur; + + if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) != PHPDBG_IS_REMOTE) { + return; + } + + out_len = *len; + if (PHPDBG_EOL_CRLF == PHPDBG_G(eol)) { /* XXX add LFCR case if it's gonna be needed */ + /* depending on the source EOL the out str will have all CR/LF duplicated */ + for (i = 0; i < in_len; i++) { + if (0x0a == in[i] || 0x0d == in[i]) { + out_len++; + } + } + out = (char *)emalloc(out_len); + + last = cur = in[0]; + i = cursor = 0; + for (; i < in_len;) { + if (0x0a == cur && last != 0x0d) { + out[cursor] = 0x0d; + cursor++; + out[cursor] = cur; + } else if(0x0d == cur) { + if (i + 1 < in_len && 0x0a != in[i+1]) { + out[cursor] = cur; + cursor++; + out[cursor] = 0x0a; + last = 0x0a; + } else { + out[cursor] = 0x0d; + last = 0x0d; + } + } else { + out[cursor] = cur; + last = cur; + } + + i++; + cursor++; + cur = in[i]; + } + + } else if (PHPDBG_EOL_LF == PHPDBG_G(eol) || PHPDBG_EOL_CR == PHPDBG_G(eol)) { + char want, kick; + + if (PHPDBG_EOL_LF == PHPDBG_G(eol)) { + want = 0x0a; + kick = 0x0d; + } else { + want = 0x0d; + kick = 0x0a; + } + + /* We gonna have a smaller or equally long string, estimation is almost neglecting */ + out = (char *)emalloc(out_len); + + last = cur = in[0]; + i = cursor = 0; + for (; cursor < in_len;) { + if (kick == cur) { + out[cursor] = want; + } else if (want == cur) { + if (kick != last) { + out[cursor] = want; + } + } else { + out[cursor] = cur; + } + + last = cur; + cursor++; + cur = in[cursor]; + } + } else { + return; + } + + efree(*str); + *str = erealloc(out, cursor); + *len = cursor; + in = NULL; +} diff --git a/sapi/phpdbg/phpdbg_eol.h b/sapi/phpdbg/phpdbg_eol.h new file mode 100644 index 0000000000..68b54cbe34 --- /dev/null +++ b/sapi/phpdbg/phpdbg_eol.h @@ -0,0 +1,46 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_EOL_H +#define PHPDBG_EOL_H + +#include "phpdbg.h" + +struct phpdbg_eol_rep { + char *name; + char *rep; + int id; +}; + +enum { + PHPDBG_EOL_CRLF, /* DOS */ + /*PHPDBG_EOL_LFCR,*/ /* for Risc OS? */ + PHPDBG_EOL_LF, /* UNIX */ + PHPDBG_EOL_CR /* MAC */ +}; + +int phpdbg_eol_global_update(char *name TSRMLS_DC); + +char *phpdbg_eol_name(int id); + +char *phpdbg_eol_rep(int id); + +void phpdbg_eol_convert(char **str, int *len TSRMLS_DC); + +#endif /* PHPDBG_EOL_H */ + diff --git a/sapi/phpdbg/phpdbg_frame.c b/sapi/phpdbg/phpdbg_frame.c index 5678534005..4429a7fb73 100644 --- a/sapi/phpdbg/phpdbg_frame.c +++ b/sapi/phpdbg/phpdbg_frame.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -37,13 +37,7 @@ void phpdbg_restore_frame(TSRMLS_D) /* {{{ */ /* move things back */ EG(current_execute_data) = PHPDBG_FRAME(execute_data); - EG(opline_ptr) = &PHPDBG_EX(opline); - EG(active_op_array) = PHPDBG_EX(op_array); - EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value); - EG(active_symbol_table) = PHPDBG_EX(symbol_table); - EG(This) = PHPDBG_EX(current_this); - EG(scope) = PHPDBG_EX(current_scope); - EG(called_scope) = PHPDBG_EX(current_called_scope); + EG(scope) = PHPDBG_EX(scope); } /* }}} */ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */ @@ -52,22 +46,27 @@ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */ int i = 0; if (PHPDBG_FRAME(num) == frame) { - phpdbg_notice("Already in frame #%d", frame); + phpdbg_notice("frame", "id=\"%d\"", "Already in frame #%d", frame); return; } - while (execute_data) { - if (i++ == frame) { - break; - } + phpdbg_try_access { + while (execute_data) { + if (i++ == frame) { + break; + } - do { - execute_data = execute_data->prev_execute_data; - } while (execute_data && execute_data->opline == NULL); - } + do { + execute_data = execute_data->prev_execute_data; + } while (execute_data && execute_data->opline == NULL); + } + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Couldn't switch frames, invalid data source"); + return; + } phpdbg_end_try_access(); if (execute_data == NULL) { - phpdbg_error("No frame #%d", frame); + phpdbg_error("frame", "type=\"maxnum\" id=\"%d\"", "No frame #%d", frame); return; } @@ -80,127 +79,143 @@ void phpdbg_switch_frame(int frame TSRMLS_DC) /* {{{ */ PHPDBG_FRAME(execute_data) = EG(current_execute_data); EG(current_execute_data) = execute_data; - EG(opline_ptr) = &PHPDBG_EX(opline); - EG(active_op_array) = PHPDBG_EX(op_array); - PHPDBG_FRAME(execute_data)->original_return_value = EG(return_value_ptr_ptr); - EG(return_value_ptr_ptr) = PHPDBG_EX(original_return_value); - EG(active_symbol_table) = PHPDBG_EX(symbol_table); - EG(This) = PHPDBG_EX(current_this); - EG(scope) = PHPDBG_EX(current_scope); - EG(called_scope) = PHPDBG_EX(current_called_scope); + EG(scope) = PHPDBG_EX(scope); } - phpdbg_notice("Switched to frame #%d", frame); - phpdbg_list_file( - zend_get_executed_filename(TSRMLS_C), - 3, - zend_get_executed_lineno(TSRMLS_C)-1, - zend_get_executed_lineno(TSRMLS_C) - TSRMLS_CC - ); + phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame); + + { + const char *file_chr = zend_get_executed_filename(TSRMLS_C); + zend_string *file = zend_string_init(file_chr, strlen(file_chr), 0); + phpdbg_list_file(file, 3, zend_get_executed_lineno(TSRMLS_C) - 1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); + efree(file); + } } /* }}} */ -static void phpdbg_dump_prototype(zval **tmp TSRMLS_DC) /* {{{ */ +static void phpdbg_dump_prototype(zval *tmp TSRMLS_DC) /* {{{ */ { - zval **funcname, **class, **type, **args, **argstmp; - char is_class; + zval *funcname, *class, class_zv, *type, *args, *argstmp; - zend_hash_find(Z_ARRVAL_PP(tmp), "function", sizeof("function"), - (void **)&funcname); + funcname = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("function")); - if ((is_class = zend_hash_find(Z_ARRVAL_PP(tmp), - "object", sizeof("object"), (void **)&class)) == FAILURE) { - is_class = zend_hash_find(Z_ARRVAL_PP(tmp), "class", sizeof("class"), - (void **)&class); + if ((class = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("object")))) { + ZVAL_NEW_STR(&class_zv, Z_OBJCE_P(class)->name); + class = &class_zv; } else { - zend_get_object_classname(*class, (const char **)&Z_STRVAL_PP(class), - (uint32_t *)&Z_STRLEN_PP(class) TSRMLS_CC); + class = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("class")); + } + + if (class) { + type = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("type")); } - if (is_class == SUCCESS) { - zend_hash_find(Z_ARRVAL_PP(tmp), "type", sizeof("type"), (void **)&type); + args = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("args")); + + phpdbg_xml(" symbol=\"%s%s%s\"", class ? Z_STRVAL_P(class) : "", class ? Z_STRVAL_P(type) : "", Z_STRVAL_P(funcname)); + + if (args) { + phpdbg_xml(">"); + } else { + phpdbg_xml(" />"); } - phpdbg_write("%s%s%s(", - is_class == FAILURE?"":Z_STRVAL_PP(class), - is_class == FAILURE?"":Z_STRVAL_PP(type), - Z_STRVAL_PP(funcname) - ); - - if (zend_hash_find(Z_ARRVAL_PP(tmp), "args", sizeof("args"), - (void **)&args) == SUCCESS) { - HashPosition iterator; - const zend_function *func = phpdbg_get_function( - Z_STRVAL_PP(funcname), is_class == FAILURE ? NULL : Z_STRVAL_PP(class) TSRMLS_CC); - const zend_arg_info *arginfo = func ? func->common.arg_info : NULL; - int j = 0, m = func ? func->common.num_args : 0; + phpdbg_out("%s%s%s(", class ? Z_STRVAL_P(class) : "", class ? Z_STRVAL_P(type) : "", Z_STRVAL_P(funcname)); + + if (args) { + const zend_function *func = NULL; + const zend_arg_info *arginfo = NULL; zend_bool is_variadic = 0; + int j = 0, m; + + phpdbg_try_access { + /* assuming no autoloader call is necessary, class should have been loaded if it's in backtrace ... */ + if ((func = phpdbg_get_function(Z_STRVAL_P(funcname), class ? Z_STRVAL_P(class) : NULL TSRMLS_CC))) { + arginfo = func->common.arg_info; + } + } phpdbg_end_try_access(); + + m = func ? func->common.num_args : 0; - zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(args), &iterator); - while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(args), - (void **) &argstmp, &iterator) == SUCCESS) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), argstmp) { if (j) { - phpdbg_write(", "); + phpdbg_out(", "); } + phpdbg_xml("<arg %r"); if (m && j < m) { -#if PHP_VERSION_ID >= 50600 - is_variadic = arginfo[j].is_variadic; -#endif - phpdbg_write("%s=%s", - arginfo[j].name, is_variadic ? "[": ""); + if (!is_variadic) { + is_variadic = arginfo ? arginfo[j].is_variadic : 0; + } + phpdbg_xml(" variadic=\"%s\" name=\"%s\">", is_variadic ? "variadic" : "", arginfo ? arginfo[j].name : ""); + phpdbg_out("%s=%s", arginfo ? arginfo[j].name : "?", is_variadic ? "[": ""); + + } else { + phpdbg_xml(">"); } ++j; - zend_print_flat_zval_r(*argstmp TSRMLS_CC); - zend_hash_move_forward_ex(Z_ARRVAL_PP(args), &iterator); - } + zend_print_flat_zval_r(argstmp TSRMLS_CC); + + phpdbg_xml("</arg>"); + } ZEND_HASH_FOREACH_END(); + if (is_variadic) { - phpdbg_write("]"); + phpdbg_out("]"); } + phpdbg_xml("</frame>"); } - phpdbg_write(")"); + phpdbg_out(")"); } void phpdbg_dump_backtrace(size_t num TSRMLS_DC) /* {{{ */ { - zval zbacktrace; - zval **tmp; - zval **file, **line; HashPosition position; + zval zbacktrace; + zval *tmp; + zval *file, *line; int i = 0, limit = num; - int user_defined; if (limit < 0) { - phpdbg_error("Invalid backtrace size %d", limit); + phpdbg_error("backtrace", "type=\"minnum\"", "Invalid backtrace size %d", limit); + return; } - zend_fetch_debug_backtrace( - &zbacktrace, 0, 0, limit TSRMLS_CC); + phpdbg_try_access { + zend_fetch_debug_backtrace(&zbacktrace, 0, 0, limit TSRMLS_CC); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Couldn't fetch backtrace, invalid data source"); + return; + } phpdbg_end_try_access(); + + phpdbg_xml("<backtrace %r>"); zend_hash_internal_pointer_reset_ex(Z_ARRVAL(zbacktrace), &position); - zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), (void**)&tmp, &position); + tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position); while (1) { - user_defined = zend_hash_find(Z_ARRVAL_PP(tmp), "file", sizeof("file"), (void **)&file); - zend_hash_find(Z_ARRVAL_PP(tmp), "line", sizeof("line"), (void **)&line); + file = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("file")); + line = zend_hash_str_find(Z_ARRVAL_P(tmp), ZEND_STRL("line")); zend_hash_move_forward_ex(Z_ARRVAL(zbacktrace), &position); - if (zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), - (void**)&tmp, &position) == FAILURE) { - phpdbg_write("frame #%d: {main} at %s:%ld", i, Z_STRVAL_PP(file), Z_LVAL_PP(line)); + if (!(tmp = zend_hash_get_current_data_ex(Z_ARRVAL(zbacktrace), &position))) { + phpdbg_write("frame", "id=\"%d\" symbol=\"{main}\" file=\"%s\" line=\"%d\"", "frame #%d: {main} at %s:%ld", i, Z_STRVAL_P(file), Z_LVAL_P(line)); break; } - if (user_defined == SUCCESS) { - phpdbg_write("frame #%d: ", i++); + if (file) { /* userland */ + phpdbg_out("frame #%d: ", i); + phpdbg_xml("<frame %r id=\"%d\" file=\"%s\" line=\"%d\"", i, Z_STRVAL_P(file), Z_LVAL_P(line)); phpdbg_dump_prototype(tmp TSRMLS_CC); - phpdbg_writeln(" at %s:%ld", Z_STRVAL_PP(file), Z_LVAL_PP(line)); + phpdbg_out(" at %s:%ld\n", Z_STRVAL_P(file), Z_LVAL_P(line)); + i++; } else { - phpdbg_write(" => "); + phpdbg_out(" => "); + phpdbg_xml("<frame %r id=\"%d\" internal=\"internal\"", i); phpdbg_dump_prototype(tmp TSRMLS_CC); - phpdbg_writeln(" (internal function)"); + phpdbg_out(" (internal function)\n"); } } - phpdbg_writeln(EMPTY); + phpdbg_out("\n"); + phpdbg_xml("</backtrace>"); + zval_dtor(&zbacktrace); } /* }}} */ diff --git a/sapi/phpdbg/phpdbg_frame.h b/sapi/phpdbg/phpdbg_frame.h index 757f98fd71..7c4574ed28 100644 --- a/sapi/phpdbg/phpdbg_frame.h +++ b/sapi/phpdbg/phpdbg_frame.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ diff --git a/sapi/phpdbg/phpdbg_help.c b/sapi/phpdbg/phpdbg_help.c index 3421f7ebeb..652e170694 100644 --- a/sapi/phpdbg/phpdbg_help.c +++ b/sapi/phpdbg/phpdbg_help.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -22,6 +22,7 @@ #include "phpdbg.h" #include "phpdbg_help.h" #include "phpdbg_prompt.h" +#include "phpdbg_eol.h" #include "zend.h" ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -61,6 +62,11 @@ void pretty_print(char *text TSRMLS_DC) unsigned int last_blank_count = 0; /* printable char offset of last blank char */ unsigned int line_count = 0; /* number printable chars on current line */ + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + phpdbg_xml("<help %r msg=\"%s\" />", text); + return; + } + /* First pass calculates a safe size for the pretty print version */ for (p = text; *p; p++) { if (UNEXPECTED(p[0] == '*') && p[1] == '*') { @@ -128,10 +134,10 @@ void pretty_print(char *text TSRMLS_DC) *q++ = '\0'; if ((q-new)>size) { - phpdbg_error("Output overrun of %lu bytes", ((q-new) - size)); + phpdbg_error("help", "overrun=\"%lu\"", "Output overrun of %lu bytes", ((q - new) - size)); } - phpdbg_write("%s\n", new); + phpdbg_out("%s\n", new); efree(new); } /* }}} */ @@ -201,7 +207,7 @@ static int get_command( return num_matches; -} /* }}} */ +} /* }}} */ PHPDBG_COMMAND(help) /* {{{ */ { @@ -231,7 +237,7 @@ PHPDBG_COMMAND(help) /* {{{ */ pretty_print(get_help("duplicate!" TSRMLS_CC) TSRMLS_CC); return SUCCESS; } else { - phpdbg_error("Internal help error, non-unique alias \"%c\"", param->str[0]); + phpdbg_error("help", "type=\"ambiguousalias\" alias=\"%s\"", "Internal help error, non-unique alias \"%c\"", param->str[0]); return FAILURE; } @@ -259,34 +265,41 @@ PHPDBG_HELP(aliases) /* {{{ */ int len; /* Print out aliases for all commands except help as this one comes last */ - phpdbg_writeln("Below are the aliased, short versions of all supported commands"); + phpdbg_writeln("help", "", "Below are the aliased, short versions of all supported commands"); + phpdbg_xml("<helpcommands %r>"); for(c = phpdbg_prompt_commands; c->name; c++) { if (c->alias && c->alias != 'h') { - phpdbg_writeln(" %c %-20s %s", c->alias, c->name, c->tip); + phpdbg_writeln("command", "alias=\"%c\" name=\"%s\" tip=\"%s\"", " %c %-20s %s", c->alias, c->name, c->tip); if (c->subs) { len = 20 - 1 - c->name_len; for(c_sub = c->subs; c_sub->alias; c_sub++) { if (c_sub->alias) { - phpdbg_writeln(" %c %c %s %-*s %s", - c->alias, c_sub->alias, (char *)c->name, len, c_sub->name, c_sub->tip); + phpdbg_writeln("subcommand", "parent_alias=\"%c\" alias=\"%c\" parent=\"%s\" name=\"%-*s\" tip=\"%s\"", " %c %c %s %-*s %s", + c->alias, c_sub->alias, c->name, len, c_sub->name, c_sub->tip); } } } } } + phpdbg_xml("</helpcommands>"); + /* Print out aliases for help as this one comes last, with the added text on how aliases are used */ get_command("h", 1, &c, phpdbg_prompt_commands TSRMLS_CC); - phpdbg_writeln(" %c %-20s %s\n", c->alias, c->name, c->tip); + phpdbg_writeln("aliasinfo", "alias=\"%c\" name=\"%s\" tip=\"%s\"", " %c %-20s %s\n", c->alias, c->name, c->tip); + + phpdbg_xml("<helpaliases>"); len = 20 - 1 - c->name_len; for(c_sub = c->subs; c_sub->alias; c_sub++) { if (c_sub->alias) { - phpdbg_writeln(" %c %c %s %-*s %s", + phpdbg_writeln("alias", "parent_alias=\"%c\" alias=\"%c\" parent=\"%s\" name=\"%-*s\" tip=\"%s\"", " %c %c %s %-*s %s", c->alias, c_sub->alias, c->name, len, c_sub->name, c_sub->tip); } } + phpdbg_xml("</helpaliases>"); + pretty_print(get_help("aliases!" TSRMLS_CC) TSRMLS_CC); return SUCCESS; } /* }}} */ @@ -307,7 +320,7 @@ PHPDBG_HELP(aliases) /* {{{ */ * Also note the convention that help text not directly referenceable as a help param * has a key ending in ! */ -#define CR "\n" +#define CR "\n" phpdbg_help_text_t phpdbg_help_text[] = { /******************************** General Help Topics ********************************/ @@ -375,6 +388,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { " **-S** **-S**cli Override SAPI name, careful!" CR " **-l** **-l**4000 Setup remote console ports" CR " **-a** **-a**192.168.0.3 Setup remote console bind address" CR +" **-x** Enable xml output (instead of normal text output)" CR " **-V** Print version number" CR " **--** **--** arg1 arg2 Use to delimit phpdbg arguments and php $argv; append any $argv " "argument after it" CR CR @@ -386,9 +400,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { "bind address using the **-a** option. If **-a** is specied without an argument, then phpdbg " "will bind to all available interfaces. You should be aware of the security implications of " "doing this, so measures should be taken to secure this service if bound to a publicly accessible " -"interface/port." CR CR - -"Specify both stdin and stdout with -lstdin/stdout; by default stdout is stdin * 2." +"interface/port." }, {"phpdbginit", CR @@ -642,14 +654,16 @@ phpdbg_help_text_t phpdbg_help_text[] = { "Specific info commands are show below:" CR CR " **Target** **Alias** **Purpose**" CR -" **break** **b** show current breakpoints" CR -" **files** **F** show included files" CR -" **classes** **c** show loaded classes" CR -" **funcs** **f** show loaded classes" CR -" **error** **e** show last error" CR -" **vars** **v** show active variables" CR -" **literal** **l** show active literal constants" CR -" **memory** **m** show memory manager stats" +" **break** **b** show current breakpoints" CR +" **files** **F** show included files" CR +" **classes** **c** show loaded classes" CR +" **funcs** **f** show loaded functions" CR +" **error** **e** show last error" CR +" **constants** **d** show user-defined constants" CR +" **vars** **v** show active variables" CR +" **globals** **g** show superglobal variables" CR +" **literal** **l** show active literal constants" CR +" **memory** **m** show memory manager stats" }, // ******** same issue about breakpoints in called frames diff --git a/sapi/phpdbg/phpdbg_help.h b/sapi/phpdbg/phpdbg_help.h index c7af5c894b..4a433fda6c 100644 --- a/sapi/phpdbg/phpdbg_help.h +++ b/sapi/phpdbg/phpdbg_help.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -35,9 +35,9 @@ PHPDBG_HELP(aliases); extern const phpdbg_command_t phpdbg_help_commands[]; #define phpdbg_help_header() \ - phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); + phpdbg_notice("version", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION); #define phpdbg_help_footer() \ - phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES); + phpdbg_notice("issues", "url=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES); typedef struct _phpdbg_help_text_t { char *key; diff --git a/sapi/phpdbg/phpdbg_info.c b/sapi/phpdbg/phpdbg_info.c index 5911185300..01633e4feb 100644 --- a/sapi/phpdbg/phpdbg_info.c +++ b/sapi/phpdbg/phpdbg_info.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -27,18 +27,20 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_INFO_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[14]) +#define PHPDBG_INFO_COMMAND_D(f, h, a, m, l, s, flags) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[14], flags) const phpdbg_command_t phpdbg_info_commands[] = { - PHPDBG_INFO_COMMAND_D(break, "show breakpoints", 'b', info_break, NULL, 0), - PHPDBG_INFO_COMMAND_D(files, "show included files", 'F', info_files, NULL, 0), - PHPDBG_INFO_COMMAND_D(classes, "show loaded classes", 'c', info_classes, NULL, 0), - PHPDBG_INFO_COMMAND_D(funcs, "show loaded classes", 'f', info_funcs, NULL, 0), - PHPDBG_INFO_COMMAND_D(error, "show last error", 'e', info_error, NULL, 0), - PHPDBG_INFO_COMMAND_D(vars, "show active variables", 'v', info_vars, NULL, 0), - PHPDBG_INFO_COMMAND_D(literal, "show active literal constants", 'l', info_literal, NULL, 0), - PHPDBG_INFO_COMMAND_D(memory, "show memory manager stats", 'm', info_memory, NULL, 0), + PHPDBG_INFO_COMMAND_D(break, "show breakpoints", 'b', info_break, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(files, "show included files", 'F', info_files, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(classes, "show loaded classes", 'c', info_classes, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(funcs, "show loaded classes", 'f', info_funcs, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(error, "show last error", 'e', info_error, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(constants, "show user defined constants", 'd', info_constants, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(vars, "show active variables", 'v', info_vars, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(globals, "show superglobals", 'g', info_globals, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(literal, "show active literal constants", 'l', info_literal, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_INFO_COMMAND_D(memory, "show memory manager stats", 'm', info_memory, NULL, 0, PHPDBG_ASYNC_SAFE), PHPDBG_END_COMMAND }; @@ -59,18 +61,22 @@ PHPDBG_INFO(break) /* {{{ */ PHPDBG_INFO(files) /* {{{ */ { - HashPosition pos; - char *fname; + zend_string *fname; - phpdbg_notice("Included files: %d", - zend_hash_num_elements(&EG(included_files))); + phpdbg_try_access { + phpdbg_notice("includedfilecount", "num=\"%d\"", "Included files: %d", zend_hash_num_elements(&EG(included_files))); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Could not fetch included file count, invalid data source"); + return SUCCESS; + } phpdbg_end_try_access(); - zend_hash_internal_pointer_reset_ex(&EG(included_files), &pos); - while (zend_hash_get_current_key_ex(&EG(included_files), &fname, - NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) { - phpdbg_writeln("File: %s", fname); - zend_hash_move_forward_ex(&EG(included_files), &pos); - } + phpdbg_try_access { + ZEND_HASH_FOREACH_STR_KEY(&EG(included_files), fname) { + phpdbg_writeln("includedfile", "name=\"%s\"", "File: %s", fname); + } ZEND_HASH_FOREACH_END(); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Could not fetch file name, invalid data source, aborting included file listing"); + } phpdbg_end_try_access(); return SUCCESS; } /* }}} */ @@ -78,125 +84,189 @@ PHPDBG_INFO(files) /* {{{ */ PHPDBG_INFO(error) /* {{{ */ { if (PG(last_error_message)) { - phpdbg_writeln("Last error: %s at %s line %d", - PG(last_error_message), PG(last_error_file), PG(last_error_lineno)); + phpdbg_try_access { + phpdbg_writeln("lasterror", "error=\"%s\" file=\"%s\" line=\"%d\"", "Last error: %s at %s line %d", PG(last_error_message), PG(last_error_file), PG(last_error_lineno)); + } phpdbg_catch_access { + phpdbg_notice("lasterror", "error=\"\"", "No error found!"); + } phpdbg_end_try_access(); } else { - phpdbg_notice("No error found!"); + phpdbg_notice("lasterror", "error=\"\"", "No error found!"); } return SUCCESS; } /* }}} */ -PHPDBG_INFO(vars) /* {{{ */ +PHPDBG_INFO(constants) /* {{{ */ { - HashTable vars; - HashPosition pos; - char *var; - zval **data; + HashTable consts; + zend_constant *data; - if (!EG(active_op_array)) { - phpdbg_error("No active op array!"); - return SUCCESS; + zend_hash_init(&consts, 8, NULL, NULL, 0); + + if (EG(zend_constants)) { + phpdbg_try_access { + ZEND_HASH_FOREACH_PTR(EG(zend_constants), data) { + if (data->module_number == PHP_USER_CONSTANT) { + zend_hash_update_ptr(&consts, data->name, data); + } + } ZEND_HASH_FOREACH_END(); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Cannot fetch all the constants, invalid data source"); + } phpdbg_end_try_access(); } - if (!EG(active_symbol_table)) { - zend_rebuild_symbol_table(TSRMLS_C); + phpdbg_notice("constantinfo", "num=\"%d\"", "User-defined constants (%d)", zend_hash_num_elements(&consts)); + + if (zend_hash_num_elements(&consts)) { + phpdbg_out("Address Refs Type Constant\n"); + ZEND_HASH_FOREACH_PTR(&consts, data) { + +#define VARIABLEINFO(attrs, msg, ...) phpdbg_writeln("constant", "address=\"%p\" refcount=\"%d\" type=\"%s\" name=\"%.*s\" " attrs, "%-18p %-7d %-9s %.*s" msg, &data->value, Z_REFCOUNT(data->value), zend_zval_type_name(&data->value), data->name->len, data->name->val, ##__VA_ARGS__) + + switch (Z_TYPE(data->value)) { + case IS_STRING: + phpdbg_try_access { + VARIABLEINFO("length=\"%d\" value=\"%.*s\"", "\nstring (%d) \"%.*s%s\"", Z_STRLEN(data->value), Z_STRLEN(data->value) < 255 ? Z_STRLEN(data->value) : 255, Z_STRVAL(data->value), Z_STRLEN(data->value) > 255 ? "..." : ""); + } phpdbg_catch_access { + VARIABLEINFO("", ""); + } phpdbg_end_try_access(); + break; + case IS_TRUE: + VARIABLEINFO("value=\"true\"", "\nbool (true)"); + break; + case IS_FALSE: + VARIABLEINFO("value=\"false\"", "\nbool (false)"); + break; + case IS_LONG: + VARIABLEINFO("value=\"%ld\"", "\nint (%ld)", Z_LVAL(data->value)); + break; + case IS_DOUBLE: + VARIABLEINFO("value=\"%lf\"", "\ndouble (%lf)", Z_DVAL(data->value)); + break; + default: + VARIABLEINFO("", ""); + +#undef VARIABLEINFO + } + } ZEND_HASH_FOREACH_END(); + } - if (!EG(active_symbol_table)) { - phpdbg_error("No active symbol table!"); - return SUCCESS; + return SUCCESS; +} /* }}} */ + +static int phpdbg_arm_auto_global(zend_auto_global *auto_global TSRMLS_DC) { + if (auto_global->armed) { + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + phpdbg_notice("variableinfo", "unreachable=\"%.*s\"", "Cannot show information about superglobal variable %.*s", auto_global->name->len, auto_global->name->val); + } else { + auto_global->armed = auto_global->auto_global_callback(auto_global->name TSRMLS_CC); } } - zend_hash_init(&vars, 8, NULL, NULL, 0); + return 0; +} - zend_hash_internal_pointer_reset_ex(EG(active_symbol_table), &pos); - while (zend_hash_get_current_key_ex(EG(active_symbol_table), &var, - NULL, NULL, 0, &pos) == HASH_KEY_IS_STRING) { - zend_hash_get_current_data_ex(EG(active_symbol_table), (void **)&data, &pos); - if (*var != '_') { - zend_hash_update( - &vars, var, strlen(var)+1, (void**)data, sizeof(zval*), NULL); - } - zend_hash_move_forward_ex(EG(active_symbol_table), &pos); +static int phpdbg_print_symbols(zend_bool show_globals TSRMLS_DC) { + HashTable vars; + zend_array *symtable; + zend_string *var; + zval *data; + + if (!EG(current_execute_data) || !EG(current_execute_data)->func) { + phpdbg_error("inactive", "type=\"op_array\"", "No active op array!"); + return SUCCESS; + } + + if (show_globals) { + /* that array should only be manipulated during init, so safe for async access during execution */ + zend_hash_apply(CG(auto_globals), (apply_func_t) phpdbg_arm_auto_global TSRMLS_CC); + symtable = &EG(symbol_table); + } else if (!(symtable = zend_rebuild_symbol_table(TSRMLS_C))) { + phpdbg_error("inactive", "type=\"symbol_table\"", "No active symbol table!"); + return SUCCESS; } - { - zend_op_array *ops = EG(active_op_array); - + zend_hash_init(&vars, 8, NULL, NULL, 0); + + phpdbg_try_access { + ZEND_HASH_FOREACH_STR_KEY_VAL(&symtable->ht, var, data) { + if (zend_is_auto_global(var TSRMLS_CC) ^ !show_globals) { + zend_hash_update(&vars, var, data); + } + } ZEND_HASH_FOREACH_END(); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Cannot fetch all data from the symbol table, invalid data source"); + } phpdbg_end_try_access(); + + if (show_globals) { + phpdbg_notice("variableinfo", "num=\"%d\"", "Superglobal variables (%d)", zend_hash_num_elements(&vars)); + } else { + zend_op_array *ops = &EG(current_execute_data)->func->op_array; + if (ops->function_name) { if (ops->scope) { - phpdbg_notice( - "Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars)); + phpdbg_notice("variableinfo", "method=\"%s::%s\" num=\"%d\"", "Variables in %s::%s() (%d)", ops->scope->name, ops->function_name, zend_hash_num_elements(&vars)); } else { - phpdbg_notice( - "Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars)); + phpdbg_notice("variableinfo", "function=\"%s\" num=\"%d\"", "Variables in %s() (%d)", ops->function_name, zend_hash_num_elements(&vars)); } } else { if (ops->filename) { - phpdbg_notice( - "Variables in %s (%d)", ops->filename, zend_hash_num_elements(&vars)); + phpdbg_notice("variableinfo", "file=\"%s\" num=\"%d\"", "Variables in %s (%d)", ops->filename->val, zend_hash_num_elements(&vars)); } else { - phpdbg_notice( - "Variables @ %p (%d)", ops, zend_hash_num_elements(&vars)); + phpdbg_notice("variableinfo", "opline=\"%p\" num=\"%d\"", "Variables @ %p (%d)", ops, zend_hash_num_elements(&vars)); } } } if (zend_hash_num_elements(&vars)) { - phpdbg_writeln("Address\t\tRefs\tType\t\tVariable"); - for (zend_hash_internal_pointer_reset_ex(&vars, &pos); - zend_hash_get_current_data_ex(&vars, (void**) &data, &pos) == SUCCESS; - zend_hash_move_forward_ex(&vars, &pos)) { - char *var; - - zend_hash_get_current_key_ex(&vars, &var, NULL, NULL, 0, &pos); - - if (*data) { - phpdbg_write( - "%p\t%d\t", - *data, - Z_REFCOUNT_PP(data)); - - switch (Z_TYPE_PP(data)) { - case IS_STRING: phpdbg_write("(string)\t"); break; - case IS_LONG: phpdbg_write("(integer)\t"); break; - case IS_DOUBLE: phpdbg_write("(float)\t"); break; - case IS_RESOURCE: phpdbg_write("(resource)\t"); break; - case IS_ARRAY: phpdbg_write("(array)\t"); break; - case IS_OBJECT: phpdbg_write("(object)\t"); break; - case IS_NULL: phpdbg_write("(null)\t"); break; + phpdbg_out("Address Refs Type Variable\n"); + ZEND_HASH_FOREACH_STR_KEY_VAL(&vars, var, data) { + phpdbg_try_access { +#define VARIABLEINFO(attrs, msg, ...) phpdbg_writeln("variable", "address=\"%p\" refcount=\"%d\" type=\"%s\" refstatus=\"%s\" name=\"%.*s\" " attrs, "%-18p %-7d %-9s %s$%.*s" msg, data, Z_REFCOUNT_P(data), zend_zval_type_name(data), Z_ISREF_P(data) ? "&": "", var->len, var->val, ##__VA_ARGS__) + + switch (Z_TYPE_P(data)) { + case IS_RESOURCE: + phpdbg_try_access { + const char *type = zend_rsrc_list_get_rsrc_type(Z_RES_P(data) TSRMLS_CC); + VARIABLEINFO("type=\"%s\"", "\n|-------(typeof)------> (%s)\n", type ? type : "unknown"); + } phpdbg_catch_access { + VARIABLEINFO("type=\"unknown\"", "\n|-------(typeof)------> (unknown)\n"); + } phpdbg_end_try_access(); + break; + case IS_OBJECT: + phpdbg_try_access { + VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (%s)\n", Z_OBJCE_P(data)->name); + } phpdbg_catch_access { + VARIABLEINFO("instanceof=\"%s\"", "\n|-----(instanceof)----> (unknown)\n"); + } phpdbg_end_try_access(); + break; + case IS_STRING: + phpdbg_try_access { + VARIABLEINFO("length=\"%d\" value=\"%.*s\"", "\nstring (%d) \"%.*s%s\"", Z_STRLEN_P(data), Z_STRLEN_P(data) < 255 ? Z_STRLEN_P(data) : 255, Z_STRVAL_P(data), Z_STRLEN_P(data) > 255 ? "..." : ""); + } phpdbg_catch_access { + VARIABLEINFO("", ""); + } phpdbg_end_try_access(); + break; + case IS_TRUE: + VARIABLEINFO("value=\"true\"", "\nbool (true)"); + break; + case IS_FALSE: + VARIABLEINFO("value=\"false\"", "\nbool (false)"); + break; + case IS_LONG: + VARIABLEINFO("value=\"%ld\"", "\nint (%ld)", Z_LVAL_P(data)); + break; + case IS_DOUBLE: + VARIABLEINFO("value=\"%lf\"", "\ndouble (%lf)", Z_DVAL_P(data)); + break; + default: + VARIABLEINFO("", ""); } - if (Z_TYPE_PP(data) == IS_RESOURCE) { - int type; - - phpdbg_writeln( - "%s$%s", Z_ISREF_PP(data) ? "&": "", var); - if (zend_list_find(Z_RESVAL_PP(data), &type)) { - phpdbg_write( - "|-------(typeof)------> (%s)", - zend_rsrc_list_get_rsrc_type(type TSRMLS_CC)); - } else { - phpdbg_write( - "|-------(typeof)------> (unknown)"); - } - phpdbg_writeln(EMPTY); - } else if (Z_TYPE_PP(data) == IS_OBJECT) { - phpdbg_writeln( - "%s$%s", Z_ISREF_PP(data) ? "&": "", var); - phpdbg_write( - "|-----(instanceof)----> (%s)", Z_OBJCE_PP(data)->name); - phpdbg_writeln(EMPTY); - } else { - phpdbg_write( - "%s$%s", Z_ISREF_PP(data) ? "&": "", var); - } - } else { - phpdbg_write( - "n/a\tn/a\tn/a\t$%s", var); - } - phpdbg_writeln(EMPTY); - } +#undef VARIABLEINFO + } phpdbg_catch_access { + phpdbg_writeln("variable", "address=\"%p\" name=\"%s\"", "%p\tn/a\tn/a\t$%s", data, var); + } phpdbg_end_try_access(); + } ZEND_HASH_FOREACH_END(); } zend_hash_destroy(&vars); @@ -204,42 +274,48 @@ PHPDBG_INFO(vars) /* {{{ */ return SUCCESS; } /* }}} */ +PHPDBG_INFO(vars) /* {{{ */ +{ + return phpdbg_print_symbols(0 TSRMLS_CC); +} + +PHPDBG_INFO(globals) /* {{{ */ +{ + return phpdbg_print_symbols(1 TSRMLS_CC); +} + PHPDBG_INFO(literal) /* {{{ */ { - if ((EG(in_execution) && EG(active_op_array)) || PHPDBG_G(ops)) { - zend_op_array *ops = EG(active_op_array) ? EG(active_op_array) : PHPDBG_G(ops); + /* literals are assumed to not be manipulated during executing of their op_array and as such async safe */ + zend_bool in_executor = PHPDBG_G(in_execution) && EG(current_execute_data) && EG(current_execute_data)->func; + if (in_executor || PHPDBG_G(ops)) { + zend_op_array *ops = in_executor ? &EG(current_execute_data)->func->op_array : PHPDBG_G(ops); int literal = 0, count = ops->last_literal-1; if (ops->function_name) { if (ops->scope) { - phpdbg_notice( - "Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count); + phpdbg_notice("literalinfo", "method=\"%s::%s\" num=\"%d\"", "Literal Constants in %s::%s() (%d)", ops->scope->name, ops->function_name, count); } else { - phpdbg_notice( - "Literal Constants in %s() (%d)", ops->function_name, count); + phpdbg_notice("literalinfo", "function=\"%s\" num=\"%d\"", "Literal Constants in %s() (%d)", ops->function_name, count); } } else { if (ops->filename) { - phpdbg_notice( - "Literal Constants in %s (%d)", ops->filename, count); + phpdbg_notice("literalinfo", "file=\"%s\" num=\"%d\"", "Literal Constants in %s (%d)", ops->filename->val, count); } else { - phpdbg_notice( - "Literal Constants @ %p (%d)", ops, count); + phpdbg_notice("literalinfo", "opline=\"%p\" num=\"%d\"", "Literal Constants @ %p (%d)", ops, count); } } while (literal < ops->last_literal) { - if (Z_TYPE(ops->literals[literal].constant) != IS_NULL) { - phpdbg_write("|-------- C%u -------> [", literal); - zend_print_zval( - &ops->literals[literal].constant, 0); - phpdbg_write("]"); - phpdbg_writeln(EMPTY); + if (Z_TYPE(ops->literals[literal]) != IS_NULL) { + phpdbg_write("literal", "id=\"%u\"", "|-------- C%u -------> [", literal); + zend_print_zval(&ops->literals[literal], 0 TSRMLS_CC); + phpdbg_out("]\n"); } literal++; } } else { - phpdbg_error("Not executing!"); + phpdbg_error("inactive", "type=\"execution\"", "Not executing!"); } return SUCCESS; @@ -247,85 +323,84 @@ PHPDBG_INFO(literal) /* {{{ */ PHPDBG_INFO(memory) /* {{{ */ { - if (is_zend_mm(TSRMLS_C)) { - phpdbg_notice("Memory Manager Information"); - phpdbg_notice("Current"); - phpdbg_writeln("|-------> Used:\t%.3f kB", - (float) (zend_memory_usage(0 TSRMLS_CC)/1024)); - phpdbg_writeln("|-------> Real:\t%.3f kB", - (float) (zend_memory_usage(1 TSRMLS_CC)/1024)); - phpdbg_notice("Peak"); - phpdbg_writeln("|-------> Used:\t%.3f kB", - (float) (zend_memory_peak_usage(0 TSRMLS_CC)/1024)); - phpdbg_writeln("|-------> Real:\t%.3f kB", - (float) (zend_memory_peak_usage(1 TSRMLS_CC)/1024)); + size_t used, real, peak_used, peak_real; + zend_mm_heap *heap; + zend_bool is_mm; + + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + heap = zend_mm_set_heap(phpdbg_original_heap_sigsafe_mem(TSRMLS_C) TSRMLS_CC); + } + if ((is_mm = is_zend_mm(TSRMLS_C))) { + used = zend_memory_usage(0 TSRMLS_CC); + real = zend_memory_usage(1 TSRMLS_CC); + peak_used = zend_memory_peak_usage(0 TSRMLS_CC); + peak_real = zend_memory_peak_usage(1 TSRMLS_CC); + } + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + zend_mm_set_heap(heap TSRMLS_CC); + } + + if (is_mm) { + phpdbg_notice("meminfo", "", "Memory Manager Information"); + phpdbg_notice("current", "", "Current"); + phpdbg_writeln("used", "mem=\"%.3f\"", "|-------> Used:\t%.3f kB", (float) (used / 1024)); + phpdbg_writeln("real", "mem=\"%.3f\"", "|-------> Real:\t%.3f kB", (float) (real / 1024)); + phpdbg_notice("peak", "", "Peak"); + phpdbg_writeln("used", "mem=\"%.3f\"", "|-------> Used:\t%.3f kB", (float) (peak_used / 1024)); + phpdbg_writeln("real", "mem=\"%.3f\"", "|-------> Real:\t%.3f kB", (float) (peak_real / 1024)); } else { - phpdbg_error("Memory Manager Disabled!"); + phpdbg_error("inactive", "type=\"memory_manager\"", "Memory Manager Disabled!"); } return SUCCESS; } /* }}} */ -static inline void phpdbg_print_class_name(zend_class_entry **ce TSRMLS_DC) /* {{{ */ +static inline void phpdbg_print_class_name(zend_class_entry *ce TSRMLS_DC) /* {{{ */ { - phpdbg_write( - "%s %s %s (%d)", - ((*ce)->type == ZEND_USER_CLASS) ? - "User" : "Internal", - ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ? - "Interface" : - ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ? - "Abstract Class" : - "Class", - (*ce)->name, zend_hash_num_elements(&(*ce)->function_table)); + const char *visibility = ce->type == ZEND_USER_CLASS ? "User" : "Internal"; + const char *type = (ce->ce_flags & ZEND_ACC_INTERFACE) ? "Interface" : (ce->ce_flags & ZEND_ACC_ABSTRACT) ? "Abstract Class" : "Class"; + + phpdbg_writeln("class", "type=\"%s\" flags=\"%s\" name=\"%.*s\" methodcount=\"%d\"", "%s %s %.*s (%d)", visibility, type, ce->name->len, ce->name->val, zend_hash_num_elements(&ce->function_table)); } /* }}} */ PHPDBG_INFO(classes) /* {{{ */ { - HashPosition position; - zend_class_entry **ce; + zend_class_entry *ce; HashTable classes; zend_hash_init(&classes, 8, NULL, NULL, 0); - for (zend_hash_internal_pointer_reset_ex(EG(class_table), &position); - zend_hash_get_current_data_ex(EG(class_table), (void**)&ce, &position) == SUCCESS; - zend_hash_move_forward_ex(EG(class_table), &position)) { - - if ((*ce)->type == ZEND_USER_CLASS) { - zend_hash_next_index_insert( - &classes, ce, sizeof(ce), NULL); - } - } - - phpdbg_notice("User Classes (%d)", - zend_hash_num_elements(&classes)); + phpdbg_try_access { + ZEND_HASH_FOREACH_PTR(EG(class_table), ce) { + if (ce->type == ZEND_USER_CLASS) { + zend_hash_next_index_insert_ptr(&classes, ce); + } + } ZEND_HASH_FOREACH_END(); + } phpdbg_catch_access { + phpdbg_notice("signalsegv", "", "Not all classes could be fetched, possibly invalid data source"); + } phpdbg_end_try_access(); - for (zend_hash_internal_pointer_reset_ex(&classes, &position); - zend_hash_get_current_data_ex(&classes, (void**)&ce, &position) == SUCCESS; - zend_hash_move_forward_ex(&classes, &position)) { + phpdbg_notice("classinfo", "num=\"%d\"", "User Classes (%d)", zend_hash_num_elements(&classes)); + /* once added, assume that classes are stable... until shutdown. */ + ZEND_HASH_FOREACH_PTR(&classes, ce) { phpdbg_print_class_name(ce TSRMLS_CC); - phpdbg_writeln(EMPTY); - if ((*ce)->parent) { - zend_class_entry *pce = (*ce)->parent; + if (ce->parent) { + phpdbg_xml("<parents %r>"); + zend_class_entry *pce = ce->parent; do { - phpdbg_write("|-------- "); - phpdbg_print_class_name(&pce TSRMLS_CC); - phpdbg_writeln(EMPTY); + phpdbg_out("|-------- "); + phpdbg_print_class_name(pce TSRMLS_CC); } while ((pce = pce->parent)); + phpdbg_xml("</parents>"); } - if ((*ce)->info.user.filename) { - phpdbg_writeln( - "|---- in %s on line %u", - (*ce)->info.user.filename, - (*ce)->info.user.line_start); + if (ce->info.user.filename) { + phpdbg_writeln("classsource", "file=\"%s\" line=\"%u\"", "|---- in %s on line %u", ce->info.user.filename->val, ce->info.user.line_start); } else { - phpdbg_writeln("|---- no source code"); + phpdbg_writeln("classsource", "", "|---- no source code"); } - phpdbg_writeln(EMPTY); - } + } ZEND_HASH_FOREACH_END(); zend_hash_destroy(&classes); @@ -334,36 +409,34 @@ PHPDBG_INFO(classes) /* {{{ */ PHPDBG_INFO(funcs) /* {{{ */ { - HashPosition position; - zend_function *zf, **pzf; + zend_function *zf; HashTable functions; zend_hash_init(&functions, 8, NULL, NULL, 0); - for (zend_hash_internal_pointer_reset_ex(EG(function_table), &position); - zend_hash_get_current_data_ex(EG(function_table), (void**)&zf, &position) == SUCCESS; - zend_hash_move_forward_ex(EG(function_table), &position)) { + phpdbg_try_access { + ZEND_HASH_FOREACH_PTR(EG(function_table), zf) { + if (zf->type == ZEND_USER_FUNCTION) { + zend_hash_next_index_insert_ptr(&functions, zf); + } + } ZEND_HASH_FOREACH_END(); + } phpdbg_catch_access { + phpdbg_notice("signalsegv", "", "Not all functions could be fetched, possibly invalid data source"); + } phpdbg_end_try_access(); - if (zf->type == ZEND_USER_FUNCTION) { - zend_hash_next_index_insert( - &functions, (void**) &zf, sizeof(zend_function), NULL); - } - } + phpdbg_notice("functioninfo", "num=\"%d\"", "User Functions (%d)", zend_hash_num_elements(&functions)); - phpdbg_notice("User Functions (%d)", - zend_hash_num_elements(&functions)); + ZEND_HASH_FOREACH_PTR(&functions, zf) { + zend_op_array *op_array = &zf->op_array; - for (zend_hash_internal_pointer_reset_ex(&functions, &position); - zend_hash_get_current_data_ex(&functions, (void**)&pzf, &position) == SUCCESS; - zend_hash_move_forward_ex(&functions, &position)) { - zend_op_array *op_array = &((*pzf)->op_array); + phpdbg_write("function", "name=\"%s\"", "|-------- %s", op_array->function_name ? op_array->function_name->val : "{main}"); - phpdbg_writeln( - "|-------- %s in %s on line %d", - op_array->function_name ? op_array->function_name : "{main}", - op_array->filename ? op_array->filename : "(no source code)", - op_array->line_start); - } + if (op_array->filename) { + phpdbg_writeln("functionsource", "file=\"%s\" line=\"%d\"", " in %s on line %d", op_array->filename->val, op_array->line_start); + } else { + phpdbg_writeln("functionsource", "", " (no source code)"); + } + } ZEND_HASH_FOREACH_END(); zend_hash_destroy(&functions); diff --git a/sapi/phpdbg/phpdbg_info.h b/sapi/phpdbg/phpdbg_info.h index fcdc131fd5..aac9fa3ab3 100644 --- a/sapi/phpdbg/phpdbg_info.h +++ b/sapi/phpdbg/phpdbg_info.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -30,7 +30,9 @@ PHPDBG_INFO(break); PHPDBG_INFO(classes); PHPDBG_INFO(funcs); PHPDBG_INFO(error); +PHPDBG_INFO(constants); PHPDBG_INFO(vars); +PHPDBG_INFO(globals); PHPDBG_INFO(literal); PHPDBG_INFO(memory); diff --git a/sapi/phpdbg/phpdbg_io.c b/sapi/phpdbg/phpdbg_io.c new file mode 100644 index 0000000000..97f0356285 --- /dev/null +++ b/sapi/phpdbg/phpdbg_io.c @@ -0,0 +1,272 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "phpdbg_io.h" + +#ifdef PHP_WIN32 +#undef UNICODE +#include "win32/inet.h" +#include <winsock2.h> +#include <windows.h> +#include <Ws2tcpip.h> +#include "win32/sockets.h" + +#else + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#include <sys/socket.h> +#include <netinet/in.h> +#if HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#include <netdb.h> +#include <fcntl.h> +#include <poll.h> +#endif + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC) { + int got_now, i = len, j; + char *p = ptr; +#ifndef PHP_WIN32 + struct pollfd pfd; + + if (tmo < 0) goto recv_once; + pfd.fd = sock; + pfd.events = POLLIN; + + j = poll(&pfd, 1, tmo); + + if (j == 0) { +#else + struct fd_set readfds; + struct timeval ttmo; + + if (tmo < 0) goto recv_once; + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + + ttmo.tv_sec = 0; + ttmo.tv_usec = tmo*1000; + + j = select(0, &readfds, NULL, NULL, &ttmo); + + if (j <= 0) { +#endif + return -1; + } + +recv_once: + while(i > 0) { + if (tmo < 0) { + /* There's something to read. Read what's available and proceed + disregarding whether len could be exhausted or not.*/ + int can_read = recv(sock, p, i, MSG_PEEK); +#ifndef _WIN32 + if (can_read == -1 && errno == EINTR) { + continue; + } +#endif + i = can_read; + } + +#ifdef _WIN32 + got_now = recv(sock, p, i, 0); +#else + do { + got_now = recv(sock, p, i, 0); + } while (got_now == -1 && errno == EINTR); +#endif + + if (got_now == -1) { + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Read operation timed out!\n")); + return -1; + } + i -= got_now; + p += got_now; + } + + return p - ptr; +} + +PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len) { + int sent, i = len; + const char *p = ptr; +/* XXX poll/select needed here? */ + while(i > 0) { + sent = send(sock, p, i, 0); + if (sent == -1) { + return -1; + } + i -= sent; + p += sent; + } + + return len; +} + + +PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC) { + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { + return phpdbg_consume_bytes(sock, ptr, len, tmo TSRMLS_CC); + } + + return read(sock, ptr, len); +} + + +PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC) { + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) { + return phpdbg_send_bytes(sock, ptr, len); + } + + return write(sock, ptr, len); +} + + +PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port TSRMLS_DC) { + struct addrinfo res; + int fd = phpdbg_create_listenable_socket(interface, port, &res TSRMLS_CC); + + if (fd == -1) { + return -1; + } + + if (bind(fd, res.ai_addr, res.ai_addrlen) == -1) { + phpdbg_close_socket(fd); + return -4; + } + + listen(fd, 5); + + return fd; +} + + +PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short port, struct addrinfo *addr_res TSRMLS_DC) { + int sock = -1, rc; + int reuse = 1; + struct in6_addr serveraddr; + struct addrinfo hints, *res = NULL; + char port_buf[8]; + int8_t any_addr = *addr == '*'; + + do { + memset(&hints, 0, sizeof hints); + if (any_addr) { + hints.ai_flags = AI_PASSIVE; + } else { + hints.ai_flags = AI_NUMERICSERV; + } + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + rc = inet_pton(AF_INET, addr, &serveraddr); + if (1 == rc) { + hints.ai_family = AF_INET; + if (!any_addr) { + hints.ai_flags |= AI_NUMERICHOST; + } + } else { + rc = inet_pton(AF_INET6, addr, &serveraddr); + if (1 == rc) { + hints.ai_family = AF_INET6; + if (!any_addr) { + hints.ai_flags |= AI_NUMERICHOST; + } + } else { + /* XXX get host by name ??? */ + } + } + + snprintf(port_buf, 7, "%u", port); + if (!any_addr) { + rc = getaddrinfo(addr, port_buf, &hints, &res); + } else { + rc = getaddrinfo(NULL, port_buf, &hints, &res); + } + + if (0 != rc) { +#ifndef PHP_WIN32 + if (rc == EAI_SYSTEM) { + char buf[128]; + int wrote; + + wrote = snprintf(buf, 128, "Could not translate address '%s'", addr); + buf[wrote] = '\0'; + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf)); + + return sock; + } else { +#endif + char buf[256]; + int wrote; + + wrote = snprintf(buf, 256, "Host '%s' not found. %s", addr, estrdup(gai_strerror(rc))); + buf[wrote] = '\0'; + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf)); + + return sock; +#ifndef PHP_WIN32 + } +#endif + return sock; + } + + if((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) { + char buf[128]; + int wrote; + + wrote = sprintf(buf, "Unable to create socket"); + buf[wrote] = '\0'; + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf)); + + return sock; + } + + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse)) == -1) { + phpdbg_close_socket(sock); + return sock; + } + + + } while (0); + + *addr_res = *res; + + return sock; +} + +PHPDBG_API void phpdbg_close_socket(int sock) { + if (socket >= 0) { +#ifdef _WIN32 + closesocket(sock); +#else + shutdown(sock, SHUT_RDWR); + close(sock); +#endif + } +} + diff --git a/sapi/phpdbg/phpdbg_io.h b/sapi/phpdbg/phpdbg_io.h new file mode 100644 index 0000000000..3ac8f4112d --- /dev/null +++ b/sapi/phpdbg/phpdbg_io.h @@ -0,0 +1,34 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_IO_H +#define PHPDBG_IO_H + +#include "phpdbg.h" + +PHPDBG_API int phpdbg_consume_bytes(int sock, char *ptr, int len, int tmo TSRMLS_DC); +PHPDBG_API int phpdbg_send_bytes(int sock, const char *ptr, int len); +PHPDBG_API int phpdbg_mixed_read(int sock, char *ptr, int len, int tmo TSRMLS_DC); +PHPDBG_API int phpdbg_mixed_write(int sock, const char *ptr, int len TSRMLS_DC); + +PHPDBG_API int phpdbg_create_listenable_socket(const char *addr, unsigned short port, struct addrinfo *res TSRMLS_DC); +PHPDBG_API int phpdbg_open_socket(const char *interface, unsigned short port TSRMLS_DC); +PHPDBG_API void phpdbg_close_socket(int sock); + +#endif /* PHPDBG_IO_H */ + diff --git a/sapi/phpdbg/phpdbg_lexer.c b/sapi/phpdbg/phpdbg_lexer.c index 3092dc396d..90f3a449da 100644 --- a/sapi/phpdbg/phpdbg_lexer.c +++ b/sapi/phpdbg/phpdbg_lexer.c @@ -1,5 +1,5 @@ /* Generated by re2c 0.13.5 */ -#line 1 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 1 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" /* * phpdbg_lexer.l */ @@ -23,8 +23,9 @@ #define YYFILL(n) #define NORMAL 0 -#define RAW 1 -#define INITIAL 2 +#define PRE_RAW 1 +#define RAW 2 +#define INITIAL 3 ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -44,14 +45,18 @@ restart: LEX(text) = YYCURSOR; -#line 48 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 49 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" { YYCTYPE yych; unsigned int yyaccept = 0; - if (YYGETCONDITION() < 1) { - goto yyc_NORMAL; + if (YYGETCONDITION() < 2) { + if (YYGETCONDITION() < 1) { + goto yyc_NORMAL; + } else { + goto yyc_PRE_RAW; + } } else { - if (YYGETCONDITION() < 2) { + if (YYGETCONDITION() < 3) { goto yyc_RAW; } else { goto yyc_INITIAL; @@ -62,10 +67,10 @@ yyc_INITIAL: { static const unsigned char yybm[] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 128, 128, 0, 0, 128, 0, 0, + 0, 192, 96, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 128, 0, 0, 0, 0, 0, 0, 0, + 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -98,1046 +103,1417 @@ yyc_INITIAL: YYDEBUG(0, *YYCURSOR); YYFILL(4); yych = *YYCURSOR; - if (yych <= 'D') { - if (yych <= '\n') { - if (yych <= 0x00) goto yy6; - if (yych <= 0x08) goto yy11; - if (yych >= '\n') goto yy4; + if (yybm[0+yych] & 32) { + goto yy4; + } + if (yych <= 'E') { + if (yych <= '\f') { + if (yych <= 0x00) goto yy7; + if (yych != '\t') goto yy12; } else { - if (yych <= '\r') { - if (yych <= '\f') goto yy11; + if (yych <= 0x1F) { + if (yych >= 0x0E) goto yy12; } else { - if (yych != ' ') goto yy11; + if (yych <= ' ') goto yy2; + if (yych <= 'D') goto yy12; + goto yy8; } } } else { if (yych <= 'd') { - if (yych <= 'Q') { - if (yych <= 'E') goto yy7; - goto yy11; - } else { - if (yych <= 'R') goto yy10; - if (yych <= 'S') goto yy8; - goto yy11; - } + if (yych <= 'Q') goto yy12; + if (yych <= 'R') goto yy11; + if (yych <= 'S') goto yy9; + goto yy12; } else { if (yych <= 'q') { - if (yych <= 'e') goto yy7; - goto yy11; + if (yych <= 'e') goto yy8; + goto yy12; } else { - if (yych <= 'r') goto yy9; - if (yych <= 's') goto yy8; - goto yy11; + if (yych <= 'r') goto yy10; + if (yych <= 's') goto yy9; + goto yy12; } } } +yy2: YYDEBUG(2, *YYCURSOR); ++YYCURSOR; if ((yych = *YYCURSOR) <= '\f') { + if (yych <= 0x00) goto yy29; if (yych <= 0x08) goto yy3; - if (yych <= '\n') goto yy26; + if (yych <= '\n') goto yy29; } else { - if (yych <= '\r') goto yy26; - if (yych == ' ') goto yy26; + if (yych <= '\r') goto yy29; + if (yych == ' ') goto yy29; } yy3: YYDEBUG(3, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 161 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 176 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { YYSETCONDITION(NORMAL); YYCURSOR = LEX(text); goto restart; } -#line 154 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 161 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; - if ((yych = *YYCURSOR) <= '\f') { - if (yych <= 0x08) goto yy5; - if (yych <= '\n') goto yy26; - } else { - if (yych <= '\r') goto yy26; - if (yych == ' ') goto yy26; - } -yy5: + YYFILL(1); + yych = *YYCURSOR; YYDEBUG(5, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy28; + } + if (yych <= 0x00) goto yy27; + if (yych == '\n') goto yy4; +yy6: + YYDEBUG(6, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 172 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy6: - YYDEBUG(6, *YYCURSOR); - yych = *++YYCURSOR; - goto yy3; +#line 180 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" yy7: YYDEBUG(7, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'V') goto yy22; - if (yych == 'v') goto yy22; + yych = *++YYCURSOR; goto yy3; yy8: YYDEBUG(8, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'H') goto yy18; - if (yych == 'h') goto yy18; + if (yych == 'V') goto yy23; + if (yych == 'v') goto yy23; goto yy3; yy9: YYDEBUG(9, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy15; - } - if (yych == 'U') goto yy12; - if (yych == 'u') goto yy12; + if (yych == 'H') goto yy19; + if (yych == 'h') goto yy19; goto yy3; yy10: YYDEBUG(10, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'U') goto yy12; - if (yych == 'u') goto yy12; + if (yybm[0+yych] & 64) { + goto yy16; + } + if (yych == 'U') goto yy13; + if (yych == 'u') goto yy13; goto yy3; yy11: YYDEBUG(11, *YYCURSOR); - yych = *++YYCURSOR; + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'U') goto yy13; + if (yych == 'u') goto yy13; goto yy3; yy12: YYDEBUG(12, *YYCURSOR); yych = *++YYCURSOR; - if (yych == 'N') goto yy14; - if (yych == 'n') goto yy14; + goto yy3; yy13: YYDEBUG(13, *YYCURSOR); - YYCURSOR = YYMARKER; - goto yy3; + yych = *++YYCURSOR; + if (yych == 'N') goto yy15; + if (yych == 'n') goto yy15; yy14: YYDEBUG(14, *YYCURSOR); - yych = *++YYCURSOR; - if (yybm[0+yych] & 128) { - goto yy15; - } - goto yy13; + YYCURSOR = YYMARKER; + goto yy3; yy15: YYDEBUG(15, *YYCURSOR); + yych = *++YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy16; + } + goto yy14; +yy16: + YYDEBUG(16, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(16, *YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy15; - } YYDEBUG(17, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy16; + } + YYDEBUG(18, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 155 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 163 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_RUN; } -#line 245 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy18: - YYDEBUG(18, *YYCURSOR); +#line 253 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy19: + YYDEBUG(19, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '\f') { - if (yych <= 0x08) goto yy13; - if (yych >= '\v') goto yy13; + if (yych <= 0x08) goto yy14; + if (yych >= '\v') goto yy14; } else { - if (yych <= '\r') goto yy19; - if (yych != ' ') goto yy13; + if (yych <= '\r') goto yy20; + if (yych != ' ') goto yy14; } -yy19: - YYDEBUG(19, *YYCURSOR); +yy20: + YYDEBUG(20, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(20, *YYCURSOR); + YYDEBUG(21, *YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy21; - if (yych <= '\n') goto yy19; + if (yych <= 0x08) goto yy22; + if (yych <= '\n') goto yy20; } else { - if (yych <= '\r') goto yy19; - if (yych == ' ') goto yy19; + if (yych <= '\r') goto yy20; + if (yych == ' ') goto yy20; } -yy21: - YYDEBUG(21, *YYCURSOR); +yy22: + YYDEBUG(22, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 150 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 158 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_SHELL; } -#line 278 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy22: - YYDEBUG(22, *YYCURSOR); +#line 286 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy23: + YYDEBUG(23, *YYCURSOR); yych = *++YYCURSOR; if (yych <= '\f') { - if (yych <= 0x08) goto yy13; - if (yych >= '\v') goto yy13; + if (yych <= 0x08) goto yy14; + if (yych >= '\v') goto yy14; } else { - if (yych <= '\r') goto yy23; - if (yych != ' ') goto yy13; + if (yych <= '\r') goto yy24; + if (yych != ' ') goto yy14; } -yy23: - YYDEBUG(23, *YYCURSOR); +yy24: + YYDEBUG(24, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(24, *YYCURSOR); + YYDEBUG(25, *YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy25; - if (yych <= '\n') goto yy23; + if (yych <= 0x08) goto yy26; + if (yych <= '\n') goto yy24; } else { - if (yych <= '\r') goto yy23; - if (yych == ' ') goto yy23; + if (yych <= '\r') goto yy24; + if (yych == ' ') goto yy24; } -yy25: - YYDEBUG(25, *YYCURSOR); +yy26: + YYDEBUG(26, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 145 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 153 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_EVAL; } -#line 311 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy26: - YYDEBUG(26, *YYCURSOR); +#line 319 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy27: + YYDEBUG(27, *YYCURSOR); + yych = *++YYCURSOR; + goto yy6; +yy28: + YYDEBUG(28, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(27, *YYCURSOR); - if (yych <= '\f') { - if (yych <= 0x08) goto yy28; - if (yych <= '\n') goto yy26; - } else { - if (yych <= '\r') goto yy26; - if (yych == ' ') goto yy26; +yy29: + YYDEBUG(29, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy28; } -yy28: - YYDEBUG(28, *YYCURSOR); + if (yych <= 0x00) goto yy27; + if (yych == '\n') goto yy4; + YYDEBUG(30, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { /* ignore whitespace */ goto restart; } -#line 334 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 344 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" } /* *********************************** */ yyc_NORMAL: { static const unsigned char yybm[] = { - 0, 16, 16, 16, 16, 16, 16, 16, - 16, 8, 8, 16, 16, 8, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 8, 16, 16, 0, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 48, 16, - 176, 176, 176, 176, 176, 176, 176, 176, - 176, 176, 0, 16, 16, 16, 16, 16, - 16, 208, 208, 208, 208, 208, 208, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 16, 16, 16, 16, 16, - 16, 208, 208, 208, 208, 208, 208, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, + 0, 8, 8, 8, 8, 8, 8, 8, + 8, 66, 68, 8, 8, 66, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 66, 8, 8, 0, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 24, 8, + 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 0, 8, 8, 8, 8, 8, + 8, 168, 168, 168, 168, 168, 168, 40, + 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 8, 8, 8, 8, 8, + 8, 168, 168, 168, 168, 168, 168, 40, + 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, }; - YYDEBUG(29, *YYCURSOR); + YYDEBUG(31, *YYCURSOR); YYFILL(11); yych = *YYCURSOR; - YYDEBUG(-1, yych); - switch (yych) { - case 0x00: goto yy36; - case '\t': - case '\r': - case ' ': goto yy31; - case '\n': goto yy34; - case '#': goto yy55; - case '-': goto yy41; - case '.': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': goto yy42; - case '0': goto yy45; - case ':': goto yy57; - case 'D': - case 'd': goto yy46; - case 'E': - case 'e': goto yy47; - case 'F': - case 'f': goto yy48; - case 'I': - case 'i': goto yy37; - case 'N': - case 'n': goto yy49; - case 'O': - case 'o': goto yy50; - case 'T': - case 't': goto yy51; - case 'Y': - case 'y': goto yy52; - case 'Z': goto yy53; - case 'z': goto yy54; - default: goto yy39; + if (yybm[0+yych] & 2) { + goto yy33; } -yy31: - YYDEBUG(31, *YYCURSOR); + if (yych <= 'N') { + if (yych <= '0') { + if (yych <= '#') { + if (yych <= '\t') { + if (yych <= 0x00) goto yy39; + goto yy43; + } else { + if (yych <= '\n') goto yy36; + if (yych <= '"') goto yy43; + goto yy58; + } + } else { + if (yych <= '-') { + if (yych <= ',') goto yy43; + goto yy40; + } else { + if (yych <= '.') goto yy45; + if (yych <= '/') goto yy43; + goto yy48; + } + } + } else { + if (yych <= 'E') { + if (yych <= ':') { + if (yych <= '9') goto yy45; + goto yy60; + } else { + if (yych <= 'C') goto yy43; + if (yych <= 'D') goto yy49; + goto yy50; + } + } else { + if (yych <= 'H') { + if (yych <= 'F') goto yy51; + goto yy43; + } else { + if (yych <= 'I') goto yy42; + if (yych <= 'M') goto yy43; + goto yy52; + } + } + } + } else { + if (yych <= 'f') { + if (yych <= 'Y') { + if (yych <= 'S') { + if (yych <= 'O') goto yy53; + goto yy43; + } else { + if (yych <= 'T') goto yy54; + if (yych <= 'X') goto yy43; + goto yy55; + } + } else { + if (yych <= 'c') { + if (yych <= 'Z') goto yy56; + goto yy43; + } else { + if (yych <= 'd') goto yy49; + if (yych <= 'e') goto yy50; + goto yy51; + } + } + } else { + if (yych <= 'o') { + if (yych <= 'i') { + if (yych <= 'h') goto yy43; + goto yy42; + } else { + if (yych <= 'm') goto yy43; + if (yych <= 'n') goto yy52; + goto yy53; + } + } else { + if (yych <= 'x') { + if (yych == 't') goto yy54; + goto yy43; + } else { + if (yych <= 'y') goto yy55; + if (yych <= 'z') goto yy57; + goto yy43; + } + } + } + } +yy33: + YYDEBUG(33, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(32, *YYCURSOR); - if (yybm[0+yych] & 8) { - goto yy31; + YYDEBUG(34, *YYCURSOR); + if (yybm[0+yych] & 2) { + goto yy33; } - YYDEBUG(33, *YYCURSOR); + if (yych <= 0x00) goto yy39; + if (yych == '\n') goto yy36; + YYDEBUG(35, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { /* ignore whitespace */ goto restart; } -#line 434 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy34: - YYDEBUG(34, *YYCURSOR); +#line 493 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy36: + YYDEBUG(36, *YYCURSOR); ++YYCURSOR; - if (yybm[0+(yych = *YYCURSOR)] & 8) { - goto yy31; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(37, *YYCURSOR); + if (yybm[0+yych] & 2) { + goto yy33; } -yy35: - YYDEBUG(35, *YYCURSOR); + if (yych <= 0x00) goto yy39; + if (yych == '\n') goto yy36; +yy38: + YYDEBUG(38, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 448 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy36: - YYDEBUG(36, *YYCURSOR); +#line 512 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy39: + YYDEBUG(39, *YYCURSOR); yych = *++YYCURSOR; - goto yy35; -yy37: - YYDEBUG(37, *YYCURSOR); + goto yy38; +yy40: + YYDEBUG(40, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'F') goto yy106; - if (yych == 'f') goto yy106; - goto yy40; -yy38: - YYDEBUG(38, *YYCURSOR); + if (yybm[0+yych] & 16) { + goto yy45; + } + if (yych == 'r') goto yy113; + goto yy44; +yy41: + YYDEBUG(41, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 125 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 133 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, STR_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_ID; } -#line 470 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy39: - YYDEBUG(39, *YYCURSOR); +#line 536 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy42: + YYDEBUG(42, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'F') goto yy109; + if (yych == 'f') goto yy109; + goto yy44; +yy43: + YYDEBUG(43, *YYCURSOR); yyaccept = 0; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; -yy40: - YYDEBUG(40, *YYCURSOR); - if (yybm[0+yych] & 16) { - goto yy39; - } - if (yych <= '9') goto yy38; - goto yy62; -yy41: - YYDEBUG(41, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 32) { - goto yy42; +yy44: + YYDEBUG(44, *YYCURSOR); + if (yybm[0+yych] & 8) { + goto yy43; } - goto yy40; -yy42: - YYDEBUG(42, *YYCURSOR); + if (yych <= '9') goto yy41; + goto yy65; +yy45: + YYDEBUG(45, *YYCURSOR); yyaccept = 1; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(43, *YYCURSOR); - if (yybm[0+yych] & 32) { - goto yy42; + YYDEBUG(46, *YYCURSOR); + if (yybm[0+yych] & 16) { + goto yy45; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy44; - if (yych <= 0x08) goto yy39; + if (yych <= 0x00) goto yy47; + if (yych <= 0x08) goto yy43; } else { - if (yych != '\r') goto yy39; + if (yych != '\r') goto yy43; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy44; - if (yych <= '"') goto yy39; + if (yych <= ' ') goto yy47; + if (yych <= '"') goto yy43; } else { - if (yych == ':') goto yy62; - goto yy39; + if (yych == ':') goto yy65; + goto yy43; } } -yy44: - YYDEBUG(44, *YYCURSOR); +yy47: + YYDEBUG(47, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 106 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 114 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = atoi(yytext); return T_DIGITS; } -#line 527 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy45: - YYDEBUG(45, *YYCURSOR); +#line 592 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy48: + YYDEBUG(48, *YYCURSOR); yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 32) { - goto yy42; + if (yybm[0+yych] & 16) { + goto yy45; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy44; - if (yych <= 0x08) goto yy40; - goto yy44; + if (yych <= 0x00) goto yy47; + if (yych <= 0x08) goto yy44; + goto yy47; } else { - if (yych == '\r') goto yy44; - goto yy40; + if (yych == '\r') goto yy47; + goto yy44; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy44; - if (yych <= '"') goto yy40; - goto yy44; + if (yych <= ' ') goto yy47; + if (yych <= '"') goto yy44; + goto yy47; } else { - if (yych == 'x') goto yy102; - goto yy40; + if (yych == 'x') goto yy105; + goto yy44; } } -yy46: - YYDEBUG(46, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'I') goto yy96; - if (yych == 'i') goto yy96; - goto yy40; -yy47: - YYDEBUG(47, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'N') goto yy91; - if (yych == 'n') goto yy91; - goto yy40; -yy48: - YYDEBUG(48, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'A') goto yy88; - if (yych == 'a') goto yy88; - goto yy40; yy49: YYDEBUG(49, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'O') goto yy84; - if (yych == 'o') goto yy84; - goto yy40; + if (yych == 'I') goto yy99; + if (yych == 'i') goto yy99; + goto yy44; yy50: YYDEBUG(50, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= 'N') { - if (yych == 'F') goto yy83; - if (yych <= 'M') goto yy40; - goto yy77; - } else { - if (yych <= 'f') { - if (yych <= 'e') goto yy40; - goto yy83; - } else { - if (yych == 'n') goto yy77; - goto yy40; - } - } + if (yych == 'N') goto yy94; + if (yych == 'n') goto yy94; + goto yy44; yy51: YYDEBUG(51, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'R') goto yy81; - if (yych == 'r') goto yy81; - goto yy40; + if (yych == 'A') goto yy91; + if (yych == 'a') goto yy91; + goto yy44; yy52: YYDEBUG(52, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy76; - if (yych == 'e') goto yy76; - goto yy40; + if (yych == 'O') goto yy87; + if (yych == 'o') goto yy87; + goto yy44; yy53: YYDEBUG(53, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy73; - goto yy40; + if (yych <= 'N') { + if (yych == 'F') goto yy86; + if (yych <= 'M') goto yy44; + goto yy80; + } else { + if (yych <= 'f') { + if (yych <= 'e') goto yy44; + goto yy86; + } else { + if (yych == 'n') goto yy80; + goto yy44; + } + } yy54: YYDEBUG(54, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy61; - goto yy40; + if (yych == 'R') goto yy84; + if (yych == 'r') goto yy84; + goto yy44; yy55: YYDEBUG(55, *YYCURSOR); - ++YYCURSOR; + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'E') goto yy79; + if (yych == 'e') goto yy79; + goto yy44; +yy56: YYDEBUG(56, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'E') goto yy76; + goto yy44; +yy57: + YYDEBUG(57, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy64; + goto yy44; +yy58: + YYDEBUG(58, *YYCURSOR); + ++YYCURSOR; + YYDEBUG(59, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 84 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 92 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return T_POUND; } -#line 634 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy57: - YYDEBUG(57, *YYCURSOR); +#line 699 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy60: + YYDEBUG(60, *YYCURSOR); ++YYCURSOR; - if ((yych = *YYCURSOR) == ':') goto yy59; - YYDEBUG(58, *YYCURSOR); + if ((yych = *YYCURSOR) == ':') goto yy62; + YYDEBUG(61, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 90 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 98 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return T_COLON; } -#line 645 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy59: - YYDEBUG(59, *YYCURSOR); +#line 710 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy62: + YYDEBUG(62, *YYCURSOR); ++YYCURSOR; - YYDEBUG(60, *YYCURSOR); + YYDEBUG(63, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 87 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 95 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return T_DCOLON; } -#line 655 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy61: - YYDEBUG(61, *YYCURSOR); +#line 720 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy64: + YYDEBUG(64, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'n') goto yy67; - goto yy40; -yy62: - YYDEBUG(62, *YYCURSOR); + if (yych == 'n') goto yy70; + goto yy44; +yy65: + YYDEBUG(65, *YYCURSOR); yych = *++YYCURSOR; - if (yych == '/') goto yy64; -yy63: - YYDEBUG(63, *YYCURSOR); + if (yych == '/') goto yy67; +yy66: + YYDEBUG(66, *YYCURSOR); YYCURSOR = YYMARKER; - if (yyaccept <= 1) { - if (yyaccept <= 0) { - goto yy38; + if (yyaccept <= 2) { + if (yyaccept <= 1) { + if (yyaccept <= 0) { + goto yy41; + } else { + goto yy47; + } } else { - goto yy44; + goto yy75; } } else { - if (yyaccept <= 2) { - goto yy72; + if (yyaccept <= 3) { + goto yy108; } else { - goto yy105; + goto yy119; } } -yy64: - YYDEBUG(64, *YYCURSOR); +yy67: + YYDEBUG(67, *YYCURSOR); yych = *++YYCURSOR; - if (yych != '/') goto yy63; - YYDEBUG(65, *YYCURSOR); + if (yych != '/') goto yy66; + YYDEBUG(68, *YYCURSOR); ++YYCURSOR; - YYDEBUG(66, *YYCURSOR); + YYDEBUG(69, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 78 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 86 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, STR_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_PROTO; } -#line 697 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy67: - YYDEBUG(67, *YYCURSOR); +#line 766 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy70: + YYDEBUG(70, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'd') goto yy40; - YYDEBUG(68, *YYCURSOR); + if (yych != 'd') goto yy44; + YYDEBUG(71, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != '_') goto yy40; -yy69: - YYDEBUG(69, *YYCURSOR); + if (yych != '_') goto yy44; +yy72: + YYDEBUG(72, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 64) { - goto yy70; + if (yybm[0+yych] & 32) { + goto yy73; } - goto yy40; -yy70: - YYDEBUG(70, *YYCURSOR); + goto yy44; +yy73: + YYDEBUG(73, *YYCURSOR); yyaccept = 2; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(71, *YYCURSOR); - if (yybm[0+yych] & 64) { - goto yy70; + YYDEBUG(74, *YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy73; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy72; - if (yych <= 0x08) goto yy39; + if (yych <= 0x00) goto yy75; + if (yych <= 0x08) goto yy43; } else { - if (yych != '\r') goto yy39; + if (yych != '\r') goto yy43; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy72; - if (yych <= '"') goto yy39; + if (yych <= ' ') goto yy75; + if (yych <= '"') goto yy43; } else { - if (yych == ':') goto yy62; - goto yy39; + if (yych == ':') goto yy65; + goto yy43; } } -yy72: - YYDEBUG(72, *YYCURSOR); +yy75: + YYDEBUG(75, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 118 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 126 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, OP_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_OPCODE; } -#line 751 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy73: - YYDEBUG(73, *YYCURSOR); +#line 820 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy76: + YYDEBUG(76, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'N') goto yy40; - YYDEBUG(74, *YYCURSOR); + if (yych != 'N') goto yy44; + YYDEBUG(77, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'D') goto yy40; - YYDEBUG(75, *YYCURSOR); + if (yych != 'D') goto yy44; + YYDEBUG(78, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == '_') goto yy69; - goto yy40; -yy76: - YYDEBUG(76, *YYCURSOR); + if (yych == '_') goto yy72; + goto yy44; +yy79: + YYDEBUG(79, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'S') goto yy77; - if (yych != 's') goto yy40; -yy77: - YYDEBUG(77, *YYCURSOR); + if (yych == 'S') goto yy80; + if (yych != 's') goto yy44; +yy80: + YYDEBUG(80, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '\f') { - if (yych <= 0x08) goto yy40; - if (yych >= '\v') goto yy40; - } else { - if (yych <= '\r') goto yy78; - if (yych != ' ') goto yy40; + if (yybm[0+yych] & 64) { + goto yy81; } -yy78: - YYDEBUG(78, *YYCURSOR); + goto yy44; +yy81: + YYDEBUG(81, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(79, *YYCURSOR); - if (yych <= '\f') { - if (yych <= 0x08) goto yy80; - if (yych <= '\n') goto yy78; - } else { - if (yych <= '\r') goto yy78; - if (yych == ' ') goto yy78; + YYDEBUG(82, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy81; } -yy80: - YYDEBUG(80, *YYCURSOR); + YYDEBUG(83, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 94 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 102 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = 1; return T_TRUTHY; } -#line 805 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy81: - YYDEBUG(81, *YYCURSOR); +#line 866 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy84: + YYDEBUG(84, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'U') goto yy82; - if (yych != 'u') goto yy40; -yy82: - YYDEBUG(82, *YYCURSOR); + if (yych == 'U') goto yy85; + if (yych != 'u') goto yy44; +yy85: + YYDEBUG(85, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy77; - if (yych == 'e') goto yy77; - goto yy40; -yy83: - YYDEBUG(83, *YYCURSOR); + if (yych == 'E') goto yy80; + if (yych == 'e') goto yy80; + goto yy44; +yy86: + YYDEBUG(86, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'F') goto yy84; - if (yych != 'f') goto yy40; -yy84: - YYDEBUG(84, *YYCURSOR); + if (yych == 'F') goto yy87; + if (yych != 'f') goto yy44; +yy87: + YYDEBUG(87, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy40; - if (yych >= '\v') goto yy40; + if (yych <= 0x08) goto yy44; + if (yych >= '\v') goto yy44; } else { - if (yych <= '\r') goto yy85; - if (yych != ' ') goto yy40; + if (yych <= '\r') goto yy88; + if (yych != ' ') goto yy44; } -yy85: - YYDEBUG(85, *YYCURSOR); +yy88: + YYDEBUG(88, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(86, *YYCURSOR); + YYDEBUG(89, *YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy87; - if (yych <= '\n') goto yy85; + if (yych <= 0x08) goto yy90; + if (yych <= '\n') goto yy88; } else { - if (yych <= '\r') goto yy85; - if (yych == ' ') goto yy85; + if (yych <= '\r') goto yy88; + if (yych == ' ') goto yy88; } -yy87: - YYDEBUG(87, *YYCURSOR); +yy90: + YYDEBUG(90, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 100 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 108 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = 0; return T_FALSY; } -#line 858 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy88: - YYDEBUG(88, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'L') goto yy89; - if (yych != 'l') goto yy40; -yy89: - YYDEBUG(89, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'S') goto yy90; - if (yych != 's') goto yy40; -yy90: - YYDEBUG(90, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy84; - if (yych == 'e') goto yy84; - goto yy40; +#line 919 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" yy91: YYDEBUG(91, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'A') goto yy92; - if (yych != 'a') goto yy40; + if (yych == 'L') goto yy92; + if (yych != 'l') goto yy44; yy92: YYDEBUG(92, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'B') goto yy93; - if (yych != 'b') goto yy40; + if (yych == 'S') goto yy93; + if (yych != 's') goto yy44; yy93: YYDEBUG(93, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'L') goto yy94; - if (yych != 'l') goto yy40; + if (yych == 'E') goto yy87; + if (yych == 'e') goto yy87; + goto yy44; yy94: YYDEBUG(94, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy95; - if (yych != 'e') goto yy40; + if (yych == 'A') goto yy95; + if (yych != 'a') goto yy44; yy95: YYDEBUG(95, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'D') goto yy77; - if (yych == 'd') goto yy77; - goto yy40; + if (yych == 'B') goto yy96; + if (yych != 'b') goto yy44; yy96: YYDEBUG(96, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'S') goto yy97; - if (yych != 's') goto yy40; + if (yych == 'L') goto yy97; + if (yych != 'l') goto yy44; yy97: YYDEBUG(97, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'A') goto yy98; - if (yych != 'a') goto yy40; + if (yych == 'E') goto yy98; + if (yych != 'e') goto yy44; yy98: YYDEBUG(98, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'B') goto yy99; - if (yych != 'b') goto yy40; + if (yych == 'D') goto yy80; + if (yych == 'd') goto yy80; + goto yy44; yy99: YYDEBUG(99, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'L') goto yy100; - if (yych != 'l') goto yy40; + if (yych == 'S') goto yy100; + if (yych != 's') goto yy44; yy100: YYDEBUG(100, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy101; - if (yych != 'e') goto yy40; + if (yych == 'A') goto yy101; + if (yych != 'a') goto yy44; yy101: YYDEBUG(101, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'D') goto yy84; - if (yych == 'd') goto yy84; - goto yy40; + if (yych == 'B') goto yy102; + if (yych != 'b') goto yy44; yy102: YYDEBUG(102, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy103; - } - goto yy40; + if (yych == 'L') goto yy103; + if (yych != 'l') goto yy44; yy103: YYDEBUG(103, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'E') goto yy104; + if (yych != 'e') goto yy44; +yy104: + YYDEBUG(104, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'D') goto yy87; + if (yych == 'd') goto yy87; + goto yy44; +yy105: + YYDEBUG(105, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy106; + } + goto yy44; +yy106: + YYDEBUG(106, *YYCURSOR); yyaccept = 3; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(104, *YYCURSOR); + YYDEBUG(107, *YYCURSOR); if (yybm[0+yych] & 128) { - goto yy103; + goto yy106; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy105; - if (yych <= 0x08) goto yy39; + if (yych <= 0x00) goto yy108; + if (yych <= 0x08) goto yy43; } else { - if (yych != '\r') goto yy39; + if (yych != '\r') goto yy43; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy105; - if (yych <= '"') goto yy39; + if (yych <= ' ') goto yy108; + if (yych <= '"') goto yy43; } else { - if (yych == ':') goto yy62; - goto yy39; + if (yych == ':') goto yy65; + goto yy43; } } -yy105: - YYDEBUG(105, *YYCURSOR); +yy108: + YYDEBUG(108, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 112 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 120 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, ADDR_PARAM); yylval->addr = strtoul(yytext, 0, 16); return T_ADDR; } -#line 989 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy106: - YYDEBUG(106, *YYCURSOR); +#line 1050 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy109: + YYDEBUG(109, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy40; - if (yych >= '\v') goto yy40; + if (yych <= 0x08) goto yy44; + if (yych >= '\v') goto yy44; } else { - if (yych <= '\r') goto yy107; - if (yych != ' ') goto yy40; + if (yych <= '\r') goto yy110; + if (yych != ' ') goto yy44; } -yy107: - YYDEBUG(107, *YYCURSOR); +yy110: + YYDEBUG(110, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(108, *YYCURSOR); + YYDEBUG(111, *YYCURSOR); if (yych <= '\f') { - if (yych <= 0x08) goto yy109; - if (yych <= '\n') goto yy107; + if (yych <= 0x08) goto yy112; + if (yych <= '\n') goto yy110; } else { - if (yych <= '\r') goto yy107; - if (yych == ' ') goto yy107; + if (yych <= '\r') goto yy110; + if (yych == ' ') goto yy110; } -yy109: - YYDEBUG(109, *YYCURSOR); +yy112: + YYDEBUG(112, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 72 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 80 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_IF; } -#line 1023 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 1084 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy113: + YYDEBUG(113, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= ' ') { + if (yych <= '\f') { + if (yych <= 0x08) goto yy44; + if (yych >= '\v') goto yy44; + } else { + if (yych <= '\r') goto yy114; + if (yych <= 0x1F) goto yy44; + } + } else { + if (yych <= '.') { + if (yych <= ',') goto yy44; + if (yych <= '-') goto yy116; + goto yy117; + } else { + if (yych <= '/') goto yy44; + if (yych <= '9') goto yy117; + goto yy44; + } + } +yy114: + YYDEBUG(114, *YYCURSOR); + ++YYCURSOR; + YYFILL(2); + yych = *YYCURSOR; + YYDEBUG(115, *YYCURSOR); + if (yych <= ' ') { + if (yych <= '\f') { + if (yych <= 0x08) goto yy66; + if (yych <= '\n') goto yy114; + goto yy66; + } else { + if (yych <= '\r') goto yy114; + if (yych <= 0x1F) goto yy66; + goto yy114; + } + } else { + if (yych <= '.') { + if (yych <= ',') goto yy66; + if (yych <= '-') goto yy120; + goto yy121; + } else { + if (yych <= '/') goto yy66; + if (yych <= '9') goto yy121; + goto yy66; + } + } +yy116: + YYDEBUG(116, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '.') goto yy117; + if (yych <= '/') goto yy44; + if (yych >= ':') goto yy44; +yy117: + YYDEBUG(117, *YYCURSOR); + yyaccept = 4; + YYMARKER = ++YYCURSOR; + YYFILL(3); + yych = *YYCURSOR; + YYDEBUG(118, *YYCURSOR); + if (yych <= ' ') { + if (yych <= '\n') { + if (yych <= 0x00) goto yy119; + if (yych <= 0x08) goto yy43; + } else { + if (yych == '\r') goto yy119; + if (yych <= 0x1F) goto yy43; + } + } else { + if (yych <= '.') { + if (yych == '#') goto yy119; + if (yych <= '-') goto yy43; + goto yy117; + } else { + if (yych <= '/') goto yy43; + if (yych <= '9') goto yy117; + if (yych <= ':') goto yy65; + goto yy43; + } + } +yy119: + YYDEBUG(119, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 73 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" + { + char *text = yytext + 2; + while (*++text < '0'); + yylval->num = atoi(text); + return T_REQ_ID; +} +#line 1179 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy120: + YYDEBUG(120, *YYCURSOR); + yych = *++YYCURSOR; + if (yych == '.') goto yy121; + if (yych <= '/') goto yy66; + if (yych >= ':') goto yy66; +yy121: + YYDEBUG(121, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(122, *YYCURSOR); + if (yych == '.') goto yy121; + if (yych <= '/') goto yy119; + if (yych <= '9') goto yy121; + goto yy119; } /* *********************************** */ -yyc_RAW: +yyc_PRE_RAW: { static const unsigned char yybm[] = { - 0, 64, 64, 64, 64, 64, 64, 64, - 64, 224, 128, 64, 64, 224, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 224, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 160, 48, 0, 0, 160, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 160, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 64, 0, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }; - YYDEBUG(110, *YYCURSOR); + YYDEBUG(123, *YYCURSOR); YYFILL(2); yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy127; + } + if (yych <= '\r') { + if (yych <= 0x08) { + if (yych <= 0x00) goto yy130; + goto yy132; + } else { + if (yych <= '\t') goto yy125; + if (yych <= '\f') goto yy132; + } + } else { + if (yych <= ' ') { + if (yych <= 0x1F) goto yy132; + } else { + if (yych == '-') goto yy131; + goto yy132; + } + } +yy125: + YYDEBUG(125, *YYCURSOR); + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '\f') { + if (yych <= 0x00) goto yy142; + if (yych <= 0x08) goto yy126; + if (yych <= '\n') goto yy142; + } else { + if (yych <= '\r') goto yy142; + if (yych == ' ') goto yy142; + } +yy126: + YYDEBUG(126, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 169 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" + { + YYSETCONDITION(RAW); + + YYCURSOR = LEX(text); + goto restart; +} +#line 1277 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy127: + YYDEBUG(127, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(128, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy141; + } + if (yych <= 0x00) goto yy140; + if (yych == '\n') goto yy127; +yy129: + YYDEBUG(129, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" + { + return 0; +} +#line 1296 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy130: + YYDEBUG(130, *YYCURSOR); + yych = *++YYCURSOR; + goto yy126; +yy131: + YYDEBUG(131, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy133; + goto yy126; +yy132: + YYDEBUG(132, *YYCURSOR); + yych = *++YYCURSOR; + goto yy126; +yy133: + YYDEBUG(133, *YYCURSOR); + ++YYCURSOR; + YYFILL(2); + yych = *YYCURSOR; + YYDEBUG(134, *YYCURSOR); if (yybm[0+yych] & 32) { - goto yy112; + goto yy133; } - if (yych <= 0x00) goto yy117; - if (yych == '\n') goto yy115; - goto yy118; -yy112: - YYDEBUG(112, *YYCURSOR); + if (yych <= '.') { + if (yych <= ',') goto yy135; + if (yych <= '-') goto yy136; + goto yy137; + } else { + if (yych <= '/') goto yy135; + if (yych <= '9') goto yy137; + } +yy135: + YYDEBUG(135, *YYCURSOR); + YYCURSOR = YYMARKER; + goto yy126; +yy136: + YYDEBUG(136, *YYCURSOR); + yych = *++YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy137; + } + goto yy135; +yy137: + YYDEBUG(137, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(113, *YYCURSOR); + YYDEBUG(138, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy137; + } + YYDEBUG(139, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 73 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" + { + char *text = yytext + 2; + while (*++text < '0'); + yylval->num = atoi(text); + return T_REQ_ID; +} +#line 1357 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy140: + YYDEBUG(140, *YYCURSOR); + yych = *++YYCURSOR; + goto yy129; +yy141: + YYDEBUG(141, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; +yy142: + YYDEBUG(142, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy141; + } + if (yych <= 0x00) goto yy140; + if (yych == '\n') goto yy127; + YYDEBUG(143, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" + { + /* ignore whitespace */ + + goto restart; +} +#line 1382 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" + } +/* *********************************** */ +yyc_RAW: + { + static const unsigned char yybm[] = { + 0, 128, 128, 128, 128, 128, 128, 128, + 128, 160, 64, 128, 128, 160, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 160, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + }; + YYDEBUG(144, *YYCURSOR); + YYFILL(1); + yych = *YYCURSOR; if (yybm[0+yych] & 32) { - goto yy112; + goto yy146; } - if (yych <= 0x00) goto yy114; - if (yych == '\n') goto yy120; - goto yy118; -yy114: - YYDEBUG(114, *YYCURSOR); + if (yych <= 0x00) goto yy152; + if (yych == '\n') goto yy149; + goto yy153; +yy146: + YYDEBUG(146, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(147, *YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy146; + } + if (yych <= 0x00) goto yy152; + if (yych == '\n') goto yy149; + goto yy153; +yy148: + YYDEBUG(148, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 140 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { phpdbg_init_param(yylval, STR_PARAM); yylval->str = zend_strndup(yytext, yyleng); yylval->len = yyleng; return T_INPUT; } -#line 1093 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy115: - YYDEBUG(115, *YYCURSOR); +#line 1452 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy149: + YYDEBUG(149, *YYCURSOR); ++YYCURSOR; - if (yybm[0+(yych = *YYCURSOR)] & 128) { - goto yy120; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(150, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy149; } -yy116: - YYDEBUG(116, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x00) goto yy152; + if (yych == '\t') goto yy155; + } else { + if (yych <= '\r') goto yy155; + if (yych == ' ') goto yy155; + } +yy151: + YYDEBUG(151, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 69 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 1107 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy117: - YYDEBUG(117, *YYCURSOR); +#line 1476 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" +yy152: + YYDEBUG(152, *YYCURSOR); yych = *++YYCURSOR; - goto yy116; -yy118: - YYDEBUG(118, *YYCURSOR); + goto yy151; +yy153: + YYDEBUG(153, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(119, *YYCURSOR); - if (yybm[0+yych] & 64) { - goto yy118; + YYDEBUG(154, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy153; } - goto yy114; -yy120: - YYDEBUG(120, *YYCURSOR); + goto yy148; +yy155: + YYDEBUG(155, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(121, *YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy120; + YYDEBUG(156, *YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy149; } - YYDEBUG(122, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x00) goto yy152; + if (yych == '\t') goto yy155; + } else { + if (yych <= '\r') goto yy155; + if (yych == ' ') goto yy155; + } + YYDEBUG(157, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 147 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" { /* ignore whitespace */ goto restart; } -#line 1139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 1515 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.c" } } -#line 168 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" +#line 183 "/Users/Bob/php-src-5.6/sapi/phpdbg/phpdbg_lexer.l" } diff --git a/sapi/phpdbg/phpdbg_lexer.h b/sapi/phpdbg/phpdbg_lexer.h index d0e259f453..ab51e7daa8 100644 --- a/sapi/phpdbg/phpdbg_lexer.h +++ b/sapi/phpdbg/phpdbg_lexer.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ diff --git a/sapi/phpdbg/phpdbg_lexer.l b/sapi/phpdbg/phpdbg_lexer.l index 7b3ce38c47..0c27fc22ac 100644 --- a/sapi/phpdbg/phpdbg_lexer.l +++ b/sapi/phpdbg/phpdbg_lexer.l @@ -21,8 +21,9 @@ #define YYFILL(n) #define NORMAL 0 -#define RAW 1 -#define INITIAL 2 +#define PRE_RAW 1 +#define RAW 2 +#define INITIAL 3 ZEND_EXTERN_MODULE_GLOBALS(phpdbg); @@ -65,10 +66,17 @@ INPUT [^\n\000]+ <!*> := yyleng = (size_t) YYCURSOR - (size_t) yytext; -<*>[\n\000] { +<*>{WS}?[\n\000] { return 0; } +<PRE_RAW, NORMAL>[-][r]{WS}?{DIGITS} { + char *text = yytext + 2; + while (*++text < '0'); + yylval->num = atoi(text); + return T_REQ_ID; +} + <NORMAL>{T_IF}{WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); @@ -143,21 +151,28 @@ INPUT [^\n\000]+ } <INITIAL>{T_EVAL}{WS} { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_EVAL; } <INITIAL>{T_SHELL}{WS} { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_SHELL; } <INITIAL>({T_RUN}|{T_RUN_SHORT}){WS} { - YYSETCONDITION(RAW); + YYSETCONDITION(PRE_RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_RUN; } +<PRE_RAW>. { + YYSETCONDITION(RAW); + + YYCURSOR = LEX(text); + goto restart; +} + <INITIAL>. { YYSETCONDITION(NORMAL); diff --git a/sapi/phpdbg/phpdbg_list.c b/sapi/phpdbg/phpdbg_list.c index eac17ba6a7..de03a3651e 100644 --- a/sapi/phpdbg/phpdbg_list.c +++ b/sapi/phpdbg/phpdbg_list.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -34,35 +34,37 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_LIST_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[13]) +#define PHPDBG_LIST_COMMAND_D(f, h, a, m, l, s, flags) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[13], flags) const phpdbg_command_t phpdbg_list_commands[] = { - PHPDBG_LIST_COMMAND_D(lines, "lists the specified lines", 'l', list_lines, NULL, "l"), - PHPDBG_LIST_COMMAND_D(class, "lists the specified class", 'c', list_class, NULL, "s"), - PHPDBG_LIST_COMMAND_D(method, "lists the specified method", 'm', list_method, NULL, "m"), - PHPDBG_LIST_COMMAND_D(func, "lists the specified function", 'f', list_func, NULL, "s"), + PHPDBG_LIST_COMMAND_D(lines, "lists the specified lines", 'l', list_lines, NULL, "l", PHPDBG_ASYNC_SAFE), + PHPDBG_LIST_COMMAND_D(class, "lists the specified class", 'c', list_class, NULL, "s", PHPDBG_ASYNC_SAFE), + PHPDBG_LIST_COMMAND_D(method, "lists the specified method", 'm', list_method, NULL, "m", PHPDBG_ASYNC_SAFE), + PHPDBG_LIST_COMMAND_D(func, "lists the specified function", 'f', list_func, NULL, "s", PHPDBG_ASYNC_SAFE), PHPDBG_END_COMMAND }; PHPDBG_LIST(lines) /* {{{ */ { if (!PHPDBG_G(exec) && !zend_is_executing(TSRMLS_C)) { - phpdbg_error("Not executing, and execution context not set"); + phpdbg_error("inactive", "type=\"execution\"", "Not executing, and execution context not set"); return SUCCESS; } switch (param->type) { - case NUMERIC_PARAM: - phpdbg_list_file(phpdbg_current_file(TSRMLS_C), - (param->num < 0 ? 1 - param->num : param->num), - (param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C), - 0 TSRMLS_CC); - break; - - case FILE_PARAM: - phpdbg_list_file(param->file.name, param->file.line, 0, 0 TSRMLS_CC); - break; + case NUMERIC_PARAM: { + const char *char_file = phpdbg_current_file(TSRMLS_C); + zend_string *file = zend_string_init(char_file, strlen(char_file), 0); + phpdbg_list_file(file, param->num < 0 ? 1 - param->num : param->num, (param->num < 0 ? param->num : 0) + zend_get_executed_lineno(TSRMLS_C), 0 TSRMLS_CC); + efree(file); + } break; + + case FILE_PARAM: { + zend_string *file = zend_string_init(param->file.name, strlen(param->file.name), 0); + phpdbg_list_file(file, param->file.line, 0, 0 TSRMLS_CC); + efree(file); + } break; phpdbg_default_switch_case(); } @@ -79,21 +81,21 @@ PHPDBG_LIST(func) /* {{{ */ PHPDBG_LIST(method) /* {{{ */ { - zend_class_entry **ce; + zend_class_entry *ce; - if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { + if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { zend_function *function; char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); - if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**) &function) == SUCCESS) { + if ((function = zend_hash_str_find_ptr(&ce->function_table, lcname, strlen(lcname)))) { phpdbg_list_function(function TSRMLS_CC); } else { - phpdbg_error("Could not find %s::%s", param->method.class, param->method.name); + phpdbg_error("list", "type=\"notfound\" method=\"%s::%s\"", "Could not find %s::%s", param->method.class, param->method.name); } efree(lcname); } else { - phpdbg_error("Could not find the class %s", param->method.class); + phpdbg_error("list", "type=\"notfound\" class=\"%s\"", "Could not find the class %s", param->method.class); } return SUCCESS; @@ -101,82 +103,69 @@ PHPDBG_LIST(method) /* {{{ */ PHPDBG_LIST(class) /* {{{ */ { - zend_class_entry **ce; - - if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { - if ((*ce)->type == ZEND_USER_CLASS) { - if ((*ce)->info.user.filename) { - phpdbg_list_file( - (*ce)->info.user.filename, - (*ce)->info.user.line_end - (*ce)->info.user.line_start + 1, - (*ce)->info.user.line_start, 0 TSRMLS_CC - ); + zend_class_entry *ce; + + if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { + if (ce->type == ZEND_USER_CLASS) { + if (ce->info.user.filename) { + phpdbg_list_file(ce->info.user.filename, ce->info.user.line_end - ce->info.user.line_start + 1, ce->info.user.line_start, 0 TSRMLS_CC); } else { - phpdbg_error("The source of the requested class (%s) cannot be found", (*ce)->name); + phpdbg_error("list", "type=\"nosource\" class=\"%s\"", "The source of the requested class (%s) cannot be found", ce->name); } } else { - phpdbg_error("The class requested (%s) is not user defined", (*ce)->name); + phpdbg_error("list", "type=\"internalclass\" class=\"%s\"", "The class requested (%s) is not user defined", ce->name); } } else { - phpdbg_error("The requested class (%s) could not be found", param->str); + phpdbg_error("list", "type=\"notfound\" class=\"%s\"", "The requested class (%s) could not be found", param->str); } return SUCCESS; } /* }}} */ -void phpdbg_list_file(const char *filename, long count, long offset, int highlight TSRMLS_DC) /* {{{ */ +void phpdbg_list_file(zend_string *filename, uint count, int offset, uint highlight TSRMLS_DC) /* {{{ */ { - struct stat st; - char *opened = NULL; - char buffer[8096] = {0,}; - long line = 0; - - php_stream *stream = NULL; - - if (VCWD_STAT(filename, &st) == FAILURE) { - phpdbg_error("Failed to stat file %s", filename); - return; - } + uint line, lastline; + phpdbg_file_source *data; - stream = php_stream_open_wrapper(filename, "rb", USE_PATH, &opened); - - if (!stream) { - phpdbg_error("Failed to open file %s to list", filename); + if (!(data = zend_hash_find_ptr(&PHPDBG_G(file_sources), filename))) { + phpdbg_error("list", "type=\"unknownfile\"", "Could not find information about included file..."); return; } - + if (offset < 0) { count += offset; offset = 0; } - - while (php_stream_gets(stream, buffer, sizeof(buffer)) != NULL) { - long linelen = strlen(buffer); - - ++line; - - if (offset <= line) { - if (!highlight) { - phpdbg_write("%05ld: %s", line, buffer); - } else { - if (highlight != line) { - phpdbg_write(" %05ld: %s", line, buffer); - } else { - phpdbg_write(">%05ld: %s", line, buffer); - } - } - if (buffer[linelen - 1] != '\n') { - phpdbg_write("\n"); + lastline = offset + count; + + if (lastline > data->lines) { + lastline = data->lines; + } + + phpdbg_xml("<list %r file=\"%s\">", filename); + + for (line = offset; line < lastline;) { + uint linestart = data->line[line++]; + uint linelen = data->line[line] - linestart; + char *buffer = data->buf + linestart; + + if (!highlight) { + phpdbg_write("line", "line=\"%u\" code=\"%.*s\"", " %05u: %.*s", line, linelen, buffer); + } else { + if (highlight != line) { + phpdbg_write("line", "line=\"%u\" code=\"%.*s\"", " %05u: %.*s", line, linelen, buffer); + } else { + phpdbg_write("line", "line=\"%u\" code=\"%.*s\" current=\"current\"", ">%05u: %.*s", line, linelen, buffer); } } - if (count > 0 && count + offset - 1 < line) { - break; + if (*(buffer + linelen - 1) != '\n' || !linelen) { + phpdbg_out("\n"); } } - - php_stream_close(stream); + + phpdbg_xml("</list>"); } /* }}} */ void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */ @@ -184,14 +173,13 @@ void phpdbg_list_function(const zend_function *fbc TSRMLS_DC) /* {{{ */ const zend_op_array *ops; if (fbc->type != ZEND_USER_FUNCTION) { - phpdbg_error("The function requested (%s) is not user defined", fbc->common.function_name); + phpdbg_error("list", "type=\"internalfunction\" function=\"%s\"", "The function requested (%s) is not user defined", fbc->common.function_name); return; } - ops = (zend_op_array*)fbc; + ops = (zend_op_array *) fbc; - phpdbg_list_file(ops->filename, - ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC); + phpdbg_list_file(ops->filename, ops->line_end - ops->line_start + 1, ops->line_start, 0 TSRMLS_CC); } /* }}} */ void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ */ @@ -209,11 +197,11 @@ void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ * func_table = &EG(scope)->function_table; } else { - phpdbg_error("No active class"); + phpdbg_error("inactive", "type=\"noclasses\"", "No active class"); return; } } else if (!EG(function_table)) { - phpdbg_error("No function table loaded"); + phpdbg_error("inactive", "type=\"function_table\"", "No function table loaded"); return; } else { func_table = EG(function_table); @@ -222,12 +210,87 @@ void phpdbg_list_function_byname(const char *str, size_t len TSRMLS_DC) /* {{{ * /* use lowercase names, case insensitive */ func_name = zend_str_tolower_dup(func_name, func_name_len); - if (zend_hash_find(func_table, func_name, func_name_len+1, (void**)&fbc) == SUCCESS) { - phpdbg_list_function(fbc TSRMLS_CC); - } else { - phpdbg_error("Function %s not found", func_name); - } + phpdbg_try_access { + if ((fbc = zend_hash_str_find_ptr(func_table, func_name, func_name_len))) { + phpdbg_list_function(fbc TSRMLS_CC); + } else { + phpdbg_error("list", "type=\"nofunction\" function=\"%s\"", "Function %s not found", func_name); + } + } phpdbg_catch_access { + phpdbg_error("signalsegv", "function=\"%s\"", "Could not list function %s, invalid data source", func_name); + } phpdbg_end_try_access(); efree(func_name); } /* }}} */ +zend_op_array *phpdbg_compile_file(zend_file_handle *file, int type TSRMLS_DC) { + phpdbg_file_source data, *dataptr; + zend_file_handle fake = {{0}}; + zend_op_array *ret; + char *filename = (char *)(file->opened_path ? file->opened_path : file->filename); + uint line; + char *bufptr, *endptr; + + zend_stream_fixup(file, &data.buf, &data.len TSRMLS_CC); + + data.filename = filename; + data.line[0] = 0; + + if (file->handle.stream.mmap.old_closer) { + /* do not unmap */ + file->handle.stream.closer = file->handle.stream.mmap.old_closer; + } + +#if HAVE_MMAP + if (file->handle.stream.mmap.map) { + data.map = file->handle.stream.mmap.map; + } +#endif + + fake.type = ZEND_HANDLE_MAPPED; + fake.handle.stream.mmap.buf = data.buf; + fake.handle.stream.mmap.len = data.len; + fake.free_filename = 0; + fake.opened_path = file->opened_path; + fake.filename = filename; + fake.opened_path = file->opened_path; + + *(dataptr = emalloc(sizeof(phpdbg_file_source) + sizeof(uint) * data.len)) = data; + + for (line = 0, bufptr = data.buf - 1, endptr = data.buf + data.len; ++bufptr < endptr;) { + if (*bufptr == '\n') { + dataptr->line[++line] = (uint)(bufptr - data.buf) + 1; + } + } + dataptr->lines = ++line; + dataptr->line[line] = endptr - data.buf; + dataptr = erealloc(dataptr, sizeof(phpdbg_file_source) + sizeof(uint) * line); + + zend_hash_str_add_ptr(&PHPDBG_G(file_sources), filename, strlen(filename), dataptr); + + ret = PHPDBG_G(compile_file)(&fake, type TSRMLS_CC); + + fake.opened_path = NULL; + zend_file_handle_dtor(&fake TSRMLS_CC); + + return ret; +} + +void phpdbg_free_file_source(phpdbg_file_source *data) { +#if HAVE_MMAP + if (data->map) { + munmap(data->map, data->len + ZEND_MMAP_AHEAD); + } else +#endif + if (data->buf) { + efree(data->buf); + } + + efree(data); +} + +void phpdbg_init_list(TSRMLS_D) { + PHPDBG_G(compile_file) = zend_compile_file; + zend_hash_init(&PHPDBG_G(file_sources), 1, NULL, (dtor_func_t) phpdbg_free_file_source, 0); + zend_compile_file = phpdbg_compile_file; +} diff --git a/sapi/phpdbg/phpdbg_list.h b/sapi/phpdbg/phpdbg_list.h index 84f6b63195..43a2d474d5 100644 --- a/sapi/phpdbg/phpdbg_list.h +++ b/sapi/phpdbg/phpdbg_list.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -33,9 +33,22 @@ PHPDBG_LIST(method); PHPDBG_LIST(func); void phpdbg_list_function_byname(const char *, size_t TSRMLS_DC); -void phpdbg_list_function(const zend_function* TSRMLS_DC); -void phpdbg_list_file(const char*, long, long, int TSRMLS_DC); +void phpdbg_list_function(const zend_function * TSRMLS_DC); +void phpdbg_list_file(zend_string *, uint, int, uint TSRMLS_DC); extern const phpdbg_command_t phpdbg_list_commands[]; +void phpdbg_init_list(TSRMLS_D); + +typedef struct { + char *filename; + char *buf; + size_t len; +#if HAVE_MMAP + void *map; +#endif + uint lines; + uint line[1]; +} phpdbg_file_source; + #endif /* PHPDBG_LIST_H */ diff --git a/sapi/phpdbg/phpdbg_opcode.c b/sapi/phpdbg/phpdbg_opcode.c index f33b1378bf..99f43344a4 100644 --- a/sapi/phpdbg/phpdbg_opcode.c +++ b/sapi/phpdbg/phpdbg_opcode.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -26,7 +26,7 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -static inline uint32_t phpdbg_decode_literal(zend_op_array *ops, zend_literal *literal TSRMLS_DC) /* {{{ */ +static inline uint32_t phpdbg_decode_literal(zend_op_array *ops, zval *literal TSRMLS_DC) /* {{{ */ { int iter = 0; @@ -46,26 +46,25 @@ static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, uint32_t switch (type &~ EXT_TYPE_UNUSED) { case IS_CV: - asprintf(&decode, "$%s", ops->vars[op->var].name); + asprintf(&decode, "$%s", ops->vars[EX_VAR_TO_NUM(op->var)]->val); break; case IS_VAR: case IS_TMP_VAR: { zend_ulong id = 0, *pid = NULL; if (vars != NULL) { - if (zend_hash_index_find(vars, (zend_ulong) ops->vars - op->var, (void**) &pid) != SUCCESS) { + if ((pid = zend_hash_index_find_ptr(vars, (zend_ulong) ops->vars - op->var))) { + id = *pid; + } else { id = zend_hash_num_elements(vars); - zend_hash_index_update( - vars, (zend_ulong) ops->vars - op->var, - (void**) &id, - sizeof(zend_ulong), NULL); - } else id = *pid; + zend_hash_index_update_mem(vars, (zend_ulong) ops->vars - op->var, &id, sizeof(zend_ulong)); + } } - asprintf(&decode, "@%lu", id); + asprintf(&decode, "@%llu", id); } break; case IS_CONST: - asprintf(&decode, "C%u", phpdbg_decode_literal(ops, op->literal TSRMLS_CC)); + asprintf(&decode, "C%u", phpdbg_decode_literal(ops, op->zv TSRMLS_CC)); break; case IS_UNUSED: @@ -92,8 +91,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRM case ZEND_JMPZNZ: decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); - asprintf( - &decode[2], "J%u or J%lu", op->op2.opline_num, op->extended_value); + asprintf(&decode[2], "J%u or J%llu", op->op2.opline_num, op->extended_value); goto result; case ZEND_JMPZ: @@ -105,8 +103,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRM case ZEND_JMP_SET: #endif decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type, vars TSRMLS_CC); - asprintf( - &decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes); + asprintf(&decode[2], "J%ld", op->op2.jmp_addr - ops->opcodes); goto result; case ZEND_RECV_INIT: @@ -118,8 +115,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars TSRM result: decode[3] = phpdbg_decode_op(ops, &op->result, op->result_type, vars TSRMLS_CC); format: - asprintf( - &decode[0], + asprintf(&decode[0], "%-20s %-20s %-20s", decode[1] ? decode[1] : "", decode[2] ? decode[2] : "", @@ -145,26 +141,26 @@ void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, ze (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) || (PHPDBG_G(oplog)))) { - zend_op *opline = execute_data->opline; - char *decode = phpdbg_decode_opline(execute_data->op_array, opline, vars TSRMLS_CC); + zend_op *opline = (zend_op *) execute_data->opline; + char *decode = phpdbg_decode_opline(&execute_data->func->op_array, opline, vars TSRMLS_CC); if (ignore_flags || (!(PHPDBG_G(flags) & PHPDBG_IS_QUIET) || (PHPDBG_G(flags) & PHPDBG_IS_STEPPING))) { /* output line info */ - phpdbg_notice("L%-5u %16p %-30s %s %s", + phpdbg_notice("opline", "line=\"%u\" opline=\"%p\" opcode=\"%s\" op=\"%s\" file=\"%s\"", "L%-5u %16p %-30s %s %s", opline->lineno, opline, phpdbg_decode_opcode(opline->opcode), decode, - execute_data->op_array->filename ? execute_data->op_array->filename : "unknown"); + execute_data->func->op_array.filename ? execute_data->func->op_array.filename->val : "unknown"); } if (!ignore_flags && PHPDBG_G(oplog)) { - phpdbg_log_ex(PHPDBG_G(oplog), "L%-5u %16p %-30s %s %s", + phpdbg_log_ex(fileno(PHPDBG_G(oplog)), "L%-5u %16p %-30s %s %s", opline->lineno, opline, phpdbg_decode_opcode(opline->opcode), decode, - execute_data->op_array->filename ? execute_data->op_array->filename : "unknown"); + execute_data->func->op_array.filename ? execute_data->func->op_array.filename->val : "unknown"); } if (decode) { @@ -180,179 +176,6 @@ void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags const char *phpdbg_decode_opcode(zend_uchar opcode) /* {{{ */ { -#if ZEND_EXTENSION_API_NO <= PHP_5_5_API_NO -#define CASE(s) case s: return #s - switch (opcode) { - CASE(ZEND_NOP); - CASE(ZEND_ADD); - CASE(ZEND_SUB); - CASE(ZEND_MUL); - CASE(ZEND_DIV); - CASE(ZEND_MOD); - CASE(ZEND_SL); - CASE(ZEND_SR); - CASE(ZEND_CONCAT); - CASE(ZEND_BW_OR); - CASE(ZEND_BW_AND); - CASE(ZEND_BW_XOR); - CASE(ZEND_BW_NOT); - CASE(ZEND_BOOL_NOT); - CASE(ZEND_BOOL_XOR); - CASE(ZEND_IS_IDENTICAL); - CASE(ZEND_IS_NOT_IDENTICAL); - CASE(ZEND_IS_EQUAL); - CASE(ZEND_IS_NOT_EQUAL); - CASE(ZEND_IS_SMALLER); - CASE(ZEND_IS_SMALLER_OR_EQUAL); - CASE(ZEND_CAST); - CASE(ZEND_QM_ASSIGN); - CASE(ZEND_ASSIGN_ADD); - CASE(ZEND_ASSIGN_SUB); - CASE(ZEND_ASSIGN_MUL); - CASE(ZEND_ASSIGN_DIV); - CASE(ZEND_ASSIGN_MOD); - CASE(ZEND_ASSIGN_SL); - CASE(ZEND_ASSIGN_SR); - CASE(ZEND_ASSIGN_CONCAT); - CASE(ZEND_ASSIGN_BW_OR); - CASE(ZEND_ASSIGN_BW_AND); - CASE(ZEND_ASSIGN_BW_XOR); - CASE(ZEND_PRE_INC); - CASE(ZEND_PRE_DEC); - CASE(ZEND_POST_INC); - CASE(ZEND_POST_DEC); - CASE(ZEND_ASSIGN); - CASE(ZEND_ASSIGN_REF); - CASE(ZEND_ECHO); - CASE(ZEND_PRINT); - CASE(ZEND_JMP); - CASE(ZEND_JMPZ); - CASE(ZEND_JMPNZ); - CASE(ZEND_JMPZNZ); - CASE(ZEND_JMPZ_EX); - CASE(ZEND_JMPNZ_EX); - CASE(ZEND_CASE); - CASE(ZEND_BRK); - CASE(ZEND_CONT); - CASE(ZEND_BOOL); - CASE(ZEND_INIT_STRING); - CASE(ZEND_ADD_CHAR); - CASE(ZEND_ADD_STRING); - CASE(ZEND_ADD_VAR); - CASE(ZEND_BEGIN_SILENCE); - CASE(ZEND_END_SILENCE); - CASE(ZEND_INIT_FCALL_BY_NAME); - CASE(ZEND_DO_FCALL); - CASE(ZEND_DO_FCALL_BY_NAME); - CASE(ZEND_RETURN); - CASE(ZEND_RECV); - CASE(ZEND_RECV_INIT); - CASE(ZEND_SEND_VAL); - CASE(ZEND_SEND_VAR); - CASE(ZEND_SEND_REF); - CASE(ZEND_NEW); - CASE(ZEND_INIT_NS_FCALL_BY_NAME); - CASE(ZEND_FREE); - CASE(ZEND_INIT_ARRAY); - CASE(ZEND_ADD_ARRAY_ELEMENT); - CASE(ZEND_INCLUDE_OR_EVAL); - CASE(ZEND_UNSET_VAR); - CASE(ZEND_UNSET_DIM); - CASE(ZEND_UNSET_OBJ); - CASE(ZEND_FE_RESET); - CASE(ZEND_FE_FETCH); - CASE(ZEND_EXIT); - CASE(ZEND_FETCH_R); - CASE(ZEND_FETCH_DIM_R); - CASE(ZEND_FETCH_OBJ_R); - CASE(ZEND_FETCH_W); - CASE(ZEND_FETCH_DIM_W); - CASE(ZEND_FETCH_OBJ_W); - CASE(ZEND_FETCH_RW); - CASE(ZEND_FETCH_DIM_RW); - CASE(ZEND_FETCH_OBJ_RW); - CASE(ZEND_FETCH_IS); - CASE(ZEND_FETCH_DIM_IS); - CASE(ZEND_FETCH_OBJ_IS); - CASE(ZEND_FETCH_FUNC_ARG); - CASE(ZEND_FETCH_DIM_FUNC_ARG); - CASE(ZEND_FETCH_OBJ_FUNC_ARG); - CASE(ZEND_FETCH_UNSET); - CASE(ZEND_FETCH_DIM_UNSET); - CASE(ZEND_FETCH_OBJ_UNSET); - CASE(ZEND_FETCH_LIST); - CASE(ZEND_FETCH_CONSTANT); - CASE(ZEND_GOTO); - CASE(ZEND_EXT_STMT); - CASE(ZEND_EXT_FCALL_BEGIN); - CASE(ZEND_EXT_FCALL_END); - CASE(ZEND_EXT_NOP); - CASE(ZEND_TICKS); - CASE(ZEND_SEND_VAR_NO_REF); - CASE(ZEND_CATCH); - CASE(ZEND_THROW); - CASE(ZEND_FETCH_CLASS); - CASE(ZEND_CLONE); - CASE(ZEND_RETURN_BY_REF); - CASE(ZEND_INIT_METHOD_CALL); - CASE(ZEND_INIT_STATIC_METHOD_CALL); - CASE(ZEND_ISSET_ISEMPTY_VAR); - CASE(ZEND_ISSET_ISEMPTY_DIM_OBJ); - CASE(ZEND_PRE_INC_OBJ); - CASE(ZEND_PRE_DEC_OBJ); - CASE(ZEND_POST_INC_OBJ); - CASE(ZEND_POST_DEC_OBJ); - CASE(ZEND_ASSIGN_OBJ); - CASE(ZEND_INSTANCEOF); - CASE(ZEND_DECLARE_CLASS); - CASE(ZEND_DECLARE_INHERITED_CLASS); - CASE(ZEND_DECLARE_FUNCTION); - CASE(ZEND_RAISE_ABSTRACT_ERROR); - CASE(ZEND_DECLARE_CONST); - CASE(ZEND_ADD_INTERFACE); - CASE(ZEND_DECLARE_INHERITED_CLASS_DELAYED); - CASE(ZEND_VERIFY_ABSTRACT_CLASS); - CASE(ZEND_ASSIGN_DIM); - CASE(ZEND_ISSET_ISEMPTY_PROP_OBJ); - CASE(ZEND_HANDLE_EXCEPTION); - CASE(ZEND_USER_OPCODE); -#ifdef ZEND_JMP_SET - CASE(ZEND_JMP_SET); -#endif - CASE(ZEND_DECLARE_LAMBDA_FUNCTION); -#ifdef ZEND_ADD_TRAIT - CASE(ZEND_ADD_TRAIT); -#endif -#ifdef ZEND_BIND_TRAITS - CASE(ZEND_BIND_TRAITS); -#endif -#ifdef ZEND_SEPARATE - CASE(ZEND_SEPARATE); -#endif -#ifdef ZEND_DISCARD_EXCEPTION - CASE(ZEND_DISCARD_EXCEPTION); -#endif -#ifdef ZEND_YIELD - CASE(ZEND_YIELD); -#endif -#ifdef ZEND_GENERATOR_RETURN - CASE(ZEND_GENERATOR_RETURN); -#endif -#ifdef ZEND_FAST_CALL - CASE(ZEND_FAST_CALL); -#endif -#ifdef ZEND_FAST_RET - CASE(ZEND_FAST_RET); -#endif -#ifdef ZEND_RECV_VARIADIC - CASE(ZEND_RECV_VARIADIC); -#endif - CASE(ZEND_OP_DATA); - default: - return "UNKNOWN"; - } -#else const char *ret = zend_get_opcode_name(opcode); return ret?ret:"UNKNOWN"; -#endif } /* }}} */ diff --git a/sapi/phpdbg/phpdbg_opcode.h b/sapi/phpdbg/phpdbg_opcode.h index 647237119c..144442981d 100644 --- a/sapi/phpdbg/phpdbg_opcode.h +++ b/sapi/phpdbg/phpdbg_opcode.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ diff --git a/sapi/phpdbg/phpdbg_out.c b/sapi/phpdbg/phpdbg_out.c new file mode 100644 index 0000000000..4d70381533 --- /dev/null +++ b/sapi/phpdbg/phpdbg_out.c @@ -0,0 +1,1306 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena <felipe@php.net> | + | Authors: Joe Watkins <joe.watkins@live.co.uk> | + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "php.h" +#include "spprintf.h" +#include "phpdbg.h" +#include "phpdbg_io.h" +#include "phpdbg_eol.h" +#include "ext/standard/html.h" + +#ifdef _WIN32 +# include "win32/time.h" +#endif + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +/* copied from php-src/main/snprintf.c and slightly modified */ +/* + * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions + * + * XXX: this is a magic number; do not decrease it + * Emax = 1023 + * NDIG = 320 + * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1; + */ +#define NUM_BUF_SIZE 2048 + +/* + * Descriptor for buffer area + */ +struct buf_area { + char *buf_end; + char *nextb; /* pointer to next byte to read/write */ +}; + +typedef struct buf_area buffy; + +/* + * The INS_CHAR macro inserts a character in the buffer and writes + * the buffer back to disk if necessary + * It uses the char pointers sp and bep: + * sp points to the next available character in the buffer + * bep points to the end-of-buffer+1 + * While using this macro, note that the nextb pointer is NOT updated. + * + * NOTE: Evaluation of the c argument should not have any side-effects + */ +#define INS_CHAR(c, sp, bep, cc) \ + { \ + if (sp < bep) \ + { \ + *sp++ = c; \ + } \ + cc++; \ + } + +#define NUM( c ) ( c - '0' ) + +#define STR_TO_DEC( str, num ) \ + num = NUM( *str++ ) ; \ + while ( isdigit((int)*str ) ) \ + { \ + num *= 10 ; \ + num += NUM( *str++ ) ; \ + } + +/* + * This macro does zero padding so that the precision + * requirement is satisfied. The padding is done by + * adding '0's to the left of the string that is going + * to be printed. + */ +#define FIX_PRECISION( adjust, precision, s, s_len ) \ + if ( adjust ) \ + while ( s_len < precision ) \ + { \ + *--s = '0' ; \ + s_len++ ; \ + } + +/* + * Macro that does padding. The padding is done by printing + * the character ch. + */ +#define PAD( width, len, ch ) do \ + { \ + INS_CHAR( ch, sp, bep, cc ) ; \ + width-- ; \ + } \ + while ( width > len ) + +/* + * Prefix the character ch to the string str + * Increase length + * Set the has_prefix flag + */ +#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES + + +#ifdef HAVE_LOCALE_H +#include <locale.h> +#define LCONV_DECIMAL_POINT (*lconv->decimal_point) +#else +#define LCONV_DECIMAL_POINT '.' +#endif +#define NUL '\0' +#define S_NULL "(null)" +#define S_NULL_LEN 6 +#define FLOAT_DIGITS 6 + +/* + * Do format conversion placing the output in buffer + */ +static int format_converter(register buffy *odp, const char *fmt, zend_bool escape_xml, va_list ap TSRMLS_DC) { + char *sp; + char *bep; + int cc = 0; + int i; + + char *s = NULL, *free_s = NULL; + size_t s_len; + zend_bool free_zcopy; + zval *zvp, zcopy; + + int min_width = 0; + int precision = 0; + enum { + LEFT, RIGHT + } adjust; + char pad_char; + char prefix_char; + + double fp_num; + wide_int i_num = (wide_int) 0; + u_wide_int ui_num; + + char num_buf[NUM_BUF_SIZE]; + char char_buf[2]; /* for printing %% and %<unknown> */ + +#ifdef HAVE_LOCALE_H + struct lconv *lconv = NULL; +#endif + + /* + * Flag variables + */ + length_modifier_e modifier; + boolean_e alternate_form; + boolean_e print_sign; + boolean_e print_blank; + boolean_e adjust_precision; + boolean_e adjust_width; + bool_int is_negative; + + sp = odp->nextb; + bep = odp->buf_end; + + while (*fmt) { + if (*fmt != '%') { + INS_CHAR(*fmt, sp, bep, cc); + } else { + /* + * Default variable settings + */ + adjust = RIGHT; + alternate_form = print_sign = print_blank = NO; + pad_char = ' '; + prefix_char = NUL; + free_zcopy = 0; + + fmt++; + + /* + * Try to avoid checking for flags, width or precision + */ + if (isascii((int)*fmt) && !islower((int)*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ + for (;; fmt++) { + if (*fmt == '-') + adjust = LEFT; + else if (*fmt == '+') + print_sign = YES; + else if (*fmt == '#') + alternate_form = YES; + else if (*fmt == ' ') + print_blank = YES; + else if (*fmt == '0') + pad_char = '0'; + else + break; + } + + /* + * Check if a width was specified + */ + if (isdigit((int)*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = YES; + } else if (*fmt == '*') { + min_width = va_arg(ap, int); + fmt++; + adjust_width = YES; + if (min_width < 0) { + adjust = LEFT; + min_width = -min_width; + } + } else + adjust_width = NO; + + /* + * Check if a precision was specified + */ + if (*fmt == '.') { + adjust_precision = YES; + fmt++; + if (isdigit((int)*fmt)) { + STR_TO_DEC(fmt, precision); + } else if (*fmt == '*') { + precision = va_arg(ap, int); + fmt++; + if (precision < 0) + precision = 0; + } else + precision = 0; + + if (precision > FORMAT_CONV_MAX_PRECISION && *fmt != 's' && *fmt != 'v' && *fmt != 'b') { + precision = FORMAT_CONV_MAX_PRECISION; + } + } else + adjust_precision = NO; + } else + adjust_precision = adjust_width = NO; + + /* + * Modifier check + */ + switch (*fmt) { + case 'L': + fmt++; + modifier = LM_LONG_DOUBLE; + break; + case 'I': + fmt++; +#if SIZEOF_LONG_LONG + if (*fmt == '6' && *(fmt+1) == '4') { + fmt += 2; + modifier = LM_LONG_LONG; + } else +#endif + if (*fmt == '3' && *(fmt+1) == '2') { + fmt += 2; + modifier = LM_LONG; + } else { +#ifdef _WIN64 + modifier = LM_LONG_LONG; +#else + modifier = LM_LONG; +#endif + } + break; + case 'l': + fmt++; +#if SIZEOF_LONG_LONG + if (*fmt == 'l') { + fmt++; + modifier = LM_LONG_LONG; + } else +#endif + modifier = LM_LONG; + break; + case 'z': + fmt++; + modifier = LM_SIZE_T; + break; + case 'j': + fmt++; +#if SIZEOF_INTMAX_T + modifier = LM_INTMAX_T; +#else + modifier = LM_SIZE_T; +#endif + break; + case 't': + fmt++; +#if SIZEOF_PTRDIFF_T + modifier = LM_PTRDIFF_T; +#else + modifier = LM_SIZE_T; +#endif + break; + case 'h': + fmt++; + if (*fmt == 'h') { + fmt++; + } + /* these are promoted to int, so no break */ + default: + modifier = LM_STD; + break; + } + + /* + * Argument extraction and printing. + * First we determine the argument type. + * Then, we convert the argument to a string. + * On exit from the switch, s points to the string that + * must be printed, s_len has the length of the string + * The precision requirements, if any, are reflected in s_len. + * + * NOTE: pad_char may be set to '0' because of the 0 flag. + * It is reset to ' ' by non-numeric formats + */ + switch (*fmt) { + case 'Z': + zvp = (zval *) va_arg(ap, zval *); + free_zcopy = zend_make_printable_zval(zvp, &zcopy TSRMLS_CC); + if (free_zcopy) { + zvp = &zcopy; + } + s_len = Z_STRLEN_P(zvp); + s = Z_STRVAL_P(zvp); + if (adjust_precision && precision < s_len) { + s_len = precision; + } + break; + case 'u': + switch(modifier) { + default: + i_num = (wide_int) va_arg(ap, unsigned int); + break; + case LM_LONG_DOUBLE: + goto fmt_error; + case LM_LONG: + i_num = (wide_int) va_arg(ap, unsigned long int); + break; + case LM_SIZE_T: + i_num = (wide_int) va_arg(ap, size_t); + break; +#if SIZEOF_LONG_LONG + case LM_LONG_LONG: + i_num = (wide_int) va_arg(ap, u_wide_int); + break; +#endif +#if SIZEOF_INTMAX_T + case LM_INTMAX_T: + i_num = (wide_int) va_arg(ap, uintmax_t); + break; +#endif +#if SIZEOF_PTRDIFF_T + case LM_PTRDIFF_T: + i_num = (wide_int) va_arg(ap, ptrdiff_t); + break; +#endif + } + /* + * The rest also applies to other integer formats, so fall + * into that case. + */ + case 'd': + case 'i': + /* + * Get the arg if we haven't already. + */ + if ((*fmt) != 'u') { + switch(modifier) { + default: + i_num = (wide_int) va_arg(ap, int); + break; + case LM_LONG_DOUBLE: + goto fmt_error; + case LM_LONG: + i_num = (wide_int) va_arg(ap, long int); + break; + case LM_SIZE_T: +#if SIZEOF_SSIZE_T + i_num = (wide_int) va_arg(ap, ssize_t); +#else + i_num = (wide_int) va_arg(ap, size_t); +#endif + break; +#if SIZEOF_LONG_LONG + case LM_LONG_LONG: + i_num = (wide_int) va_arg(ap, wide_int); + break; +#endif +#if SIZEOF_INTMAX_T + case LM_INTMAX_T: + i_num = (wide_int) va_arg(ap, intmax_t); + break; +#endif +#if SIZEOF_PTRDIFF_T + case LM_PTRDIFF_T: + i_num = (wide_int) va_arg(ap, ptrdiff_t); + break; +#endif + } + } + s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + + if (*fmt != 'u') { + if (is_negative) { + prefix_char = '-'; + } else if (print_sign) { + prefix_char = '+'; + } else if (print_blank) { + prefix_char = ' '; + } + } + break; + + + case 'o': + switch(modifier) { + default: + ui_num = (u_wide_int) va_arg(ap, unsigned int); + break; + case LM_LONG_DOUBLE: + goto fmt_error; + case LM_LONG: + ui_num = (u_wide_int) va_arg(ap, unsigned long int); + break; + case LM_SIZE_T: + ui_num = (u_wide_int) va_arg(ap, size_t); + break; +#if SIZEOF_LONG_LONG + case LM_LONG_LONG: + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + break; +#endif +#if SIZEOF_INTMAX_T + case LM_INTMAX_T: + ui_num = (u_wide_int) va_arg(ap, uintmax_t); + break; +#endif +#if SIZEOF_PTRDIFF_T + case LM_PTRDIFF_T: + ui_num = (u_wide_int) va_arg(ap, ptrdiff_t); + break; +#endif + } + s = ap_php_conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && *s != '0') { + *--s = '0'; + s_len++; + } + break; + + + case 'x': + case 'X': + switch(modifier) { + default: + ui_num = (u_wide_int) va_arg(ap, unsigned int); + break; + case LM_LONG_DOUBLE: + goto fmt_error; + case LM_LONG: + ui_num = (u_wide_int) va_arg(ap, unsigned long int); + break; + case LM_SIZE_T: + ui_num = (u_wide_int) va_arg(ap, size_t); + break; +#if SIZEOF_LONG_LONG + case LM_LONG_LONG: + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + break; +#endif +#if SIZEOF_INTMAX_T + case LM_INTMAX_T: + ui_num = (u_wide_int) va_arg(ap, uintmax_t); + break; +#endif +#if SIZEOF_PTRDIFF_T + case LM_PTRDIFF_T: + ui_num = (u_wide_int) va_arg(ap, ptrdiff_t); + break; +#endif + } + s = ap_php_conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && i_num != 0) { + *--s = *fmt; /* 'x' or 'X' */ + *--s = '0'; + s_len += 2; + } + break; + + + case 's': + case 'v': + s = va_arg(ap, char *); + if (s != NULL) { + if (adjust_precision) { + s_len = precision; + } else { + s_len = strlen(s); + } + + if (escape_xml) { + /* added: support for xml escaping */ + + int old_slen = s_len, i = 0; + char *old_s = s, *s_ptr; + free_s = s_ptr = s = emalloc(old_slen * 6 + 1); + do { + if (old_s[i] == '&' || old_s[i] == '"' || old_s[i] == '<') { + *s_ptr++ = '&'; + switch (old_s[i]) { + case '"': + s_len += 5; + *s_ptr++ = 'q'; + *s_ptr++ = 'u'; + *s_ptr++ = 'o'; + *s_ptr++ = 't'; + break; + case '<': + s_len += 3; + *s_ptr++ = 'l'; + *s_ptr++ = 't'; + break; + case '&': + s_len += 4; + *s_ptr++ = 'a'; + *s_ptr++ = 'm'; + *s_ptr++ = 'p'; + break; + } + *s_ptr++ = ';'; + } else { + *s_ptr++ = old_s[i]; + } + } while (i++ < old_slen); + } + } else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + break; + + + case 'b': + if (escape_xml) { + s = PHPDBG_G(err_buf).xml; + } else { + s = PHPDBG_G(err_buf).msg; + } + + if (s != NULL) { + if (escape_xml) { + s_len = PHPDBG_G(err_buf).xmllen; + } else { + s_len = PHPDBG_G(err_buf).msglen; + } + + if (adjust_precision && precision != s_len) { + s_len = precision; + } + } else { + s = ""; + s_len = 0; + } + pad_char = ' '; + break; + + + case 'r': + if (PHPDBG_G(req_id)) { + s_len = spprintf(&s, 0, "req=\"%lu\"", PHPDBG_G(req_id)); + free_s = s; + } else { + s = ""; + s_len = 0; + } + break; + + + case 'f': + case 'F': + case 'e': + case 'E': + + switch(modifier) { + case LM_LONG_DOUBLE: + fp_num = (double) va_arg(ap, long double); + break; + case LM_STD: + fp_num = va_arg(ap, double); + break; + default: + goto fmt_error; + } + + if (zend_isnan(fp_num)) { + s = "NAN"; + s_len = 3; + } else if (zend_isinf(fp_num)) { + s = "INF"; + s_len = 3; + } else { +#ifdef HAVE_LOCALE_H + if (!lconv) { + lconv = localeconv(); + } +#endif + s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form, + (adjust_precision == NO) ? FLOAT_DIGITS : precision, + (*fmt == 'f')?LCONV_DECIMAL_POINT:'.', + &is_negative, &num_buf[1], &s_len); + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + } + break; + + + case 'g': + case 'k': + case 'G': + case 'H': + switch(modifier) { + case LM_LONG_DOUBLE: + fp_num = (double) va_arg(ap, long double); + break; + case LM_STD: + fp_num = va_arg(ap, double); + break; + default: + goto fmt_error; + } + + if (zend_isnan(fp_num)) { + s = "NAN"; + s_len = 3; + break; + } else if (zend_isinf(fp_num)) { + if (fp_num > 0) { + s = "INF"; + s_len = 3; + } else { + s = "-INF"; + s_len = 4; + } + break; + } + + if (adjust_precision == NO) { + precision = FLOAT_DIGITS; + } else if (precision == 0) { + precision = 1; + } + /* + * * We use &num_buf[ 1 ], so that we have room for the sign + */ +#ifdef HAVE_LOCALE_H + if (!lconv) { + lconv = localeconv(); + } +#endif + s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]); + if (*s == '-') { + prefix_char = *s++; + } else if (print_sign) { + prefix_char = '+'; + } else if (print_blank) { + prefix_char = ' '; + } + + s_len = strlen(s); + + if (alternate_form && (strchr(s, '.')) == NULL) { + s[s_len++] = '.'; + } + break; + + + case 'c': + char_buf[0] = (char) (va_arg(ap, int)); + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case '%': + char_buf[0] = '%'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case 'n': + *(va_arg(ap, int *)) = cc; + goto skip_output; + + /* + * Always extract the argument as a "char *" pointer. We + * should be using "void *" but there are still machines + * that don't understand it. + * If the pointer size is equal to the size of an unsigned + * integer we convert the pointer to a hex number, otherwise + * we print "%p" to indicate that we don't handle "%p". + */ + case 'p': + if (sizeof(char *) <= sizeof(u_wide_int)) { + ui_num = (u_wide_int)((size_t) va_arg(ap, char *)); + s = ap_php_conv_p2(ui_num, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + if (ui_num != 0) { + *--s = 'x'; + *--s = '0'; + s_len += 2; + } + } else { + s = "%p"; + s_len = 2; + } + pad_char = ' '; + break; + + + case NUL: + /* + * The last character of the format string was %. + * We ignore it. + */ + continue; + + +fmt_error: + php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt); + /* + * The default case is for unrecognized %'s. + * We print %<char> to help the user identify what + * option is not understood. + * This is also useful in case the user wants to pass + * the output of format_converter to another function + * that understands some other %<char> (like syslog). + * Note that we can't point s inside fmt because the + * unknown <char> could be preceded by width etc. + */ + default: + char_buf[0] = '%'; + char_buf[1] = *fmt; + s = char_buf; + s_len = 2; + pad_char = ' '; + break; + } + + if (prefix_char != NUL) { + *--s = prefix_char; + s_len++; + } + if (adjust_width && adjust == RIGHT && min_width > s_len) { + if (pad_char == '0' && prefix_char != NUL) { + INS_CHAR(*s, sp, bep, cc) + s++; + s_len--; + min_width--; + } + PAD(min_width, s_len, pad_char); + } + /* + * Print the string s. + */ + for (i = s_len; i != 0; i--) { + INS_CHAR(*s, sp, bep, cc); + s++; + } + + if (adjust_width && adjust == LEFT && min_width > s_len) + PAD(min_width, s_len, pad_char); + if (free_zcopy) { + zval_dtor(&zcopy); + } + } +skip_output: + if (free_s) { + efree(free_s); + free_s = NULL; + } + + fmt++; + } + odp->nextb = sp; + return (cc); +} + +static void strx_printv(int *ccp, char *buf, size_t len, const char *format, zend_bool escape_xml, va_list ap TSRMLS_DC) { + buffy od; + int cc; + + /* + * First initialize the descriptor + * Notice that if no length is given, we initialize buf_end to the + * highest possible address. + */ + if (len == 0) { + od.buf_end = (char *) ~0; + od.nextb = (char *) ~0; + } else { + od.buf_end = &buf[len-1]; + od.nextb = buf; + } + + /* + * Do the conversion + */ + cc = format_converter(&od, format, escape_xml, ap TSRMLS_CC); + if (len != 0 && od.nextb <= od.buf_end) { + *(od.nextb) = '\0'; + } + if (ccp) { + *ccp = cc; + } +} + +static int phpdbg_xml_vsnprintf(char *buf, size_t len, const char *format, zend_bool escape_xml, va_list ap TSRMLS_DC) { + int cc; + + strx_printv(&cc, buf, len, format, escape_xml, ap TSRMLS_CC); + return (cc); +} + +PHPDBG_API int phpdbg_xml_vasprintf(char **buf, const char *format, zend_bool escape_xml, va_list ap TSRMLS_DC) { + va_list ap2; + int cc; + + va_copy(ap2, ap); + cc = phpdbg_xml_vsnprintf(NULL, 0, format, escape_xml, ap2 TSRMLS_CC); + va_end(ap2); + + *buf = NULL; + + if (cc >= 0) { + if ((*buf = emalloc(++cc)) != NULL) { + if ((cc = phpdbg_xml_vsnprintf(*buf, cc, format, escape_xml, ap TSRMLS_CC)) < 0) { + efree(*buf); + *buf = NULL; + } + } + } + + return cc; +} +/* copy end */ + +PHPDBG_API int _phpdbg_xml_asprintf(char **buf TSRMLS_DC, const char *format, zend_bool escape_xml, ...) { + int ret; + va_list va; + + va_start(va, escape_xml); + ret = phpdbg_xml_vasprintf(buf, format, escape_xml, va TSRMLS_CC); + va_end(va); + + return ret; +} + +PHPDBG_API int _phpdbg_asprintf(char **buf TSRMLS_DC, const char *format, ...) { + int ret; + va_list va; + + va_start(va, format); + ret = phpdbg_xml_vasprintf(buf, format, 0, va TSRMLS_CC); + va_end(va); + + return ret; +} + +static int phpdbg_encode_xml(char **buf, char *msg, int msglen, int from, char *to) { + int i; + int tolen = to ? strlen(to) : 5; + char *tmp = *buf = emalloc(msglen * tolen); + for (i = 0; i++ < msglen; msg++) { + if (*msg == '&') { + memcpy(tmp, ZEND_STRL("&")); + tmp += sizeof("&") - 1; + } else if (*msg == '<') { + memcpy(tmp, ZEND_STRL("<")); + tmp += sizeof("<") - 1; + } else if (((int) *msg) == from) { + memcpy(tmp, to, tolen); + tmp += tolen; + } else { + *tmp++ = *msg; + } + } + + { + int len = tmp - *buf; + *buf = erealloc(*buf, len + 1); + return len; + } +} + +static void phpdbg_encode_ctrl_chars(char **buf, int *buflen) { + char *tmp, *tmpptr; + int len; + int i; + + tmp = tmpptr = emalloc(*buflen * 5); + + for (i = 0; i < *buflen; i++) { + if ((*buf)[i] < 0x20) { + *tmpptr++ = '&'; + *tmpptr++ = '#'; + if ((unsigned int) ((*buf)[i]) > 9) { + *tmpptr++ = ((*buf)[i] / 10) + '0'; + } + *tmpptr++ = ((*buf)[i] % 10) + '0'; + *tmpptr++ = ';'; + } else { + *tmpptr++ = (*buf)[i]; + } + } + + len = tmpptr - tmp; + + efree(*buf); + *buf = erealloc(tmp, len + 1); + *buflen = len; +} + +static int phpdbg_process_print(int fd, int type, const char *tag, const char *msg, int msglen, const char *xml, int xmllen TSRMLS_DC) { + char *msgout = NULL, *buf; + int msgoutlen, xmloutlen, buflen; + const char *severity; + + if ((PHPDBG_G(flags) & PHPDBG_WRITE_XML) && PHPDBG_G(in_script_xml) && PHPDBG_G(in_script_xml) != type) { + phpdbg_mixed_write(fd, ZEND_STRL("</stream>") TSRMLS_CC); + PHPDBG_G(in_script_xml) = 0; + } + + switch (type) { + case P_ERROR: + severity = "error"; + if (!PHPDBG_G(last_was_newline)) { + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + phpdbg_mixed_write(fd, ZEND_STRL("<phpdbg>\n" "</phpdbg>") TSRMLS_CC); + } else { + phpdbg_mixed_write(fd, ZEND_STRL("\n") TSRMLS_CC); + } + PHPDBG_G(last_was_newline) = 1; + } + if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { + msgoutlen = phpdbg_asprintf(&msgout, "\033[%sm[%.*s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, msglen, msg); + } else { + msgoutlen = phpdbg_asprintf(&msgout, "[%.*s]\n", msglen, msg); + } + break; + + case P_NOTICE: + severity = "notice"; + if (!PHPDBG_G(last_was_newline)) { + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + phpdbg_mixed_write(fd, ZEND_STRL("<phpdbg>\n" "</phpdbg>") TSRMLS_CC); + } else { + phpdbg_mixed_write(fd, ZEND_STRL("\n") TSRMLS_CC); + } + PHPDBG_G(last_was_newline) = 1; + } + if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { + msgoutlen = phpdbg_asprintf(&msgout, "\033[%sm[%.*s]\033[0m\n", PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, msglen, msg); + } else { + msgoutlen = phpdbg_asprintf(&msgout, "[%.*s]\n", msglen, msg); + } + break; + + case P_WRITELN: + severity = "normal"; + if (msg) { + msgoutlen = phpdbg_asprintf(&msgout, "%.*s\n", msglen, msg); + } else { + msgoutlen = 1; + msgout = estrdup("\n"); + } + PHPDBG_G(last_was_newline) = 1; + break; + + case P_WRITE: + severity = "normal"; + if (msg) { + msgout = estrndup(msg, msglen); + msgoutlen = msglen; + PHPDBG_G(last_was_newline) = msg[msglen - 1] == '\n'; + } else { + msgoutlen = 0; + msgout = estrdup(""); + } + break; + + case P_STDOUT: + case P_STDERR: + if (msg) { + PHPDBG_G(last_was_newline) = msg[msglen - 1] == '\n'; + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + zend_string *encoded; + + if (PHPDBG_G(in_script_xml) != type) { + char *stream_buf; + int stream_buflen = phpdbg_asprintf(&stream_buf, "<stream type=\"%s\">", type == P_STDERR ? "stderr" : "stdout"); + phpdbg_mixed_write(fd, stream_buf, stream_buflen TSRMLS_CC); + efree(stream_buf); + PHPDBG_G(in_script_xml) = type; + } + encoded = php_escape_html_entities((unsigned char *) msg, msglen, 0, ENT_NOQUOTES, PG(internal_encoding) && PG(internal_encoding)[0] ? PG(internal_encoding) : (SG(default_charset) ? SG(default_charset) : "UTF-8") TSRMLS_CC); + buflen = encoded->len; + memcpy(buf = emalloc(buflen + 1), encoded->val, buflen); + phpdbg_encode_ctrl_chars(&buf, &buflen); + phpdbg_mixed_write(fd, buf, buflen TSRMLS_CC); + efree(buf); + } else { + phpdbg_mixed_write(fd, msg, msglen TSRMLS_CC); + } + return msglen; + } + break; + + /* no formatting on logging output */ + case P_LOG: + severity = "log"; + if (msg) { + struct timeval tp; + if (gettimeofday(&tp, NULL) == SUCCESS) { + msgoutlen = phpdbg_asprintf(&msgout, "[%ld %.8F]: %.*s\n", tp.tv_sec, tp.tv_usec / 1000000., msglen, msg); + } else { + msgoutlen = FAILURE; + } + } + break; + } + + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + char *xmlout; + + if (PHPDBG_G(req_id)) { + char *xmlbuf = NULL; + xmllen = phpdbg_asprintf(&xmlbuf, "req=\"%lu\" %.*s", PHPDBG_G(req_id), xmllen, xml); + xml = xmlbuf; + } + if (msgout) { + buflen = phpdbg_encode_xml(&buf, msgout, msgoutlen, '"', """); + xmloutlen = phpdbg_asprintf(&xmlout, "<%s severity=\"%s\" %.*s msgout=\"%.*s\" />", tag, severity, xmllen, xml, buflen, buf); + + efree(buf); + } else { + xmloutlen = phpdbg_asprintf(&xmlout, "<%s severity=\"%s\" %.*s msgout=\"\" />", tag, severity, xmllen, xml); + } + + phpdbg_encode_ctrl_chars(&xmlout, &xmloutlen); + phpdbg_eol_convert(&xmlout, &xmloutlen TSRMLS_CC); + phpdbg_mixed_write(fd, xmlout, xmloutlen TSRMLS_CC); + efree(xmlout); + } else if (msgout) { + phpdbg_eol_convert(&msgout, &msgoutlen TSRMLS_CC); + phpdbg_mixed_write(fd, msgout, msgoutlen TSRMLS_CC); + } + + if (PHPDBG_G(req_id) && (PHPDBG_G(flags) & PHPDBG_WRITE_XML)) { + efree((char *) xml); + } + + if (msgout) { + efree(msgout); + } + + return msgout ? msgoutlen : xmloutlen; +} /* }}} */ + +PHPDBG_API int phpdbg_vprint(int type TSRMLS_DC, int fd, const char *tag, const char *xmlfmt, const char *strfmt, va_list args) { + char *msg = NULL, *xml = NULL; + int msglen = 0, xmllen = 0; + int len; + va_list argcpy; + + if (strfmt != NULL && strlen(strfmt) > 0L) { + va_copy(argcpy, args); + msglen = phpdbg_xml_vasprintf(&msg, strfmt, 0, argcpy TSRMLS_CC); + va_end(argcpy); + } + + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + if (xmlfmt != NULL && strlen(xmlfmt) > 0L) { + va_copy(argcpy, args); + xmllen = phpdbg_xml_vasprintf(&xml, xmlfmt, 1, argcpy TSRMLS_CC); + va_end(argcpy); + } else { + xml = estrdup(""); + } + } + + if (PHPDBG_G(err_buf).active && type != P_STDOUT && type != P_STDERR) { + PHPDBG_G(err_buf).type = type; + PHPDBG_G(err_buf).fd = fd; + PHPDBG_G(err_buf).tag = estrdup(tag); + PHPDBG_G(err_buf).msg = msg; + PHPDBG_G(err_buf).msglen = msglen; + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + PHPDBG_G(err_buf).xml = xml; + PHPDBG_G(err_buf).xmllen = xmllen; + } + + return msglen; + } + + len = phpdbg_process_print(fd, type, tag, msg, msglen, xml, xmllen TSRMLS_CC); + + if (msg) { + efree(msg); + } + + if (xml) { + efree(xml); + } + + return len; +} + +PHPDBG_API void phpdbg_free_err_buf(TSRMLS_D) { + if (PHPDBG_G(err_buf).type == 0) { + return; + } + + PHPDBG_G(err_buf).type = 0; + + efree(PHPDBG_G(err_buf).tag); + efree(PHPDBG_G(err_buf).msg); + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + efree(PHPDBG_G(err_buf).xml); + } +} + +PHPDBG_API void phpdbg_activate_err_buf(zend_bool active TSRMLS_DC) { + PHPDBG_G(err_buf).active = active; +} + +PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const char *strfmt TSRMLS_DC, ...) { + int len; + va_list args; + int errbuf_active = PHPDBG_G(err_buf).active; + + PHPDBG_G(err_buf).active = 0; + +#ifdef ZTS + va_start(args, tsrm_ls); +#else + va_start(args, strfmt); +#endif + len = phpdbg_vprint(PHPDBG_G(err_buf).type TSRMLS_CC, PHPDBG_G(err_buf).fd, tag ? tag : PHPDBG_G(err_buf).tag, xmlfmt, strfmt, args); + va_end(args); + + PHPDBG_G(err_buf).active = errbuf_active; + phpdbg_free_err_buf(TSRMLS_C); + + return len; +} + +PHPDBG_API int phpdbg_print(int type TSRMLS_DC, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) { + va_list args; + int len; + + va_start(args, strfmt); + len = phpdbg_vprint(type TSRMLS_CC, fd, tag, xmlfmt, strfmt, args); + va_end(args); + + return len; +} + +PHPDBG_API int phpdbg_xml_internal(int fd TSRMLS_DC, const char *fmt, ...) { + int len = 0; + + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + va_list args; + char *buffer; + int buflen; + + va_start(args, fmt); + buflen = phpdbg_xml_vasprintf(&buffer, fmt, 1, args TSRMLS_CC); + va_end(args); + + phpdbg_encode_ctrl_chars(&buffer, &buflen); + + if (PHPDBG_G(in_script_xml)) { + phpdbg_mixed_write(fd, ZEND_STRL("</stream>") TSRMLS_CC); + PHPDBG_G(in_script_xml) = 0; + } + + len = phpdbg_mixed_write(fd, buffer, buflen TSRMLS_CC); + efree(buffer); + } + + return len; +} + +PHPDBG_API int phpdbg_log_internal(int fd TSRMLS_DC, const char *fmt, ...) { + va_list args; + char *buffer; + int buflen; + int len = 0; + + va_start(args, fmt); + buflen = phpdbg_xml_vasprintf(&buffer, fmt, 0, args TSRMLS_CC); + va_end(args); + + len = phpdbg_mixed_write(fd, buffer, buflen TSRMLS_CC); + efree(buffer); + + return len; +} + +PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...) { + va_list args; + char *buffer; + int buflen; + int len = 0; + + va_start(args, fmt); + buflen = phpdbg_xml_vasprintf(&buffer, fmt, 0, args TSRMLS_CC); + va_end(args); + + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + char *msg; + int msglen; + + msglen = phpdbg_encode_xml(&msg, buffer, buflen, 256, NULL); + phpdbg_encode_ctrl_chars(&msg, &msglen); + phpdbg_eol_convert(&msg, &msglen TSRMLS_CC); + + if (PHPDBG_G(in_script_xml)) { + phpdbg_mixed_write(fd, ZEND_STRL("</stream>") TSRMLS_CC); + PHPDBG_G(in_script_xml) = 0; + } + + phpdbg_mixed_write(fd, ZEND_STRL("<phpdbg>") TSRMLS_CC); + len = phpdbg_mixed_write(fd, msg, msglen TSRMLS_CC); + phpdbg_mixed_write(fd, ZEND_STRL("</phpdbg>") TSRMLS_CC); + } else { + phpdbg_eol_convert(&buffer, &buflen TSRMLS_CC); + len = phpdbg_mixed_write(fd, buffer, buflen TSRMLS_CC); + } + + return len; +} + + +PHPDBG_API int phpdbg_rlog_internal(int fd TSRMLS_DC, const char *fmt, ...) { /* {{{ */ + int rc = 0; + + va_list args; + struct timeval tp; + + va_start(args, fmt); + if (gettimeofday(&tp, NULL) == SUCCESS) { + char friendly[100]; + char *format = NULL, *buffer = NULL, *outbuf = NULL; + const time_t tt = tp.tv_sec; + +#ifdef PHP_WIN32 + strftime(friendly, 100, "%a %b %d %H.%%04d %Y", localtime(&tt)); +#else + strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tt)); +#endif + phpdbg_asprintf(&buffer, friendly, tp.tv_usec/1000); + phpdbg_asprintf(&format, "[%s]: %s\n", buffer, fmt); + rc = phpdbg_xml_vasprintf(&outbuf, format, 0, args TSRMLS_CC); + + if (outbuf) { + rc = phpdbg_mixed_write(fd, outbuf, rc TSRMLS_CC); + efree(outbuf); + } + + efree(format); + efree(buffer); + } + va_end(args); + + return rc; +} /* }}} */ diff --git a/sapi/phpdbg/phpdbg_out.h b/sapi/phpdbg/phpdbg_out.h new file mode 100644 index 0000000000..ea25b04279 --- /dev/null +++ b/sapi/phpdbg/phpdbg_out.h @@ -0,0 +1,93 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena <felipe@php.net> | + | Authors: Joe Watkins <joe.watkins@live.co.uk> | + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_OUT_H +#define PHPDBG_OUT_H + +/** + * Error/notice/formatting helpers + */ +enum { + P_ERROR = 1, + P_NOTICE, + P_WRITELN, + P_WRITE, + P_STDOUT, + P_STDERR, + P_LOG +}; + +#ifdef ZTS +PHPDBG_API int phpdbg_print(int severity TSRMLS_DC, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 6, 7); +PHPDBG_API int phpdbg_xml_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); +PHPDBG_API int phpdbg_log_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); +PHPDBG_API int phpdbg_out_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); +PHPDBG_API int phpdbg_rlog_internal(int fd TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); +#else +PHPDBG_API int phpdbg_print(int severity, int fd, const char *tag, const char *xmlfmt, const char *strfmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 5, 6); +PHPDBG_API int phpdbg_xml_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); +PHPDBG_API int phpdbg_log_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); +PHPDBG_API int phpdbg_out_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); +PHPDBG_API int phpdbg_rlog_internal(int fd, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3); +#endif + + +#define phpdbg_error(tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_notice(tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_writeln(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_write(tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_script(type, fmt, ...) phpdbg_print(type TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT].fd, NULL, NULL, fmt, ##__VA_ARGS__) +#define phpdbg_log(fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#define phpdbg_xml(fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#define phpdbg_out(fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) + +#define phpdbg_error_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_notice_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_writeln_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_write_ex(out, tag, xmlfmt, strfmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, tag, xmlfmt, strfmt, ##__VA_ARGS__) +#define phpdbg_script_ex(out, type, fmt, ...) phpdbg_print(type TSRMLS_CC, out, NULL, NULL, fmt, ##__VA_ARGS__) +#define phpdbg_log_ex(out, fmt, ...) phpdbg_log_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#define phpdbg_xml_ex(out, fmt, ...) phpdbg_xml_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#define phpdbg_out_ex(out, fmt, ...) phpdbg_out_internal(PHPDBG_G(io)[PHPDBG_STDOUT].fd TSRMLS_CC, fmt, ##__VA_ARGS__) + +#define phpdbg_rlog(fd, fmt, ...) phpdbg_rlog_internal(fd TSRMLS_CC, fmt, ##__VA_ARGS__) + +#define phpdbg_xml_asprintf(buf, ...) _phpdbg_xml_asprintf(buf TSRMLS_CC, ##__VA_ARGS__) +PHPDBG_API int _phpdbg_xml_asprintf(char **buf TSRMLS_DC, const char *format, zend_bool escape_xml, ...); + +#define phpdbg_asprintf(buf, ...) _phpdbg_asprintf(buf TSRMLS_CC, ##__VA_ARGS__) +PHPDBG_API int _phpdbg_asprintf(char **buf TSRMLS_DC, const char *format, ...); + + +#if PHPDBG_DEBUG +# define phpdbg_debug(fmt, ...) phpdbg_log_ex(PHPDBG_G(io)[PHPDBG_STDERR].fd TSRMLS_CC, fmt, ##__VA_ARGS__) +#else +# define phpdbg_debug(fmt, ...) +#endif + +PHPDBG_API void phpdbg_free_err_buf(TSRMLS_D); +PHPDBG_API void phpdbg_activate_err_buf(zend_bool active TSRMLS_DC); +PHPDBG_API int phpdbg_output_err_buf(const char *tag, const char *xmlfmt, const char *strfmt TSRMLS_DC, ...); + + +/* {{{ For separation */ +#define SEPARATE "------------------------------------------------" /* }}} */ + +#endif /* PHPDBG_OUT_H */ diff --git a/sapi/phpdbg/phpdbg_parser.c b/sapi/phpdbg/phpdbg_parser.c index e34c2f48ff..8bb9103a98 100644 --- a/sapi/phpdbg/phpdbg_parser.c +++ b/sapi/phpdbg/phpdbg_parser.c @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 2.6.2. */ +/* A Bison parser, made by GNU Bison 2.6. */ /* Bison implementation for Yacc-like parsers in C @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.6.2" +#define YYBISON_VERSION "2.6" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -69,8 +69,9 @@ #define yynerrs phpdbg_nerrs /* Copy the first part of user declarations. */ + /* Line 336 of yacc.c */ -#line 1 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 1 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" /* @@ -97,8 +98,9 @@ static int yyerror(void ***tsrm_ls, const char *msg); ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + /* Line 336 of yacc.c */ -#line 102 "sapi/phpdbg/phpdbg_parser.c" +#line 104 "sapi/phpdbg/phpdbg_parser.c" # ifndef YY_NULL # if defined __cplusplus && 201103L <= __cplusplus @@ -128,8 +130,9 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); extern int phpdbg_debug; #endif /* "%code requires" blocks. */ + /* Line 350 of yacc.c */ -#line 31 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 31 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" #include "phpdbg.h" #ifndef YY_TYPEDEF_YY_SCANNER_T @@ -138,8 +141,9 @@ typedef void* yyscan_t; #endif + /* Line 350 of yacc.c */ -#line 143 "sapi/phpdbg/phpdbg_parser.c" +#line 147 "sapi/phpdbg/phpdbg_parser.c" /* Tokens. */ #ifndef YYTOKENTYPE @@ -164,7 +168,8 @@ typedef void* yyscan_t; T_OPCODE = 272, T_ID = 273, T_INPUT = 274, - T_UNEXPECTED = 275 + T_UNEXPECTED = 275, + T_REQ_ID = 276 }; #endif /* Tokens. */ @@ -186,6 +191,7 @@ typedef void* yyscan_t; #define T_ID 273 #define T_INPUT 274 #define T_UNEXPECTED 275 +#define T_REQ_ID 276 @@ -215,8 +221,9 @@ int phpdbg_parse (); /* Copy the second part of user declarations. */ + /* Line 353 of yacc.c */ -#line 220 "sapi/phpdbg/phpdbg_parser.c" +#line 227 "sapi/phpdbg/phpdbg_parser.c" #ifdef short # undef short @@ -434,22 +441,22 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 25 +#define YYFINAL 26 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 42 +#define YYLAST 48 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 21 +#define YYNTOKENS 22 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 5 +#define YYNNTS 6 /* YYNRULES -- Number of rules. */ -#define YYNRULES 25 +#define YYNRULES 28 /* YYNRULES -- Number of states. */ -#define YYNSTATES 38 +#define YYNSTATES 43 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 275 +#define YYMAXUTOK 276 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -484,7 +491,7 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20 + 15, 16, 17, 18, 19, 20, 21 }; #if YYDEBUG @@ -492,30 +499,31 @@ static const yytype_uint8 yytranslate[] = YYRHS. */ static const yytype_uint8 yyprhs[] = { - 0, 0, 3, 5, 7, 8, 10, 13, 17, 22, - 27, 33, 37, 43, 47, 50, 52, 54, 56, 58, - 60, 62, 64, 67, 70, 72 + 0, 0, 3, 5, 7, 8, 10, 13, 16, 20, + 25, 30, 36, 40, 46, 50, 53, 55, 57, 59, + 61, 63, 65, 67, 69, 70, 74, 78, 81 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 22, 0, -1, 23, -1, 25, -1, -1, 24, -1, - 23, 24, -1, 18, 10, 14, -1, 18, 10, 12, - 14, -1, 13, 18, 10, 14, -1, 13, 18, 10, - 12, 14, -1, 18, 11, 18, -1, 18, 11, 18, - 12, 14, -1, 18, 12, 14, -1, 6, 19, -1, - 17, -1, 16, -1, 15, -1, 7, -1, 8, -1, - 14, -1, 18, -1, 3, 19, -1, 5, 19, -1, - 4, -1, 4, 19, -1 + 23, 0, -1, 24, -1, 27, -1, -1, 25, -1, + 24, 25, -1, 24, 26, -1, 18, 10, 14, -1, + 18, 10, 12, 14, -1, 13, 18, 10, 14, -1, + 13, 18, 10, 12, 14, -1, 18, 11, 18, -1, + 18, 11, 18, 12, 14, -1, 18, 12, 14, -1, + 6, 19, -1, 17, -1, 16, -1, 15, -1, 7, + -1, 8, -1, 14, -1, 18, -1, 21, -1, -1, + 3, 26, 19, -1, 5, 26, 19, -1, 4, 26, + -1, 4, 26, 19, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 66, 66, 67, 68, 72, 73, 77, 82, 87, - 97, 107, 112, 118, 124, 129, 130, 131, 132, 133, - 134, 135, 139, 144, 149, 153 + 0, 67, 67, 68, 69, 73, 74, 75, 79, 84, + 89, 99, 109, 114, 120, 126, 131, 132, 133, 134, + 135, 136, 137, 141, 142, 146, 151, 156, 160 }; #endif @@ -531,8 +539,9 @@ static const char *const yytname[] = "\":: (double colon)\"", "\"# (pound sign)\"", "\"protocol (file://)\"", "\"digits (numbers)\"", "\"literal (string)\"", "\"address\"", "\"opcode\"", "\"identifier (command or function name)\"", - "\"input (input string or data)\"", "\"input\"", "$accept", "input", - "parameters", "parameter", "full_expression", YY_NULL + "\"input (input string or data)\"", "\"input\"", + "\"request id (-r %d)\"", "$accept", "input", "parameters", "parameter", + "req_id", "full_expression", YY_NULL }; #endif @@ -543,24 +552,24 @@ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275 + 275, 276 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 21, 22, 22, 22, 23, 23, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 25, 25, 25, 25 + 0, 22, 23, 23, 23, 24, 24, 24, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 26, 26, 27, 27, 27, 27 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 1, 1, 0, 1, 2, 3, 4, 4, - 5, 3, 5, 3, 2, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 1, 2 + 0, 2, 1, 1, 0, 1, 2, 2, 3, 4, + 4, 5, 3, 5, 3, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 3, 3, 2, 3 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. @@ -568,33 +577,35 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 4, 0, 24, 0, 0, 18, 19, 0, 20, 17, - 16, 15, 21, 0, 2, 5, 3, 22, 25, 23, - 14, 0, 0, 0, 0, 1, 6, 0, 0, 7, - 11, 13, 0, 9, 8, 0, 10, 12 + 4, 24, 24, 24, 0, 19, 20, 0, 21, 18, + 17, 16, 22, 0, 2, 5, 3, 23, 0, 27, + 0, 15, 0, 0, 0, 0, 1, 6, 7, 25, + 28, 26, 0, 0, 8, 12, 14, 0, 10, 9, + 0, 11, 13 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 13, 14, 15, 16 + -1, 13, 14, 15, 18, 16 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -11 +#define YYPACT_NINF -16 static const yytype_int8 yypact[] = { - -3, -10, 11, 12, 13, -11, -11, 15, -11, -11, - -11, -11, -4, 29, 10, -11, -11, -11, -11, -11, - -11, 24, 7, 17, 22, -11, -11, 8, 23, -11, - 26, -11, 25, -11, -11, 27, -11, -11 + -3, -15, -15, -15, -10, -16, -16, 3, -16, -16, + -16, -16, 22, 29, 10, -16, -16, -16, 11, 17, + 19, -16, 30, 8, 21, 27, -16, -16, -16, -16, + -16, -16, 23, 28, -16, 31, -16, 32, -16, -16, + 33, -16, -16 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -11, -11, -11, 28, -11 + -16, -16, -16, 34, 5, -16 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -603,26 +614,26 @@ static const yytype_int8 yypgoto[] = #define YYTABLE_NINF -1 static const yytype_uint8 yytable[] = { - 1, 2, 3, 4, 5, 6, 22, 23, 24, 17, + 1, 2, 3, 4, 5, 6, 17, 19, 20, 21, 7, 8, 9, 10, 11, 12, 4, 5, 6, 28, - 32, 29, 33, 7, 8, 9, 10, 11, 12, 25, - 18, 19, 20, 21, 27, 30, 31, 34, 35, 36, - 0, 37, 26 + 33, 22, 34, 7, 8, 9, 10, 11, 12, 26, + 29, 17, 23, 24, 25, 37, 30, 38, 31, 35, + 32, 36, 39, 40, 0, 0, 41, 42, 27 }; #define yypact_value_is_default(yystate) \ - ((yystate) == (-11)) + ((yystate) == (-16)) #define yytable_value_is_error(yytable_value) \ YYID (0) static const yytype_int8 yycheck[] = { - 3, 4, 5, 6, 7, 8, 10, 11, 12, 19, - 13, 14, 15, 16, 17, 18, 6, 7, 8, 12, - 12, 14, 14, 13, 14, 15, 16, 17, 18, 0, - 19, 19, 19, 18, 10, 18, 14, 14, 12, 14, - -1, 14, 14 + 3, 4, 5, 6, 7, 8, 21, 2, 3, 19, + 13, 14, 15, 16, 17, 18, 6, 7, 8, 14, + 12, 18, 14, 13, 14, 15, 16, 17, 18, 0, + 19, 21, 10, 11, 12, 12, 19, 14, 19, 18, + 10, 14, 14, 12, -1, -1, 14, 14, 14 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -630,9 +641,10 @@ static const yytype_int8 yycheck[] = static const yytype_uint8 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 13, 14, 15, - 16, 17, 18, 22, 23, 24, 25, 19, 19, 19, - 19, 18, 10, 11, 12, 0, 24, 10, 12, 14, - 18, 14, 12, 14, 14, 12, 14, 14 + 16, 17, 18, 23, 24, 25, 27, 21, 26, 26, + 26, 19, 18, 10, 11, 12, 0, 25, 26, 19, + 19, 19, 10, 12, 14, 18, 14, 12, 14, 14, + 12, 14, 14 }; #define yyerrok (yyerrstatus = 0) @@ -1284,6 +1296,7 @@ YYSTYPE yylval; The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; + goto yysetstate; /*------------------------------------------------------------. @@ -1461,26 +1474,37 @@ yyreduce: switch (yyn) { case 3: -/* Line 1802 of yacc.c */ -#line 67 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 68 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); } break; case 5: -/* Line 1802 of yacc.c */ -#line 72 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 73 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(1) - (1)])); } break; case 6: -/* Line 1802 of yacc.c */ -#line 73 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 74 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { phpdbg_stack_push(PHPDBG_G(parser_stack), &(yyvsp[(2) - (2)])); } break; case 7: -/* Line 1802 of yacc.c */ -#line 77 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 75 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (2)]); } + break; + + case 8: + +/* Line 1803 of yacc.c */ +#line 79 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = FILE_PARAM; (yyval).file.name = (yyvsp[(2) - (3)]).str; @@ -1488,9 +1512,10 @@ yyreduce: } break; - case 8: -/* Line 1802 of yacc.c */ -#line 82 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 9: + +/* Line 1803 of yacc.c */ +#line 84 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FILE_PARAM; (yyval).file.name = (yyvsp[(1) - (4)]).str; @@ -1498,9 +1523,10 @@ yyreduce: } break; - case 9: -/* Line 1802 of yacc.c */ -#line 87 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 10: + +/* Line 1803 of yacc.c */ +#line 89 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = FILE_PARAM; (yyval).file.name = malloc((yyvsp[(1) - (4)]).len + (yyvsp[(2) - (4)]).len + 1); @@ -1513,9 +1539,10 @@ yyreduce: } break; - case 10: -/* Line 1802 of yacc.c */ -#line 97 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 11: + +/* Line 1803 of yacc.c */ +#line 99 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FILE_PARAM; (yyval).file.name = malloc((yyvsp[(1) - (5)]).len + (yyvsp[(2) - (5)]).len + 1); @@ -1528,9 +1555,10 @@ yyreduce: } break; - case 11: -/* Line 1802 of yacc.c */ -#line 107 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 12: + +/* Line 1803 of yacc.c */ +#line 109 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = METHOD_PARAM; (yyval).method.class = (yyvsp[(1) - (3)]).str; @@ -1538,9 +1566,10 @@ yyreduce: } break; - case 12: -/* Line 1802 of yacc.c */ -#line 112 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 13: + +/* Line 1803 of yacc.c */ +#line 114 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_METHOD_PARAM; (yyval).method.class = (yyvsp[(1) - (5)]).str; @@ -1549,9 +1578,10 @@ yyreduce: } break; - case 13: -/* Line 1802 of yacc.c */ -#line 118 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 14: + +/* Line 1803 of yacc.c */ +#line 120 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = NUMERIC_FUNCTION_PARAM; (yyval).str = (yyvsp[(1) - (3)]).str; @@ -1560,9 +1590,10 @@ yyreduce: } break; - case 14: -/* Line 1802 of yacc.c */ -#line 124 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 15: + +/* Line 1803 of yacc.c */ +#line 126 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = COND_PARAM; (yyval).str = (yyvsp[(2) - (2)]).str; @@ -1570,90 +1601,109 @@ yyreduce: } break; - case 15: -/* Line 1802 of yacc.c */ -#line 129 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" - { (yyval) = (yyvsp[(1) - (1)]); } - break; - case 16: -/* Line 1802 of yacc.c */ -#line 130 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 131 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 17: -/* Line 1802 of yacc.c */ -#line 131 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 132 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 18: -/* Line 1802 of yacc.c */ -#line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 133 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 19: -/* Line 1802 of yacc.c */ -#line 133 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 134 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 20: -/* Line 1802 of yacc.c */ -#line 134 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 135 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 21: -/* Line 1802 of yacc.c */ -#line 135 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 136 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 22: -/* Line 1802 of yacc.c */ -#line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 1803 of yacc.c */ +#line 137 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 23: + +/* Line 1803 of yacc.c */ +#line 141 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" + { PHPDBG_G(req_id) = (yyvsp[(1) - (1)]).num; } + break; + + case 25: + +/* Line 1803 of yacc.c */ +#line 146 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = EVAL_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; + (yyval).str = (yyvsp[(3) - (3)]).str; + (yyval).len = (yyvsp[(3) - (3)]).len; } break; - case 23: -/* Line 1802 of yacc.c */ -#line 144 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 26: + +/* Line 1803 of yacc.c */ +#line 151 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = SHELL_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; + (yyval).str = (yyvsp[(3) - (3)]).str; + (yyval).len = (yyvsp[(3) - (3)]).len; } break; - case 24: -/* Line 1802 of yacc.c */ -#line 149 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 27: + +/* Line 1803 of yacc.c */ +#line 156 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = RUN_PARAM; (yyval).len = 0; } break; - case 25: -/* Line 1802 of yacc.c */ -#line 153 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + case 28: + +/* Line 1803 of yacc.c */ +#line 160 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" { (yyval).type = RUN_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; + (yyval).str = (yyvsp[(3) - (3)]).str; + (yyval).len = (yyvsp[(3) - (3)]).len; } break; -/* Line 1802 of yacc.c */ -#line 1657 "sapi/phpdbg/phpdbg_parser.c" + +/* Line 1803 of yacc.c */ +#line 1707 "sapi/phpdbg/phpdbg_parser.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1882,12 +1932,13 @@ yyreturn: } -/* Line 2048 of yacc.c */ -#line 160 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 2049 of yacc.c */ +#line 167 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" static int yyerror(void ***tsrm_ls, const char *msg) { - phpdbg_error("Parse Error: %s", msg); + phpdbg_error("command", "type=\"parseerror\" msg=\"%s\"", "Parse Error: %s", msg); { const phpdbg_param_t *top = PHPDBG_G(parser_stack); @@ -1909,3 +1960,4 @@ int phpdbg_do_parse(phpdbg_param_t *stack, char *input TSRMLS_DC) { return yyparse(NULL); #endif } + diff --git a/sapi/phpdbg/phpdbg_parser.h b/sapi/phpdbg/phpdbg_parser.h index b3aadb9c62..e8ab7a6503 100644 --- a/sapi/phpdbg/phpdbg_parser.h +++ b/sapi/phpdbg/phpdbg_parser.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 2.6.2. */ +/* A Bison parser, made by GNU Bison 2.6. */ /* Bison interface for Yacc-like parsers in C @@ -40,8 +40,9 @@ extern int phpdbg_debug; #endif /* "%code requires" blocks. */ -/* Line 2055 of yacc.c */ -#line 31 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + +/* Line 2056 of yacc.c */ +#line 31 "/Users/Bob/php-src-X/sapi/phpdbg/phpdbg_parser.y" #include "phpdbg.h" #ifndef YY_TYPEDEF_YY_SCANNER_T @@ -50,8 +51,9 @@ typedef void* yyscan_t; #endif -/* Line 2055 of yacc.c */ -#line 55 "sapi/phpdbg/phpdbg_parser.h" + +/* Line 2056 of yacc.c */ +#line 57 "sapi/phpdbg/phpdbg_parser.h" /* Tokens. */ #ifndef YYTOKENTYPE @@ -76,7 +78,8 @@ typedef void* yyscan_t; T_OPCODE = 272, T_ID = 273, T_INPUT = 274, - T_UNEXPECTED = 275 + T_UNEXPECTED = 275, + T_REQ_ID = 276 }; #endif /* Tokens. */ @@ -98,6 +101,7 @@ typedef void* yyscan_t; #define T_ID 273 #define T_INPUT 274 #define T_UNEXPECTED 275 +#define T_REQ_ID 276 diff --git a/sapi/phpdbg/phpdbg_parser.y b/sapi/phpdbg/phpdbg_parser.y index 702bf78455..e4353976f3 100644 --- a/sapi/phpdbg/phpdbg_parser.y +++ b/sapi/phpdbg/phpdbg_parser.y @@ -59,6 +59,7 @@ typedef void* yyscan_t; %token T_ID "identifier (command or function name)" %token T_INPUT "input (input string or data)" %token T_UNEXPECTED "input" +%token T_REQ_ID "request id (-r %d)" %% /* Rules */ @@ -71,6 +72,7 @@ input parameters : parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); } | parameters parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$2); } + | parameters req_id { $$ = $1; } ; parameter @@ -135,32 +137,37 @@ parameter | T_ID { $$ = $1; } ; +req_id + : T_REQ_ID { PHPDBG_G(req_id) = $1.num; } + | /* empty */ +; + full_expression - : T_EVAL T_INPUT { + : T_EVAL req_id T_INPUT { $$.type = EVAL_PARAM; - $$.str = $2.str; - $$.len = $2.len; + $$.str = $3.str; + $$.len = $3.len; } - | T_SHELL T_INPUT { + | T_SHELL req_id T_INPUT { $$.type = SHELL_PARAM; - $$.str = $2.str; - $$.len = $2.len; + $$.str = $3.str; + $$.len = $3.len; } - | T_RUN { + | T_RUN req_id { $$.type = RUN_PARAM; $$.len = 0; } - | T_RUN T_INPUT { + | T_RUN req_id T_INPUT { $$.type = RUN_PARAM; - $$.str = $2.str; - $$.len = $2.len; + $$.str = $3.str; + $$.len = $3.len; } ; %% static int yyerror(void ***tsrm_ls, const char *msg) { - phpdbg_error("Parse Error: %s", msg); + phpdbg_error("command", "type=\"parseerror\" msg=\"%s\"", "Parse Error: %s", msg); { const phpdbg_param_t *top = PHPDBG_G(parser_stack); diff --git a/sapi/phpdbg/phpdbg_print.c b/sapi/phpdbg/phpdbg_print.c index eba7ed7666..62a614281d 100644 --- a/sapi/phpdbg/phpdbg_print.c +++ b/sapi/phpdbg/phpdbg_print.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -26,25 +26,25 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9]) +#define PHPDBG_PRINT_COMMAND_D(f, h, a, m, l, s, flags) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[9], flags) const phpdbg_command_t phpdbg_print_commands[] = { - PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0), - PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0), - PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s"), - PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m"), - PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s"), - PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0), + PHPDBG_PRINT_COMMAND_D(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s", PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m", PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s", PHPDBG_ASYNC_SAFE), + PHPDBG_PRINT_COMMAND_D(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0, PHPDBG_ASYNC_SAFE), PHPDBG_END_COMMAND }; PHPDBG_PRINT(opline) /* {{{ */ { - if (EG(in_execution) && EG(current_execute_data)) { + if (PHPDBG_G(in_execution) && EG(current_execute_data)) { phpdbg_print_opline(EG(current_execute_data), 1 TSRMLS_CC); } else { - phpdbg_error("Not Executing!"); + phpdbg_error("inactive", "type=\"execution\"", "Not Executing!"); } return SUCCESS; @@ -56,38 +56,39 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) case ZEND_USER_FUNCTION: { zend_op_array* op_array = &(method->op_array); HashTable vars; - + if (op_array) { zend_op *opline = &(op_array->opcodes[0]); uint32_t opcode = 0, end = op_array->last-1; if (method->common.scope) { - phpdbg_writeln("\tL%d-%d %s::%s() %s", - op_array->line_start, op_array->line_end, - method->common.scope->name, - method->common.function_name, - op_array->filename ? op_array->filename : "unknown"); + phpdbg_writeln("printoplineinfo", "type=\"User\" startline=\"%d\" endline=\"%d\" method=\"%s::%s\" file=\"%s\"", "\tL%d-%d %s::%s() %s", + op_array->line_start, + op_array->line_end, + method->common.scope->name->val, + method->common.function_name->val, + op_array->filename ? op_array->filename->val : "unknown"); } else { - phpdbg_writeln("\tL%d-%d %s() %s", - method->common.function_name ? op_array->line_start : 0, + phpdbg_writeln("printoplineinfo", "type=\"User\" startline=\"%d\" endline=\"%d\" function=\"%s\" file=\"%s\"", "\tL%d-%d %s() %s", + method->common.function_name ? op_array->line_start : 0, method->common.function_name ? op_array->line_end : 0, - method->common.function_name ? method->common.function_name : "{main}", - op_array->filename ? op_array->filename : "unknown"); + method->common.function_name ? method->common.function_name->val : "{main}", + op_array->filename ? op_array->filename->val : "unknown"); } zend_hash_init(&vars, op_array->last, NULL, NULL, 0); do { char *decode = phpdbg_decode_opline(op_array, opline, &vars TSRMLS_CC); if (decode != NULL) { - phpdbg_writeln("\t\tL%u\t%p %-30s %s", + phpdbg_writeln("print", "line=\"%u\" opline=\"%p\" opcode=\"%s\" op=\"%s\"", "\t\tL%u\t%p %-30s %s", opline->lineno, - opline, + opline, phpdbg_decode_opcode(opline->opcode), decode); free(decode); } else { - phpdbg_error("\tFailed to decode opline %16p", opline); + phpdbg_error("print", "type=\"decodefailure\" opline=\"%16p\"", "\tFailed to decode opline %16p", opline); } opline++; } while (opcode++ < end); @@ -97,9 +98,9 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) default: { if (method->common.scope) { - phpdbg_writeln("\tInternal %s::%s()", method->common.scope->name, method->common.function_name); + phpdbg_writeln("printoplineinfo", "type=\"Internal\" method=\"%s::%s\"", "\tInternal %s::%s()", method->common.scope->name->val, method->common.function_name->val); } else { - phpdbg_writeln("\tInternal %s()", method->common.function_name); + phpdbg_writeln("printoplineinfo", "type=\"Internal\" function=\"%s\"", "\tInternal %s()", method->common.function_name->val); } } } @@ -108,17 +109,17 @@ static inline void phpdbg_print_function_helper(zend_function *method TSRMLS_DC) PHPDBG_PRINT(exec) /* {{{ */ { if (PHPDBG_G(exec)) { - if (!PHPDBG_G(ops)) { + if (!PHPDBG_G(ops) && !(PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER)) { phpdbg_compile(TSRMLS_C); } if (PHPDBG_G(ops)) { - phpdbg_notice("Context %s", PHPDBG_G(exec)); + phpdbg_notice("printinfo", "file=\"%s\" num=\"%d\"", "Context %s (%d ops)", PHPDBG_G(exec), PHPDBG_G(ops)->last); phpdbg_print_function_helper((zend_function*) PHPDBG_G(ops) TSRMLS_CC); } } else { - phpdbg_error("No execution context set"); + phpdbg_error("inactive", "type=\"nocontext\"", "No execution context set"); } return SUCCESS; @@ -126,25 +127,24 @@ return SUCCESS; PHPDBG_PRINT(stack) /* {{{ */ { - zend_op_array *ops = EG(active_op_array); - - if (EG(in_execution) && ops) { + if (PHPDBG_G(in_execution) && EG(current_execute_data)) { + zend_op_array *ops = &EG(current_execute_data)->func->op_array; if (ops->function_name) { if (ops->scope) { - phpdbg_notice("Stack in %s::%s()", ops->scope->name, ops->function_name); + phpdbg_notice("printinfo", "method=\"%s::%s\" num=\"%d\"", "Stack in %s::%s() (%d ops)", ops->scope->name->val, ops->function_name->val, ops->last); } else { - phpdbg_notice("Stack in %s()", ops->function_name); + phpdbg_notice("printinfo", "function=\"%s\" num=\"%d\"", "Stack in %s() (%d ops)", ops->function_name->val, ops->last); } } else { if (ops->filename) { - phpdbg_notice("Stack in %s", ops->filename); + phpdbg_notice("printinfo", "file=\"%s\" num=\"%d\"", "Stack in %s (%d ops)", ops->filename->val, ops->last); } else { - phpdbg_notice("Stack @ %p", ops); + phpdbg_notice("printinfo", "opline=\"%p\" num=\"%d\"", "Stack @ %p (%d ops)", ops, ops->last); } } phpdbg_print_function_helper((zend_function*) ops TSRMLS_CC); } else { - phpdbg_error("Not Executing!"); + phpdbg_error("inactive", "type=\"execution\"", "Not Executing!"); } return SUCCESS; @@ -152,32 +152,33 @@ PHPDBG_PRINT(stack) /* {{{ */ PHPDBG_PRINT(class) /* {{{ */ { - zend_class_entry **ce; + zend_class_entry *ce; - if (zend_lookup_class(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { - phpdbg_notice("%s %s: %s", - ((*ce)->type == ZEND_USER_CLASS) ? + if (phpdbg_safe_class_lookup(param->str, param->len, &ce TSRMLS_CC) == SUCCESS) { + phpdbg_notice("printinfo", "type=\"%s\" flag=\"%s\" class=\"%s\" num=\"%d\"", "%s %s: %s (%d methods)", + (ce->type == ZEND_USER_CLASS) ? "User" : "Internal", - ((*ce)->ce_flags & ZEND_ACC_INTERFACE) ? + (ce->ce_flags & ZEND_ACC_INTERFACE) ? "Interface" : - ((*ce)->ce_flags & ZEND_ACC_ABSTRACT) ? + (ce->ce_flags & ZEND_ACC_ABSTRACT) ? "Abstract Class" : "Class", - (*ce)->name); + ce->name->val, + zend_hash_num_elements(&ce->function_table)); + + phpdbg_xml("<printmethods %r>"); - phpdbg_writeln("Methods (%d):", zend_hash_num_elements(&(*ce)->function_table)); - if (zend_hash_num_elements(&(*ce)->function_table)) { - HashPosition position; + if (zend_hash_num_elements(&ce->function_table)) { zend_function *method; - for (zend_hash_internal_pointer_reset_ex(&(*ce)->function_table, &position); - zend_hash_get_current_data_ex(&(*ce)->function_table, (void**) &method, &position) == SUCCESS; - zend_hash_move_forward_ex(&(*ce)->function_table, &position)) { + ZEND_HASH_FOREACH_PTR(&ce->function_table, method) { phpdbg_print_function_helper(method TSRMLS_CC); - } + } ZEND_HASH_FOREACH_END(); } + + phpdbg_xml("</printmethods>"); } else { - phpdbg_error("The class %s could not be found", param->str); + phpdbg_error("print", "type=\"noclass\" class=\"%s\"", "The class %s could not be found", param->str); } return SUCCESS; @@ -185,25 +186,27 @@ PHPDBG_PRINT(class) /* {{{ */ PHPDBG_PRINT(method) /* {{{ */ { - zend_class_entry **ce; + zend_class_entry *ce; - if (zend_lookup_class(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { + if (phpdbg_safe_class_lookup(param->method.class, strlen(param->method.class), &ce TSRMLS_CC) == SUCCESS) { zend_function *fbc; - char *lcname = zend_str_tolower_dup(param->method.name, strlen(param->method.name)); + zend_string *lcname = zend_string_alloc(strlen(param->method.name), 0); + zend_str_tolower_copy(lcname->val, param->method.name, lcname->len); - if (zend_hash_find(&(*ce)->function_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { - phpdbg_notice("%s Method %s", + if ((fbc = zend_hash_find_ptr(&ce->function_table, lcname))) { + phpdbg_notice("printinfo", "type=\"%s\" flags=\"Method\" symbol=\"%s\" num=\"%d\"", "%s Method %s (%d ops)", (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", - fbc->common.function_name); + fbc->common.function_name->val, + (fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0); phpdbg_print_function_helper(fbc TSRMLS_CC); } else { - phpdbg_error("The method %s could not be found", param->method.name); + phpdbg_error("print", "type=\"nomethod\" method=\"%s::%s\"", "The method %s::%s could not be found", param->method.class, param->method.name); } - efree(lcname); + zend_string_release(lcname); } else { - phpdbg_error("The class %s could not be found", param->method.class); + phpdbg_error("print", "type=\"noclass\" class=\"%s\"", "The class %s could not be found", param->method.class); } return SUCCESS; @@ -215,7 +218,7 @@ PHPDBG_PRINT(func) /* {{{ */ zend_function* fbc; const char *func_name = param->str; size_t func_name_len = param->len; - char *lcname; + zend_string *lcname; /* search active scope if begins with period */ if (func_name[0] == '.') { if (EG(scope)) { @@ -224,28 +227,34 @@ PHPDBG_PRINT(func) /* {{{ */ func_table = &EG(scope)->function_table; } else { - phpdbg_error("No active class"); + phpdbg_error("inactive", "type=\"noclasses\"", "No active class"); return SUCCESS; } } else if (!EG(function_table)) { - phpdbg_error("No function table loaded"); + phpdbg_error("inactive", "type=\"function_table\"", "No function table loaded"); return SUCCESS; } else { func_table = EG(function_table); } - lcname = zend_str_tolower_dup(func_name, func_name_len); + lcname = zend_string_alloc(func_name_len, 0); + zend_str_tolower_copy(lcname->val, func_name, lcname->len); - if (zend_hash_find(func_table, lcname, strlen(lcname)+1, (void**)&fbc) == SUCCESS) { - phpdbg_notice("%s %s %s", - (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", - (fbc->common.scope) ? "Method" : "Function", - fbc->common.function_name); + phpdbg_try_access { + if ((fbc = zend_hash_find_ptr(func_table, lcname))) { + phpdbg_notice("printinfo", "type=\"%s\" flags=\"%s\" symbol=\"%s\" num=\"%d\"", "%s %s %s (%d ops)", + (fbc->type == ZEND_USER_FUNCTION) ? "User" : "Internal", + (fbc->common.scope) ? "Method" : "Function", + fbc->common.function_name->val, + (fbc->type == ZEND_USER_FUNCTION) ? fbc->op_array.last : 0); - phpdbg_print_function_helper(fbc TSRMLS_CC); - } else { - phpdbg_error("The function %s could not be found", func_name); - } + phpdbg_print_function_helper(fbc TSRMLS_CC); + } else { + phpdbg_error("print", "type=\"nofunction\" function=\"%s\"", "The function %s could not be found", func_name); + } + } phpdbg_catch_access { + phpdbg_error("signalsegv", "function=\"%.*s\"", "Couldn't fetch function %.*s, invalid data source", (int) func_name_len, func_name); + } phpdbg_end_try_access(); efree(lcname); diff --git a/sapi/phpdbg/phpdbg_print.h b/sapi/phpdbg/phpdbg_print.h index 7bd096bf4e..ed85e965c1 100644 --- a/sapi/phpdbg/phpdbg_print.h +++ b/sapi/phpdbg/phpdbg_print.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 134ef33f6d..190907e687 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -22,7 +22,9 @@ #include <string.h> #include "zend.h" #include "zend_compile.h" +#include "zend_exceptions.h" #include "phpdbg.h" + #include "phpdbg_help.h" #include "phpdbg_print.h" #include "phpdbg_info.h" @@ -37,126 +39,136 @@ #include "phpdbg_frame.h" #include "phpdbg_lexer.h" #include "phpdbg_parser.h" +#include "phpdbg_wait.h" +#include "phpdbg_eol.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +#ifdef HAVE_LIBDL +#ifdef PHP_WIN32 +#include "win32/param.h" +#include "win32/winutil.h" +#define GET_DL_ERROR() php_win_err() +#elif defined(NETWARE) +#include <sys/param.h> +#define GET_DL_ERROR() dlerror() +#else +#include <sys/param.h> +#define GET_DL_ERROR() DL_ERROR() +#endif +#endif /* {{{ command declarations */ const phpdbg_command_t phpdbg_prompt_commands[] = { - PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s"), - PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0), - PHPDBG_COMMAND_D(continue,"continue execution", 'c', NULL, 0), - PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s"), - PHPDBG_COMMAND_D(ev, "evaluate some code", 0, NULL, "i"), - PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0), - PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0), - PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0), - PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 0), - PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c"), - PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n"), - PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n"), - PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*"), - PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "s"), - PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0), - PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0), - PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s"), - PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s"), - PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s"), - PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s"), - PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s"), - PHPDBG_COMMAND_D(sh, "shell a command", 0, NULL, "i"), - PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0), - PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss"), + PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s", 0), + PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(continue,"continue execution", 'c', NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s", 0), + PHPDBG_COMMAND_D(ev, "evaluate some code", 0 , NULL, "i", PHPDBG_ASYNC_SAFE), /* restricted ASYNC_SAFE */ + PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0, 0), + PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0, 0), + PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0, 0), + PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 0, 0), + PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c", 0), + PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n", PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n", PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*", PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "s", PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0, 0), + PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0, 0), + PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s", PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s", PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s", 0), + PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s", 0), + PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s", PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(sh, "shell a command", 0 , NULL, "i", 0), + PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0, PHPDBG_ASYNC_SAFE), + PHPDBG_COMMAND_D(wait, "wait for other process", 'W', NULL, 0, 0), + PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss", 0), + PHPDBG_COMMAND_D(eol, "set EOL", 'E', NULL, "|s", 0), PHPDBG_END_COMMAND }; /* }}} */ -ZEND_EXTERN_MODULE_GLOBALS(phpdbg); - static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ */ { phpdbg_param_t *name = NULL; if (stack->type == STACK_PARAM) { + char *lc_name; + name = stack->next; - + if (!name || name->type != STR_PARAM) { return FAILURE; } - - if (zend_hash_exists( - &PHPDBG_G(registered), name->str, name->len+1)) { - zval fname, *fretval; - zend_fcall_info fci; + lc_name = zend_str_tolower_dup(name->str, name->len); - ZVAL_STRINGL(&fname, name->str, name->len, 1); + if (zend_hash_str_exists(&PHPDBG_G(registered), lc_name, name->len)) { + zval fretval; + zend_fcall_info fci; memset(&fci, 0, sizeof(zend_fcall_info)); + ZVAL_STRINGL(&fci.function_name, lc_name, name->len); fci.size = sizeof(zend_fcall_info); fci.function_table = &PHPDBG_G(registered); - fci.function_name = &fname; - fci.symbol_table = EG(active_symbol_table); - fci.object_ptr = NULL; - fci.retval_ptr_ptr = &fretval; + fci.symbol_table = zend_rebuild_symbol_table(TSRMLS_C); + fci.object = NULL; + fci.retval = &fretval; fci.no_separation = 1; if (name->next) { zval params; phpdbg_param_t *next = name->next; - + array_init(¶ms); while (next) { char *buffered = NULL; - + switch (next->type) { case OP_PARAM: case COND_PARAM: case STR_PARAM: - add_next_index_stringl( - ¶ms, - next->str, - next->len, 1); + add_next_index_stringl(¶ms, next->str, next->len); break; - + case NUMERIC_PARAM: add_next_index_long(¶ms, next->num); break; - + case METHOD_PARAM: - spprintf(&buffered, 0, "%s::%s", - next->method.class, next->method.name); - add_next_index_string(¶ms, buffered, 0); + spprintf(&buffered, 0, "%s::%s", next->method.class, next->method.name); + add_next_index_string(¶ms, buffered); break; - + case NUMERIC_METHOD_PARAM: - spprintf(&buffered, 0, "%s::%s#%ld", - next->method.class, next->method.name, next->num); - add_next_index_string(¶ms, buffered, 0); + spprintf(&buffered, 0, "%s::%s#%ld", next->method.class, next->method.name, next->num); + add_next_index_string(¶ms, buffered); break; - + case NUMERIC_FUNCTION_PARAM: - spprintf(&buffered, 0, "%s#%ld", - next->str, next->num); - add_next_index_string(¶ms, buffered, 0); + spprintf(&buffered, 0, "%s#%ld", next->str, next->num); + add_next_index_string(¶ms, buffered); break; - + case FILE_PARAM: - spprintf(&buffered, 0, "%s:%ld", - next->file.name, next->file.line); - add_next_index_string(¶ms, buffered, 0); + spprintf(&buffered, 0, "%s:%ld", next->file.name, next->file.line); + add_next_index_string(¶ms, buffered); break; - + case NUMERIC_FILE_PARAM: - spprintf(&buffered, 0, "%s:#%ld", - next->file.name, next->file.line); - add_next_index_string(¶ms, buffered, 0); + spprintf(&buffered, 0, "%s:#%ld", next->file.name, next->file.line); + add_next_index_string(¶ms, buffered); break; - + default: { /* not yet */ } } - - next = next->next; + + next = next->next; } zend_fcall_info_args(&fci, ¶ms TSRMLS_CC); @@ -165,22 +177,24 @@ static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ * fci.param_count = 0; } - phpdbg_debug( - "created %d params from arguments", - fci.param_count); + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); - zend_call_function(&fci, NULL TSRMLS_CC); + phpdbg_debug("created %d params from arguments", fci.param_count); - if (fretval) { - zend_print_zval_r( - fretval, 0 TSRMLS_CC); - phpdbg_writeln(EMPTY); + if (zend_call_function(&fci, NULL TSRMLS_CC) == SUCCESS) { + zend_print_zval_r(&fretval, 0 TSRMLS_CC); + phpdbg_out("\n"); + zval_ptr_dtor(&fretval); } - zval_dtor(&fname); + zval_dtor(&fci.function_name); + efree(lc_name); return SUCCESS; - } + } + + efree(lc_name); } return FAILURE; @@ -189,7 +203,7 @@ static inline int phpdbg_call_register(phpdbg_param_t *stack TSRMLS_DC) /* {{{ * void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC) /* {{{ */ { struct stat sb; - + if (init_file && VCWD_STAT(init_file, &sb) != -1) { FILE *fp = fopen(init_file, "r"); if (fp) { @@ -219,8 +233,7 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ in_code = 0; code[code_len] = '\0'; { - zend_eval_stringl( - code, code_len, NULL, "phpdbginit code" TSRMLS_CC); + zend_eval_stringl(code, code_len, NULL, "phpdbginit code" TSRMLS_CC); } free(code); code = NULL; @@ -243,30 +256,26 @@ void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_ } { - char *why = NULL; char *input = phpdbg_read_input(cmd TSRMLS_CC); phpdbg_param_t stack; phpdbg_init_param(&stack, STACK_PARAM); + phpdbg_activate_err_buf(1 TSRMLS_CC); + if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { - switch (phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { + switch (phpdbg_stack_execute(&stack, 1 /* allow_async_unsafe == 1 */ TSRMLS_CC)) { case FAILURE: -// if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { - phpdbg_error( - "Unrecognized command in %s:%d: %s, %s!", - init_file, line, input, why); - } -// } + phpdbg_activate_err_buf(0 TSRMLS_CC); + if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + phpdbg_output_err_buf("initfailure", "%b file=\"%s\" line=\"%d\" input=\"%s\"", "Unrecognized command in %s:%d: %s, %b!" TSRMLS_CC, init_file, line, input); + } break; } } - if (why) { - free(why); - why = NULL; - } + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); @@ -282,8 +291,7 @@ next_line: fclose(fp); } else { - phpdbg_error( - "Failed to open %s for initialization", init_file); + phpdbg_error("initfailure", "type=\"openfile\" file=\"%s\"", "Failed to open %s for initialization", init_file); } if (free_init) { @@ -315,8 +323,7 @@ void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TS scan_dir[i] = 0; } - asprintf( - &init_file, "%s/%s", scan_dir, PHPDBG_INIT_FILENAME); + asprintf(&init_file, "%s/%s", scan_dir, PHPDBG_INIT_FILENAME); phpdbg_try_file_init(init_file, strlen(init_file), 1 TSRMLS_CC); if (i == -1) { break; @@ -342,36 +349,38 @@ PHPDBG_COMMAND(exec) /* {{{ */ if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) { if (PHPDBG_G(exec)) { - phpdbg_notice("Unsetting old execution context: %s", PHPDBG_G(exec)); + phpdbg_notice("exec", "type=\"unset\" context=\"%s\"", "Unsetting old execution context: %s", PHPDBG_G(exec)); efree(PHPDBG_G(exec)); PHPDBG_G(exec) = NULL; PHPDBG_G(exec_len) = 0L; } if (PHPDBG_G(ops)) { - phpdbg_notice("Destroying compiled opcodes"); + phpdbg_notice("exec", "type=\"unsetops\"", "Destroying compiled opcodes"); phpdbg_clean(0 TSRMLS_CC); } PHPDBG_G(exec) = res; PHPDBG_G(exec_len) = res_len; - + + VCWD_CHDIR_FILE(res); + *SG(request_info).argv = PHPDBG_G(exec); php_hash_environment(TSRMLS_C); - phpdbg_notice("Set execution context: %s", PHPDBG_G(exec)); + phpdbg_notice("exec", "type=\"set\" context=\"%s\"", "Set execution context: %s", PHPDBG_G(exec)); if (phpdbg_compile(TSRMLS_C) == FAILURE) { - phpdbg_error("Failed to compile %s", PHPDBG_G(exec)); + phpdbg_error("compile", "type=\"compilefailure\" context=\"%s\"", "Failed to compile %s", PHPDBG_G(exec)); } } else { - phpdbg_notice("Execution context not changed"); + phpdbg_notice("exec", "type=\"unchanged\"", "Execution context not changed"); } } else { - phpdbg_error("Cannot use %s as execution context, not a valid file or symlink", param->str); + phpdbg_error("exec", "type=\"invalid\" context=\"%s\"", "Cannot use %s as execution context, not a valid file or symlink", param->str); } } else { - phpdbg_error("Cannot stat %s, ensure the file exists", param->str); + phpdbg_error("exec", "type=\"notfound\" context=\"%s\"", "Cannot stat %s, ensure the file exists", param->str); } return SUCCESS; } /* }}} */ @@ -381,27 +390,23 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */ zend_file_handle fh; if (!PHPDBG_G(exec)) { - phpdbg_error("No execution context"); + phpdbg_error("inactive", "type=\"nocontext\"", "No execution context"); return SUCCESS; } - if (EG(in_execution)) { - phpdbg_error("Cannot compile while in execution"); + if (PHPDBG_G(in_execution)) { + phpdbg_error("inactive", "type=\"isrunning\"", "Cannot compile while in execution"); return FAILURE; } - phpdbg_notice("Attempting compilation of %s", PHPDBG_G(exec)); - - if (php_stream_open_for_zend_ex(PHPDBG_G(exec), &fh, - USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC) == SUCCESS) { - + if (php_stream_open_for_zend_ex(PHPDBG_G(exec), &fh, USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC) == SUCCESS) { PHPDBG_G(ops) = zend_compile_file(&fh, ZEND_INCLUDE TSRMLS_CC); zend_destroy_file_handle(&fh TSRMLS_CC); - phpdbg_notice("Success"); + phpdbg_notice("compile", "context=\"%s\"", "Successful compilation of %s", PHPDBG_G(exec)); return SUCCESS; } else { - phpdbg_error("Could not open file %s", PHPDBG_G(exec)); + phpdbg_error("compile", "type=\"openfailure\" context=\"%s\"", "Could not open file %s", PHPDBG_G(exec)); } return FAILURE; @@ -409,7 +414,7 @@ int phpdbg_compile(TSRMLS_D) /* {{{ */ PHPDBG_COMMAND(step) /* {{{ */ { - if (EG(in_execution)) { + if (PHPDBG_G(in_execution)) { PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } @@ -423,24 +428,19 @@ PHPDBG_COMMAND(continue) /* {{{ */ PHPDBG_COMMAND(until) /* {{{ */ { - if (!EG(in_execution)) { - phpdbg_error("Not executing"); + if (!PHPDBG_G(in_execution)) { + phpdbg_error("inactive", "type=\"noexec\"", "Not executing"); return SUCCESS; } PHPDBG_G(flags) |= PHPDBG_IN_UNTIL; { - uint32_t next = 0, - self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); - zend_op *opline = &EG(active_op_array)->opcodes[self]; - - for (next = self; next < EG(active_op_array)->last; next++) { - if (EG(active_op_array)->opcodes[next].lineno != opline->lineno) { - zend_hash_index_update( - &PHPDBG_G(seek), - (zend_ulong) &EG(active_op_array)->opcodes[next], - &EG(active_op_array)->opcodes[next], - sizeof(zend_op), NULL); + const zend_op *opline = EG(current_execute_data)->opline; + const zend_op_array *op_array = &EG(current_execute_data)->func->op_array; + + while (++opline < op_array->opcodes + op_array->last) { + if (opline->lineno != EG(current_execute_data)->opline->lineno) { + zend_hash_index_update_ptr(&PHPDBG_G(seek), (zend_ulong) opline, (void *) opline); break; } } @@ -449,68 +449,46 @@ PHPDBG_COMMAND(until) /* {{{ */ return PHPDBG_UNTIL; } /* }}} */ +static void phpdbg_seek_to_end(TSRMLS_D) { + const zend_op *opline = EG(current_execute_data)->opline; + const zend_op_array *op_array = &EG(current_execute_data)->func->op_array - 1; + + while (++opline < op_array->opcodes + op_array->last) { + switch (opline->opcode) { + case ZEND_RETURN: + case ZEND_THROW: + case ZEND_EXIT: +#ifdef ZEND_YIELD + case ZEND_YIELD: +#endif + zend_hash_index_update_ptr(&PHPDBG_G(seek), (zend_ulong) opline, (void *) opline); + return; + } + } +} + PHPDBG_COMMAND(finish) /* {{{ */ { - if (!EG(in_execution)) { - phpdbg_error("Not executing"); + if (!PHPDBG_G(in_execution)) { + phpdbg_error("inactive", "type=\"noexec\"", "Not executing"); return SUCCESS; } PHPDBG_G(flags) |= PHPDBG_IN_FINISH; - { - uint32_t next = 0, - self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); - - for (next = self; next < EG(active_op_array)->last; next++) { - switch (EG(active_op_array)->opcodes[next].opcode) { - case ZEND_RETURN: - case ZEND_THROW: - case ZEND_EXIT: -#ifdef ZEND_YIELD - case ZEND_YIELD: -#endif - zend_hash_index_update( - &PHPDBG_G(seek), - (zend_ulong) &EG(active_op_array)->opcodes[next], - &EG(active_op_array)->opcodes[next], - sizeof(zend_op), NULL); - break; - } - } - } + phpdbg_seek_to_end(TSRMLS_C); return PHPDBG_FINISH; } /* }}} */ PHPDBG_COMMAND(leave) /* {{{ */ { - if (!EG(in_execution)) { - phpdbg_error("Not executing"); + if (!PHPDBG_G(in_execution)) { + phpdbg_error("inactive", "type=\"noexec\"", "Not executing"); return SUCCESS; } PHPDBG_G(flags) |= PHPDBG_IN_LEAVE; - { - uint32_t next = 0, - self = (EG(current_execute_data)->opline - EG(active_op_array)->opcodes); - - for (next = self; next < EG(active_op_array)->last; next++) { - switch (EG(active_op_array)->opcodes[next].opcode) { - case ZEND_RETURN: - case ZEND_THROW: - case ZEND_EXIT: -#ifdef ZEND_YIELD - case ZEND_YIELD: -#endif - zend_hash_index_update( - &PHPDBG_G(seek), - (zend_ulong) &EG(active_op_array)->opcodes[next], - &EG(active_op_array)->opcodes[next], - sizeof(zend_op), NULL); - break; - } - } - } + phpdbg_seek_to_end(TSRMLS_C); return PHPDBG_LEAVE; } /* }}} */ @@ -518,8 +496,10 @@ PHPDBG_COMMAND(leave) /* {{{ */ PHPDBG_COMMAND(frame) /* {{{ */ { if (!param) { - phpdbg_notice("Currently in frame #%d", PHPDBG_G(frame).num); - } else phpdbg_switch_frame(param->num TSRMLS_CC); + phpdbg_notice("frame", "id=\"%d\"", "Currently in frame #%d", PHPDBG_G(frame).num); + } else { + phpdbg_switch_frame(param->num TSRMLS_CC); + } return SUCCESS; } /* }}} */ @@ -527,89 +507,65 @@ PHPDBG_COMMAND(frame) /* {{{ */ static inline void phpdbg_handle_exception(TSRMLS_D) /* }}} */ { zend_fcall_info fci; - - zval fname, - *trace, - exception; + zval trace; /* get filename and linenumber before unsetting exception */ const char *filename = zend_get_executed_filename(TSRMLS_C); uint32_t lineno = zend_get_executed_lineno(TSRMLS_C); - /* copy exception */ - exception = *EG(exception); - zval_copy_ctor(&exception); - EG(exception) = NULL; - - phpdbg_error( - "Uncaught %s!", - Z_OBJCE(exception)->name); - /* call __toString */ - ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring")-1, 1); + ZVAL_STRINGL(&fci.function_name, "__tostring", sizeof("__tostring") - 1); fci.size = sizeof(fci); - fci.function_table = &Z_OBJCE(exception)->function_table; - fci.function_name = &fname; + fci.function_table = &EG(exception)->ce->function_table; fci.symbol_table = NULL; - fci.object_ptr = &exception; - fci.retval_ptr_ptr = &trace; + fci.object = EG(exception); + fci.retval = &trace; fci.param_count = 0; fci.params = NULL; fci.no_separation = 1; - zend_call_function(&fci, NULL TSRMLS_CC); + if (zend_call_function(&fci, NULL TSRMLS_CC) == SUCCESS) { + phpdbg_writeln("exception", "name=\"%s\" trace=\"%.*s\"", "Uncaught %s!\n%.*s", EG(exception)->ce->name->val, Z_STRLEN(trace), Z_STRVAL(trace)); - if (trace) { - phpdbg_writeln( - "Uncaught %s", Z_STRVAL_P(trace)); - /* remember to dtor trace */ zval_ptr_dtor(&trace); + } else { + phpdbg_error("exception", "name=\"%s\"" "Uncaught %s!", EG(exception)->ce->name->val); } /* output useful information about address */ - phpdbg_writeln( - "Stacked entered at %p in %s on line %u", - EG(active_op_array)->opcodes, filename, lineno); + phpdbg_writeln("exception", "opline=\"%p\" file=\"%s\" line=\"%u\"", "Stack entered at %p in %s on line %u", EG(current_execute_data)->func->op_array.opcodes, filename, lineno); - zval_dtor(&fname); - zval_dtor(&exception); + zval_dtor(&fci.function_name); + zend_clear_exception(TSRMLS_C); } /* }}} */ PHPDBG_COMMAND(run) /* {{{ */ { - if (EG(in_execution)) { - phpdbg_error("Cannot start another execution while one is in progress"); + if (PHPDBG_G(in_execution)) { + phpdbg_error("inactive", "type=\"isrunning\"", "Cannot start another execution while one is in progress"); return SUCCESS; } if (PHPDBG_G(ops) || PHPDBG_G(exec)) { - zend_op **orig_opline = EG(opline_ptr); - zend_op_array *orig_op_array = EG(active_op_array); - zval **orig_retval_ptr = EG(return_value_ptr_ptr); - zend_bool restore = 1; zend_execute_data *ex = EG(current_execute_data); - + zend_bool restore = 1; + if (!PHPDBG_G(ops)) { if (phpdbg_compile(TSRMLS_C) == FAILURE) { - phpdbg_error("Failed to compile %s, cannot run", PHPDBG_G(exec)); + phpdbg_error("compile", "type=\"compilefailure\" context=\"%s\"", "Failed to compile %s, cannot run", PHPDBG_G(exec)); goto out; } } - EG(active_op_array) = PHPDBG_G(ops); - EG(return_value_ptr_ptr) = &PHPDBG_G(retval); - if (!EG(active_symbol_table)) { - zend_rebuild_symbol_table(TSRMLS_C); - } - /* clean up from last execution */ if (ex && ex->symbol_table) { - zend_hash_clean(ex->symbol_table); + zend_hash_clean(&ex->symbol_table->ht); + } else { + zend_rebuild_symbol_table(TSRMLS_C); } /* clean seek state */ PHPDBG_G(flags) &= ~PHPDBG_SEEK_MASK; - zend_hash_clean( - &PHPDBG_G(seek)); + zend_hash_clean(&PHPDBG_G(seek)); /* reset hit counters */ phpdbg_reset_breakpoints(TSRMLS_C); @@ -619,7 +575,7 @@ PHPDBG_COMMAND(run) /* {{{ */ int argc = 0; int i; char *argv_str = strtok(param->str, " "); - + while (argv_str) { if (argc >= 4 && argc == (argc & -argc)) { argv = erealloc(argv, (argc * 2 + 1) * sizeof(char *)); @@ -635,38 +591,35 @@ PHPDBG_COMMAND(run) /* {{{ */ efree(SG(request_info).argv); SG(request_info).argv = erealloc(argv, ++argc * sizeof(char *)); SG(request_info).argc = argc; - + php_hash_environment(TSRMLS_C); } zend_try { - php_output_activate(TSRMLS_C); PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; - zend_execute(EG(active_op_array) TSRMLS_CC); + zend_execute(PHPDBG_G(ops), &PHPDBG_G(retval) TSRMLS_CC); PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE; - php_output_deactivate(TSRMLS_C); + phpdbg_notice("stop", "type=\"normal\"", "Script ended normally"); } zend_catch { - EG(active_op_array) = orig_op_array; - EG(opline_ptr) = orig_opline; - EG(return_value_ptr_ptr) = orig_retval_ptr; - + PHPDBG_G(in_execution) = 0; if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - phpdbg_error("Caught exit/error from VM"); + phpdbg_error("stop", "type=\"bailout\"", "Caught exit/error from VM"); restore = 0; } } zend_end_try(); + if (PHPDBG_G(socket_fd) != -1) { + close(PHPDBG_G(socket_fd)); + PHPDBG_G(socket_fd) = -1; + } + if (restore) { if (EG(exception)) { phpdbg_handle_exception(TSRMLS_C); } - - EG(active_op_array) = orig_op_array; - EG(opline_ptr) = orig_opline; - EG(return_value_ptr_ptr) = orig_retval_ptr; } } else { - phpdbg_error("Nothing to execute!"); + phpdbg_error("inactive", "type=\"nocontext\"", "Nothing to execute!"); } out: @@ -674,31 +627,56 @@ out: return SUCCESS; } /* }}} */ +int phpdbg_output_ev_variable(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv TSRMLS_DC) { + phpdbg_notice("eval", "variable=\"%.*s\"", "Printing variable %.*s", (int) len, name); + phpdbg_xml("<eval %r>"); + zend_print_zval_r(zv, 0 TSRMLS_CC); + phpdbg_xml("</eval>"); + phpdbg_out("\n"); + + efree(name); + efree(keyname); + + return SUCCESS; +} + PHPDBG_COMMAND(ev) /* {{{ */ { - zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)==PHPDBG_IS_STEPPING); + zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING) == PHPDBG_IS_STEPPING); zval retval; + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + phpdbg_try_access { + phpdbg_parse_variable(param->str, param->len, &EG(symbol_table).ht, 0, phpdbg_output_ev_variable, 0 TSRMLS_CC); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "", "Could not fetch data, invalid data source"); + } phpdbg_end_try_access(); + return SUCCESS; + } + if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { - PHPDBG_G(flags) &= ~ PHPDBG_IS_STEPPING; + PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING; } /* disable stepping while eval() in progress */ PHPDBG_G(flags) |= PHPDBG_IN_EVAL; zend_try { - if (zend_eval_stringl(param->str, param->len, - &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) { - zend_print_zval_r( - &retval, 0 TSRMLS_CC); - phpdbg_writeln(EMPTY); - zval_dtor(&retval); + if (zend_eval_stringl(param->str, param->len, &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) { + phpdbg_xml("<eval %r>"); + if (PHPDBG_G(flags) & PHPDBG_WRITE_XML) { + zval *zvp = &retval; + phpdbg_xml_var_dump(zvp TSRMLS_CC); + } + zend_print_zval_r(&retval, 0 TSRMLS_CC); + phpdbg_xml("</eval>"); + phpdbg_out("\n"); + zval_ptr_dtor(&retval); } } zend_end_try(); PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL; /* switch stepping back on */ - if (stepping && - !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { + if (stepping && !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) { PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; } @@ -709,8 +687,8 @@ PHPDBG_COMMAND(ev) /* {{{ */ PHPDBG_COMMAND(back) /* {{{ */ { - if (!EG(in_execution)) { - phpdbg_error("Not executing!"); + if (!PHPDBG_G(in_execution)) { + phpdbg_error("inactive", "type=\"noexec\"", "Not executing!"); return SUCCESS; } @@ -725,62 +703,54 @@ PHPDBG_COMMAND(back) /* {{{ */ PHPDBG_COMMAND(print) /* {{{ */ { - phpdbg_writeln(SEPARATE); - phpdbg_notice("Execution Context Information"); + phpdbg_out("Execution Context Information\n\n"); + phpdbg_xml("<printinfo %r>"); #ifdef HAVE_LIBREADLINE - phpdbg_writeln("Readline\tyes"); + phpdbg_writeln("print", "readline=\"yes\"", "Readline yes"); #else - phpdbg_writeln("Readline\tno"); + phpdbg_writeln("print", "readline=\"no\"", "Readline no"); #endif #ifdef HAVE_LIBEDIT - phpdbg_writeln("Libedit\t\tyes"); + phpdbg_writeln("print", "libedit=\"yes\"", "Libedit yes"); #else - phpdbg_writeln("Libedit\t\tno"); + phpdbg_writeln("print", "libedit=\"no\"", "Libedit no"); #endif - phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); - phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no"); - phpdbg_writeln("Stepping\t%s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); - phpdbg_writeln("Quietness\t%s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); - phpdbg_writeln("Oplog\t\t%s", PHPDBG_G(oplog) ? "on" : "off"); + phpdbg_writeln("print", "context=\"%s\"", "Exec %s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); + phpdbg_writeln("print", "compiled=\"%s\"", "Compiled %s", PHPDBG_G(ops) ? "yes" : "no"); + phpdbg_writeln("print", "stepping=\"%s\"", "Stepping %s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off"); + phpdbg_writeln("print", "quiet=\"%s\"", "Quietness %s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off"); + phpdbg_writeln("print", "oplog=\"%s\"", "Oplog %s", PHPDBG_G(oplog) ? "on" : "off"); if (PHPDBG_G(ops)) { - phpdbg_writeln("Opcodes\t\t%d", PHPDBG_G(ops)->last); - - if (PHPDBG_G(ops)->last_var) { - phpdbg_writeln("Variables\t%d", PHPDBG_G(ops)->last_var-1); - } else { - phpdbg_writeln("Variables\tNone"); - } + phpdbg_writeln("print", "ops=\"%d\"", "Opcodes %d", PHPDBG_G(ops)->last); + phpdbg_writeln("print", "vars=\"%d\"", "Variables %d", PHPDBG_G(ops)->last_var ? PHPDBG_G(ops)->last_var - 1 : 0); } - phpdbg_writeln("Executing\t%s", EG(in_execution) ? "yes" : "no"); - if (EG(in_execution)) { - phpdbg_writeln("VM Return\t%d", PHPDBG_G(vmret)); + phpdbg_writeln("print", "executing=\"%d\"", "Executing %s", PHPDBG_G(in_execution) ? "yes" : "no"); + if (PHPDBG_G(in_execution)) { + phpdbg_writeln("print", "vmret=\"%d\"", "VM Return %d", PHPDBG_G(vmret)); } - phpdbg_writeln("Classes\t\t%d", zend_hash_num_elements(EG(class_table))); - phpdbg_writeln("Functions\t%d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants\t%d", zend_hash_num_elements(EG(zend_constants))); - phpdbg_writeln("Included\t%d", zend_hash_num_elements(&EG(included_files))); - - phpdbg_writeln(SEPARATE); + phpdbg_writeln("print", "classes=\"%d\"", "Classes %d", zend_hash_num_elements(EG(class_table))); + phpdbg_writeln("print", "functions=\"%d\"", "Functions %d", zend_hash_num_elements(EG(function_table))); + phpdbg_writeln("print", "constants=\"%d\"", "Constants %d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("print", "includes=\"%d\"", "Included %d", zend_hash_num_elements(&EG(included_files))); + phpdbg_xml("</printinfo>"); return SUCCESS; } /* }}} */ PHPDBG_COMMAND(info) /* {{{ */ { - phpdbg_error( - "No information command selected!"); + phpdbg_error("info", "type=\"toofewargs\" expected=\"1\"", "No information command selected!"); return SUCCESS; } /* }}} */ PHPDBG_COMMAND(set) /* {{{ */ { - phpdbg_error( - "No set command selected!"); + phpdbg_error("set", "type=\"toofewargs\" expected=\"1\"", "No set command selected!"); return SUCCESS; } /* }}} */ @@ -789,8 +759,8 @@ PHPDBG_COMMAND(break) /* {{{ */ { if (!param) { phpdbg_set_breakpoint_file( - zend_get_executed_filename(TSRMLS_C), - zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); + zend_get_executed_filename(TSRMLS_C), + zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); } else switch (param->type) { case ADDR_PARAM: phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC); @@ -799,7 +769,7 @@ PHPDBG_COMMAND(break) /* {{{ */ if (PHPDBG_G(exec)) { phpdbg_set_breakpoint_file(phpdbg_current_file(TSRMLS_C), param->num TSRMLS_CC); } else { - phpdbg_error("Execution context not set!"); + phpdbg_error("inactive", "type=\"noexec\"", "Execution context not set!"); } break; case METHOD_PARAM: @@ -837,42 +807,226 @@ PHPDBG_COMMAND(sh) /* {{{ */ { FILE *fd = NULL; if ((fd=VCWD_POPEN((char*)param->str, "w"))) { - /* do something perhaps ?? do we want input ?? */ + /* TODO: do something perhaps ?? do we want input ?? */ fclose(fd); } else { - phpdbg_error( - "Failed to execute %s", param->str); + phpdbg_error("sh", "type=\"failure\" smd=\"%s\"", "Failed to execute %s", param->str); + } + + return SUCCESS; +} /* }}} */ + +static int add_module_info(zend_module_entry *module TSRMLS_DC) { + phpdbg_write("module", "name=\"%s\"", "%s\n", module->name); + return 0; +} + +static int add_zendext_info(zend_extension *ext TSRMLS_DC) { + phpdbg_write("extension", "name=\"%s\"", "%s\n", ext->name); + return 0; +} + +PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, char **name TSRMLS_DC) { + DL_HANDLE handle; + char *extension_dir; + + extension_dir = INI_STR("extension_dir"); + + if (strchr(*path, '/') != NULL || strchr(*path, DEFAULT_SLASH) != NULL) { + /* path is fine */ + } else if (extension_dir && extension_dir[0]) { + char *libpath; + int extension_dir_len = strlen(extension_dir); + if (IS_SLASH(extension_dir[extension_dir_len-1])) { + spprintf(&libpath, 0, "%s%s", extension_dir, *path); /* SAFE */ + } else { + spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, *path); /* SAFE */ + } + efree(*path); + *path = libpath; + } else { + phpdbg_error("dl", "type=\"relpath\"", "Not a full path given or extension_dir ini setting is not set"); + + return NULL; + } + + handle = DL_LOAD(*path); + + if (!handle) { +#if PHP_WIN32 + char *err = GET_DL_ERROR(); + if (err && *err != "") { + phpdbg_error("dl", "type=\"unknown\"", "%s", err); + LocalFree(err); + } else { + phpdbg_error("dl", "type=\"unknown\"", "Unknown reason"); + } +#else + phpdbg_error("dl", "type=\"unknown\"", "%s", GET_DL_ERROR()); +#endif + return NULL; + } + +#if ZEND_EXTENSIONS_SUPPORT + do { + zend_extension *new_extension; + zend_extension_version_info *extension_version_info; + + extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info"); + if (!extension_version_info) { + extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info"); + } + new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "zend_extension_entry"); + if (!new_extension) { + new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "_zend_extension_entry"); + } + if (!extension_version_info || !new_extension) { + break; + } + if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { + phpdbg_error("dl", "type=\"wrongapi\" extension=\"%s\" apineeded=\"%d\" apiinstalled=\"%d\"", "%s requires Zend Engine API version %d, which does not match the installed Zend Engine API version %d", new_extension->name, extension_version_info->zend_extension_api_no, ZEND_EXTENSION_API_NO); + + goto quit; + } else if (strcmp(ZEND_EXTENSION_BUILD_ID, extension_version_info->build_id) && (!new_extension->build_id_check || new_extension->build_id_check(ZEND_EXTENSION_BUILD_ID) != SUCCESS)) { + phpdbg_error("dl", "type=\"wrongbuild\" extension=\"%s\" buildneeded=\"%s\" buildinstalled=\"%s\"", "%s was built with configuration %s, whereas running engine is %s", new_extension->name, extension_version_info->build_id, ZEND_EXTENSION_BUILD_ID); + + goto quit; + } + + *name = new_extension->name; + + zend_register_extension(new_extension, handle TSRMLS_CC); + + if (new_extension->startup) { + if (new_extension->startup(new_extension) != SUCCESS) { + phpdbg_error("dl", "type=\"startupfailure\" extension=\"%s\"", "Unable to startup Zend extension %s", new_extension->name); + + goto quit; + } + zend_append_version_info(new_extension); + } + + return "Zend extension"; + } while (0); +#endif + + do { + zend_module_entry *module_entry; + zend_module_entry *(*get_module)(void); + + get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module"); + if (!get_module) { + get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "_get_module"); + } + + if (!get_module) { + break; + } + + module_entry = get_module(); + *name = (char *) module_entry->name; + + if (strcmp(ZEND_EXTENSION_BUILD_ID, module_entry->build_id)) { + phpdbg_error("dl", "type=\"wrongbuild\" module=\"%s\" buildneeded=\"%s\" buildinstalled=\"%s\"", "%s was built with configuration %s, whereas running engine is %s", module_entry->name, module_entry->build_id, ZEND_EXTENSION_BUILD_ID); + + goto quit; + } + + module_entry->type = MODULE_PERSISTENT; + module_entry->module_number = zend_next_free_module(); + module_entry->handle = handle; + + if ((module_entry = zend_register_module_ex(module_entry TSRMLS_CC)) == NULL) { + phpdbg_error("dl", "type=\"registerfailure\" module=\"%s\"", "Unable to register module %s", module_entry->name); + + goto quit; + } + + if (zend_startup_module_ex(module_entry TSRMLS_CC) == FAILURE) { + phpdbg_error("dl", "type=\"startupfailure\" module=\"%s\"", "Unable to startup module %s", module_entry->name); + + goto quit; + } + + if (module_entry->request_startup_func) { + if (module_entry->request_startup_func(MODULE_PERSISTENT, module_entry->module_number TSRMLS_CC) == FAILURE) { + phpdbg_error("dl", "type=\"initfailure\" module=\"%s\"", "Unable to initialize module %s", module_entry->name); + + goto quit; + } + } + + return "module"; + } while (0); + + phpdbg_error("dl", "type=\"nophpso\"", "This shared object is nor a Zend extension nor a module"); + +quit: + DL_UNLOAD(handle); + return NULL; +} + +PHPDBG_COMMAND(dl) /* {{{ */ +{ + const char *type; + char *name, *path; + + if (!param || param->type == EMPTY_PARAM) { + phpdbg_notice("dl", "extensiontype=\"Zend extension\"", "Zend extensions"); + zend_llist_apply(&zend_extensions, (llist_apply_func_t) add_zendext_info TSRMLS_CC); + phpdbg_out("\n"); + phpdbg_notice("dl", "extensiontype=\"module\"", "Modules"); + zend_hash_apply(&module_registry, (apply_func_t) add_module_info TSRMLS_CC); + } else switch (param->type) { + case STR_PARAM: +#ifdef HAVE_LIBDL + path = estrndup(param->str, param->len); + + phpdbg_activate_err_buf(1 TSRMLS_CC); + if ((type = phpdbg_load_module_or_extension(&path, &name TSRMLS_CC)) == NULL) { + phpdbg_error("dl", "path=\"%s\" %b", "Could not load %s, not found or invalid zend extension / module: %b", path); + efree(name); + } else { + phpdbg_notice("dl", "extensiontype=\"%s\" name=\"%s\" path=\"%s\"", "Successfully loaded the %s %s at path %s", type, name, path); + } + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); + efree(path); +#else + phpdbg_error("dl", "type=\"unsupported\" path=\"%.*s\"", "Cannot dynamically load %.*s - dynamic modules are not supported", (int) param->len, param->str); +#endif + break; + + phpdbg_default_switch_case(); } - + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(source) /* {{{ */ { struct stat sb; - + if (VCWD_STAT(param->str, &sb) != -1) { phpdbg_try_file_init(param->str, param->len, 0 TSRMLS_CC); } else { - phpdbg_error( - "Failed to stat %s, file does not exist", param->str); + phpdbg_error("source", "type=\"notfound\" file=\"%s\"", "Failed to stat %s, file does not exist", param->str); } - + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(export) /* {{{ */ { FILE *handle = VCWD_FOPEN(param->str, "w+"); - + if (handle) { phpdbg_export_breakpoints(handle TSRMLS_CC); fclose(handle); } else { - phpdbg_error( - "Failed to open or create %s, check path and permissions", param->str); + phpdbg_error("export", "type=\"openfailure\" file=\"%s\"", "Failed to open or create %s, check path and permissions", param->str); } - + return SUCCESS; } /* }}} */ @@ -882,20 +1036,17 @@ PHPDBG_COMMAND(register) /* {{{ */ char *lcname = zend_str_tolower_dup(param->str, param->len); size_t lcname_len = strlen(lcname); - if (!zend_hash_exists(&PHPDBG_G(registered), lcname, lcname_len+1)) { - if (zend_hash_find(EG(function_table), lcname, lcname_len+1, (void**) &function) == SUCCESS) { - zend_hash_update( - &PHPDBG_G(registered), lcname, lcname_len+1, (void*)&function, sizeof(zend_function), NULL); + if (!zend_hash_str_exists(&PHPDBG_G(registered), lcname, lcname_len)) { + if ((function = zend_hash_str_find_ptr(EG(function_table), lcname, lcname_len))) { + zend_hash_str_update_ptr(&PHPDBG_G(registered), lcname, lcname_len, function); function_add_ref(function); - phpdbg_notice( - "Registered %s", lcname); + phpdbg_notice("register", "function=\"%s\"", "Registered %s", lcname); } else { - phpdbg_error("The requested function (%s) could not be found", param->str); + phpdbg_error("register", "type=\"notfoundc\" function=\"%s\"", "The requested function (%s) could not be found", param->str); } } else { - phpdbg_error( - "The requested name (%s) is already in use", lcname); + phpdbg_error("register", "type=\"inuse\" function=\"%s\"", "The requested name (%s) is already in use", lcname); } efree(lcname); @@ -915,38 +1066,44 @@ PHPDBG_COMMAND(quit) /* {{{ */ PHPDBG_COMMAND(clean) /* {{{ */ { - if (EG(in_execution)) { - phpdbg_error("Cannot clean environment while executing"); + if (PHPDBG_G(in_execution)) { + phpdbg_error("inactive", "type=\"isrunning\"", "Cannot clean environment while executing"); return SUCCESS; } - phpdbg_notice("Cleaning Execution Environment"); + phpdbg_out("Cleaning Execution Environment\n"); + phpdbg_xml("<cleaninfo %r>"); - phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table))); - phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table))); - phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants))); - phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files))); + phpdbg_writeln("clean", "classes=\"%d\"", "Classes %d", zend_hash_num_elements(EG(class_table))); + phpdbg_writeln("clean", "functions=\"%d\"", "Functions %d", zend_hash_num_elements(EG(function_table))); + phpdbg_writeln("clean", "constants=\"%d\"", "Constants %d", zend_hash_num_elements(EG(zend_constants))); + phpdbg_writeln("clean", "includes=\"%d\"", "Includes %d", zend_hash_num_elements(&EG(included_files))); phpdbg_clean(1 TSRMLS_CC); + phpdbg_xml("</cleaninfo>"); + return SUCCESS; } /* }}} */ PHPDBG_COMMAND(clear) /* {{{ */ { - phpdbg_notice("Clearing Breakpoints"); - - phpdbg_writeln("File\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE])); - phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM])); - phpdbg_writeln("Methods\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD])); - phpdbg_writeln("Oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE])); - phpdbg_writeln("File oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE])); - phpdbg_writeln("Function oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE])); - phpdbg_writeln("Method oplines\t\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE])); - phpdbg_writeln("Conditionals\t\t%d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_COND])); + phpdbg_out("Clearing Breakpoints\n"); + phpdbg_xml("<clearinfo %r>"); + + phpdbg_writeln("clear", "files=\"%d\"", "File %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE])); + phpdbg_writeln("clear", "functions=\"%d\"", "Functions %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM])); + phpdbg_writeln("clear", "methods=\"%d\"", "Methods %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD])); + phpdbg_writeln("clear", "oplines=\"%d\"", "Oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE])); + phpdbg_writeln("clear", "fileoplines=\"%d\"", "File oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE])); + phpdbg_writeln("clear", "functionoplines=\"%d\"", "Function oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE])); + phpdbg_writeln("clear", "methodoplines=\"%d\"", "Method oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE])); + phpdbg_writeln("clear", "eval=\"%d\"", "Conditionals %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_COND])); phpdbg_clear_breakpoints(TSRMLS_C); + phpdbg_xml("</clearinfo>"); + return SUCCESS; } /* }}} */ @@ -981,7 +1138,7 @@ PHPDBG_COMMAND(watch) /* {{{ */ } else switch (param->type) { case STR_PARAM: if (phpdbg_create_var_watchpoint(param->str, param->len TSRMLS_CC) != FAILURE) { - phpdbg_notice("Set watchpoint on %.*s", (int)param->len, param->str); + phpdbg_notice("watch", "variable=\"%.*s\"", "Set watchpoint on %.*s", (int) param->len, param->str); } break; @@ -991,10 +1148,9 @@ PHPDBG_COMMAND(watch) /* {{{ */ return SUCCESS; } /* }}} */ -int phpdbg_interactive(TSRMLS_D) /* {{{ */ +int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC) /* {{{ */ { int ret = SUCCESS; - char *why = NULL; char *input = NULL; phpdbg_param_t stack; @@ -1007,42 +1163,49 @@ int phpdbg_interactive(TSRMLS_D) /* {{{ */ phpdbg_init_param(&stack, STACK_PARAM); if (phpdbg_do_parse(&stack, input TSRMLS_CC) <= 0) { - switch (ret = phpdbg_stack_execute(&stack, &why TSRMLS_CC)) { + phpdbg_activate_err_buf(1 TSRMLS_CC); + +#ifdef PHP_WIN32 +#define PARA ((phpdbg_param_t *)stack.next)->type + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) { + sigio_watcher_start(); + } +#endif + switch (ret = phpdbg_stack_execute(&stack, allow_async_unsafe TSRMLS_CC)) { case FAILURE: if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - if (phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { - if (why) { - phpdbg_error("%s", why); - } + if (!allow_async_unsafe || phpdbg_call_register(&stack TSRMLS_CC) == FAILURE) { + phpdbg_output_err_buf(NULL, "%b", "%b" TSRMLS_CC); } } - - if (why) { - free(why); - why = NULL; - } break; case PHPDBG_LEAVE: case PHPDBG_FINISH: case PHPDBG_UNTIL: case PHPDBG_NEXT: { - if (!EG(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { - phpdbg_error("Not running"); + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); + if (!PHPDBG_G(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) { + phpdbg_error("command", "type=\"noexec\"", "Not running"); } goto out; } } - } - if (why) { - free(why); - why = NULL; + phpdbg_activate_err_buf(0 TSRMLS_CC); + phpdbg_free_err_buf(TSRMLS_C); +#ifdef PHP_WIN32 + if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE && (RUN_PARAM == PARA || EVAL_PARAM == PARA)) { + sigio_watcher_stop(); + } +#undef PARA +#endif } phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); - + PHPDBG_G(req_id) = 0; } while ((input = phpdbg_read_input(NULL TSRMLS_CC))); } @@ -1050,13 +1213,10 @@ out: if (input) { phpdbg_stack_free(&stack); phpdbg_destroy_input(&input TSRMLS_CC); + PHPDBG_G(req_id) = 0; } - if (why) { - free(why); - } - - if (EG(in_execution)) { + if (PHPDBG_G(in_execution)) { phpdbg_restore_frame(TSRMLS_C); } @@ -1083,138 +1243,45 @@ void phpdbg_clean(zend_bool full TSRMLS_DC) /* {{{ */ } } /* }}} */ -static inline zend_execute_data *phpdbg_create_execute_data(zend_op_array *op_array, zend_bool nested TSRMLS_DC) /* {{{ */ -{ -#if PHP_VERSION_ID >= 50500 - return zend_create_execute_data_from_op_array(op_array, nested TSRMLS_CC); -#else - -#undef EX -#define EX(element) execute_data->element -#undef EX_CV -#define EX_CV(var) EX(CVs)[var] -#undef EX_CVs -#define EX_CVs() EX(CVs) -#undef EX_T -#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset)) -#undef EX_Ts -#define EX_Ts() EX(Ts) - - zend_execute_data *execute_data = (zend_execute_data *)zend_vm_stack_alloc( - ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + - ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)) + - ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T TSRMLS_CC); - - EX(CVs) = (zval***)((char*)execute_data + ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data))); - memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var); - EX(Ts) = (temp_variable *)(((char*)EX(CVs)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2))); - EX(fbc) = NULL; - EX(called_scope) = NULL; - EX(object) = NULL; - EX(old_error_reporting) = NULL; - EX(op_array) = op_array; - EX(symbol_table) = EG(active_symbol_table); - EX(prev_execute_data) = EG(current_execute_data); - EG(current_execute_data) = execute_data; - EX(nested) = nested; - - if (!op_array->run_time_cache && op_array->last_cache_slot) { - op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*)); - } - - if (op_array->this_var != -1 && EG(This)) { - Z_ADDREF_P(EG(This)); /* For $this pointer */ - if (!EG(active_symbol_table)) { - EX_CV(op_array->this_var) = (zval**)EX_CVs() + (op_array->last_var + op_array->this_var); - *EX_CV(op_array->this_var) = EG(This); - } else { - if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX_CV(op_array->this_var))==FAILURE) { - Z_DELREF_P(EG(This)); - } - } - } - - EX(opline) = op_array->opcodes; - EG(opline_ptr) = &EX(opline); - - EX(function_state).function = (zend_function *) op_array; - EX(function_state).arguments = NULL; - - return execute_data; -#endif -} /* }}} */ +#define DO_INTERACTIVE(allow_async_unsafe) do { \ + if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { \ + const char *file_char = zend_get_executed_filename(TSRMLS_C); \ + zend_string *file = zend_string_init(file_char, strlen(file_char), 0); \ + phpdbg_list_file(file, 3, zend_get_executed_lineno(TSRMLS_C)-1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC); \ + efree(file); \ + } \ + \ + switch (phpdbg_interactive(allow_async_unsafe TSRMLS_CC)) { \ + case PHPDBG_LEAVE: \ + case PHPDBG_FINISH: \ + case PHPDBG_UNTIL: \ + case PHPDBG_NEXT:{ \ + goto next; \ + } \ + } \ +} while (0) -#if PHP_VERSION_ID >= 50500 void phpdbg_execute_ex(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ { -#else -void phpdbg_execute_ex(zend_op_array *op_array TSRMLS_DC) /* {{{ */ -{ - long long flags = 0; - zend_ulong address = 0L; - zend_execute_data *execute_data; - zend_bool nested = 0; -#endif - zend_bool original_in_execution = EG(in_execution); + zend_bool original_in_execution = PHPDBG_G(in_execution); HashTable vars; -#if PHP_VERSION_ID < 50500 - if (EG(exception)) { - return; - } -#endif + zend_hash_init(&vars, execute_data->func->op_array.last, NULL, NULL, 0); - EG(in_execution) = 1; - -#if PHP_VERSION_ID >= 50500 - if (0) { -zend_vm_enter: - execute_data = phpdbg_create_execute_data(EG(active_op_array), 1 TSRMLS_CC); - } - zend_hash_init(&vars, EG(active_op_array)->last, NULL, NULL, 0); -#else -zend_vm_enter: - execute_data = phpdbg_create_execute_data(op_array, nested TSRMLS_CC); - nested = 1; - zend_hash_init(&vars, EG(active_op_array)->last, NULL, NULL, 0); -#endif + PHPDBG_G(in_execution) = 1; while (1) { - if ((PHPDBG_G(flags) & PHPDBG_BP_RESOLVE_MASK)) { /* resolve nth opline breakpoints */ - phpdbg_resolve_op_array_breaks(EG(active_op_array) TSRMLS_CC); + phpdbg_resolve_op_array_breaks(&execute_data->func->op_array TSRMLS_CC); } - + #ifdef ZEND_WIN32 if (EG(timed_out)) { zend_timeout(0); } #endif -#define DO_INTERACTIVE() do { \ - if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { \ - phpdbg_list_file( \ - zend_get_executed_filename(TSRMLS_C), \ - 3, \ - zend_get_executed_lineno(TSRMLS_C)-1, \ - zend_get_executed_lineno(TSRMLS_C) \ - TSRMLS_CC \ - ); \ - } \ - \ -/* do { */\ - switch (phpdbg_interactive(TSRMLS_C)) { \ - case PHPDBG_LEAVE: \ - case PHPDBG_FINISH: \ - case PHPDBG_UNTIL: \ - case PHPDBG_NEXT:{ \ - goto next; \ - } \ - } \ -/* } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)); */\ -} while (0) - /* allow conditional breakpoints and initialization to access the vm uninterrupted */ if ((PHPDBG_G(flags) & PHPDBG_IN_COND_BP) || @@ -1232,8 +1299,7 @@ zend_vm_enter: if (PHPDBG_G(flags) & PHPDBG_IN_UNTIL) { if (zend_hash_index_exists(&PHPDBG_G(seek), address)) { PHPDBG_G(flags) &= ~PHPDBG_IN_UNTIL; - zend_hash_clean( - &PHPDBG_G(seek)); + zend_hash_clean(&PHPDBG_G(seek)); } else { /* skip possible breakpoints */ goto next; @@ -1244,8 +1310,7 @@ zend_vm_enter: if (PHPDBG_G(flags) & PHPDBG_IN_FINISH) { if (zend_hash_index_exists(&PHPDBG_G(seek), address)) { PHPDBG_G(flags) &= ~PHPDBG_IN_FINISH; - zend_hash_clean( - &PHPDBG_G(seek)); + zend_hash_clean(&PHPDBG_G(seek)); } /* skip possible breakpoints */ goto next; @@ -1255,14 +1320,12 @@ zend_vm_enter: if (PHPDBG_G(flags) & PHPDBG_IN_LEAVE) { if (zend_hash_index_exists(&PHPDBG_G(seek), address)) { PHPDBG_G(flags) &= ~PHPDBG_IN_LEAVE; - zend_hash_clean( - &PHPDBG_G(seek)); - phpdbg_notice( - "Breaking for leave at %s:%u", + zend_hash_clean(&PHPDBG_G(seek)); + phpdbg_notice("breakpoint", "id=\"leave\" file=\"%s\" line=\"%u\"", "Breaking for leave at %s:%u", zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C) ); - DO_INTERACTIVE(); + DO_INTERACTIVE(1); } else { /* skip possible breakpoints */ goto next; @@ -1271,18 +1334,17 @@ zend_vm_enter: } /* not while in conditionals */ - phpdbg_print_opline_ex( - execute_data, &vars, 0 TSRMLS_CC); + phpdbg_print_opline_ex(execute_data, &vars, 0 TSRMLS_CC); if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING && (PHPDBG_G(flags) & PHPDBG_STEP_OPCODE || execute_data->opline->lineno != PHPDBG_G(last_line))) { PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING; - DO_INTERACTIVE(); + DO_INTERACTIVE(1); } /* check if some watchpoint was hit */ { if (phpdbg_print_changed_zvals(TSRMLS_C) == SUCCESS) { - DO_INTERACTIVE(); + DO_INTERACTIVE(1); } } @@ -1294,42 +1356,82 @@ zend_vm_enter: && (brake = phpdbg_find_breakpoint(execute_data TSRMLS_CC)) && (brake->type != PHPDBG_BREAK_FILE || execute_data->opline->lineno != PHPDBG_G(last_line))) { phpdbg_hit_breakpoint(brake, 1 TSRMLS_CC); - DO_INTERACTIVE(); + DO_INTERACTIVE(1); } } -next: if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) { - phpdbg_writeln(EMPTY); - phpdbg_notice("Program received signal SIGINT"); PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED; - DO_INTERACTIVE(); + + phpdbg_out("\n"); + phpdbg_notice("signal", "type=\"SIGINT\"", "Program received signal SIGINT"); + DO_INTERACTIVE(1); } +next: + PHPDBG_G(last_line) = execute_data->opline->lineno; + /* stupid hack to make zend_do_fcall_common_helper return ZEND_VM_ENTER() instead of recursively calling zend_execute() and eventually segfaulting */ + if (execute_data->opline->opcode == ZEND_DO_FCALL && execute_data->func->type == ZEND_USER_FUNCTION) { + zend_execute_ex = execute_ex; + } PHPDBG_G(vmret) = execute_data->opline->handler(execute_data TSRMLS_CC); + zend_execute_ex = phpdbg_execute_ex; - if (PHPDBG_G(vmret) > 0) { - switch (PHPDBG_G(vmret)) { - case 1: - EG(in_execution) = original_in_execution; - zend_hash_destroy(&vars); - return; - case 2: -#if PHP_VERSION_ID < 50500 - op_array = EG(active_op_array); -#endif - zend_hash_destroy(&vars); - goto zend_vm_enter; - break; - case 3: - execute_data = EG(current_execute_data); - break; - default: - break; + if (PHPDBG_G(vmret) != 0) { + if (PHPDBG_G(vmret) < 0) { + zend_hash_destroy(&vars); + PHPDBG_G(in_execution) = original_in_execution; + return; + } else { + execute_data = EG(current_execute_data); } } } zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen"); } /* }}} */ + +/* only if *not* interactive and while executing */ +void phpdbg_force_interruption(TSRMLS_D) { + zend_execute_data *data = EG(current_execute_data); /* should be always readable if not NULL */ + + PHPDBG_G(flags) |= PHPDBG_IN_SIGNAL_HANDLER; + + if (data) { + if (data->func) { + phpdbg_notice("hardinterrupt", "opline=\"%p\" num=\"%lu\" file=\"%s\" line=\"%u\"", "Current opline: %p (op #%lu) in %s:%u", data->opline, (data->opline - data->func->op_array.opcodes) / sizeof(data->opline), data->func->op_array.filename, data->opline->lineno); + } else { + phpdbg_notice("hardinterrupt", "opline=\"%p\"", "Current opline: %p (op_array information unavailable)", data->opline); + } + } else { + phpdbg_notice("hardinterrupt", "", "No information available about executing context"); + } + + DO_INTERACTIVE(0); + +next: + PHPDBG_G(flags) &= ~PHPDBG_IN_SIGNAL_HANDLER; + + if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) { + zend_bailout(); + } +} + +PHPDBG_COMMAND(eol) /* {{{ */ +{ + if (!param || param->type == EMPTY_PARAM) { + phpdbg_notice("eol", "argument required", "argument required"); + } else switch (param->type) { + case STR_PARAM: + if (FAILURE == phpdbg_eol_global_update(param->str TSRMLS_CC)) { + phpdbg_notice("eol", "unknown EOL name '%s', give crlf, lf, cr", "unknown EOL name '%s', give crlf, lf, cr", param->str); + } + break; + + phpdbg_default_switch_case(); + } + + return SUCCESS; +} /* }}} */ + diff --git a/sapi/phpdbg/phpdbg_prompt.h b/sapi/phpdbg/phpdbg_prompt.h index 0bd03f03bb..94e24df833 100644 --- a/sapi/phpdbg/phpdbg_prompt.h +++ b/sapi/phpdbg/phpdbg_prompt.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -24,9 +24,11 @@ /* {{{ */ void phpdbg_init(char *init_file, size_t init_file_len, zend_bool use_default TSRMLS_DC); void phpdbg_try_file_init(char *init_file, size_t init_file_len, zend_bool free_init TSRMLS_DC); -int phpdbg_interactive(TSRMLS_D); +int phpdbg_interactive(zend_bool allow_async_unsafe TSRMLS_DC); int phpdbg_compile(TSRMLS_D); -void phpdbg_clean(zend_bool full TSRMLS_DC); /* }}} */ +void phpdbg_clean(zend_bool full TSRMLS_DC); +void phpdbg_force_interruption(TSRMLS_D); +/* }}} */ /* {{{ phpdbg command handlers */ PHPDBG_COMMAND(exec); @@ -47,12 +49,15 @@ PHPDBG_COMMAND(clean); PHPDBG_COMMAND(clear); PHPDBG_COMMAND(help); PHPDBG_COMMAND(sh); +PHPDBG_COMMAND(dl); PHPDBG_COMMAND(set); PHPDBG_COMMAND(source); PHPDBG_COMMAND(export); PHPDBG_COMMAND(register); PHPDBG_COMMAND(quit); -PHPDBG_COMMAND(watch); /* }}} */ +PHPDBG_COMMAND(watch); +PHPDBG_COMMAND(eol); +PHPDBG_COMMAND(wait); /* }}} */ /* {{{ prompt commands */ extern const phpdbg_command_t phpdbg_prompt_commands[]; /* }}} */ diff --git a/sapi/phpdbg/phpdbg_rinit_hook.c b/sapi/phpdbg/phpdbg_rinit_hook.c new file mode 100644 index 0000000000..1bf891654d --- /dev/null +++ b/sapi/phpdbg/phpdbg_rinit_hook.c @@ -0,0 +1,101 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg_rinit_hook.h" +#include "php_ini.h" +#include <errno.h> + +ZEND_DECLARE_MODULE_GLOBALS(phpdbg_webhelper); + +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("phpdbg.auth", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, auth, zend_phpdbg_webhelper_globals, phpdbg_webhelper_globals) + STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, path, zend_phpdbg_webhelper_globals, phpdbg_webhelper_globals) +PHP_INI_END() + +static inline void php_phpdbg_webhelper_globals_ctor(zend_phpdbg_webhelper_globals *pg) /* {{{ */ +{ +} /* }}} */ + +static PHP_MINIT_FUNCTION(phpdbg_webhelper) /* {{{ */ +{ + if (!strcmp(sapi_module.name, PHPDBG_NAME)) { + return SUCCESS; + } + + ZEND_INIT_MODULE_GLOBALS(phpdbg_webhelper, php_phpdbg_webhelper_globals_ctor, NULL); + REGISTER_INI_ENTRIES(); + + return SUCCESS; +} /* }}} */ + +static PHP_RINIT_FUNCTION(phpdbg_webhelper) /* {{{ */ +{ + zval cookies = PG(http_globals)[TRACK_VARS_COOKIE]; + zval *auth; + + if (Z_TYPE(cookies) == IS_ARRAY || (auth = zend_hash_str_find(Z_ARRVAL(cookies), PHPDBG_NAME "_AUTH_COOKIE", sizeof(PHPDBG_NAME "_AUTH_COOKIE"))) || Z_STRLEN_P(auth) != strlen(PHPDBG_WG(auth)) || strcmp(Z_STRVAL_P(auth), PHPDBG_WG(auth))) { + return SUCCESS; + } + +#ifndef _WIN32 + { + struct sockaddr_un sock; + int s = socket(AF_UNIX, SOCK_STREAM, 0); + int len = strlen(PHPDBG_WG(path)) + sizeof(sock.sun_family); + char buf[(1 << 8) + 1]; + int buflen; + sock.sun_family = AF_UNIX; + strcpy(sock.sun_path, PHPDBG_WG(path)); + + if (connect(s, (struct sockaddr *)&sock, len) == -1) { + zend_error(E_ERROR, "Unable to connect to UNIX domain socket at %s defined by phpdbg.path ini setting. Reason: %s", PHPDBG_WG(path), strerror(errno)); + } + + char *msg = NULL; + char msglen[5] = {0}; + phpdbg_webdata_compress(&msg, (int *)msglen TSRMLS_CC); + + send(s, msglen, 4, 0); + send(s, msg, *(int *) msglen, 0); + + while ((buflen = recv(s, buf, sizeof(buf) - 1, 0)) > 0) { + php_write(buf, buflen TSRMLS_CC); + } + + close(s); + + php_output_flush_all(TSRMLS_C); + zend_bailout(); + } +#endif + + return SUCCESS; +} /* }}} */ + +zend_module_entry phpdbg_webhelper_module_entry = { + STANDARD_MODULE_HEADER, + "phpdbg_webhelper", + NULL, + PHP_MINIT(phpdbg_webhelper), + NULL, + PHP_RINIT(phpdbg_webhelper), + NULL, + NULL, + PHPDBG_VERSION, + STANDARD_MODULE_PROPERTIES +}; diff --git a/sapi/phpdbg/phpdbg_rinit_hook.h b/sapi/phpdbg/phpdbg_rinit_hook.h new file mode 100644 index 0000000000..d28be10f8c --- /dev/null +++ b/sapi/phpdbg/phpdbg_rinit_hook.h @@ -0,0 +1,41 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena <felipe@php.net> | + | Authors: Joe Watkins <joe.watkins@live.co.uk> | + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_WEBHELPER_H +#define PHPDBG_WEBHELPER_H + +#include "phpdbg_webdata_transfer.h" + +extern zend_module_entry phpdbg_webhelper_module_entry; +#define phpext_phpdbg_webhelper_ptr &phpdbg_webhelper_module_entry + +#ifdef ZTS +# define PHPDBG_WG(v) TSRMG(phpdbg_webhelper_globals_id, zend_phpdbg_webhelper_globals *, v) +#else +# define PHPDBG_WG(v) (phpdbg_webhelper_globals.v) +#endif + +/* {{{ structs */ +ZEND_BEGIN_MODULE_GLOBALS(phpdbg_webhelper) + char *auth; + char *path; +ZEND_END_MODULE_GLOBALS(phpdbg_webhelper) /* }}} */ + +#endif /* PHPDBG_WEBHELPER_H */ diff --git a/sapi/phpdbg/phpdbg_set.c b/sapi/phpdbg/phpdbg_set.c index 3d3eced705..82b9f69f7a 100644 --- a/sapi/phpdbg/phpdbg_set.c +++ b/sapi/phpdbg/phpdbg_set.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -27,30 +27,32 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -#define PHPDBG_SET_COMMAND_D(f, h, a, m, l, s) \ - PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[18]) +#define PHPDBG_SET_COMMAND_D(f, h, a, m, l, s, flags) \ + PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[18], flags) const phpdbg_command_t phpdbg_set_commands[] = { - PHPDBG_SET_COMMAND_D(prompt, "usage: set prompt [<string>]", 'p', set_prompt, NULL, "|s"), + PHPDBG_SET_COMMAND_D(prompt, "usage: set prompt [<string>]", 'p', set_prompt, NULL, "|s", 0), #ifndef _WIN32 - PHPDBG_SET_COMMAND_D(color, "usage: set color <element> <color>", 'c', set_color, NULL, "ss"), - PHPDBG_SET_COMMAND_D(colors, "usage: set colors [<on|off>]", 'C', set_colors, NULL, "|b"), + PHPDBG_SET_COMMAND_D(color, "usage: set color <element> <color>", 'c', set_color, NULL, "ss", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(colors, "usage: set colors [<on|off>]", 'C', set_colors, NULL, "|b", PHPDBG_ASYNC_SAFE), #endif - PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog [<output>]", 'O', set_oplog, NULL, "|s"), - PHPDBG_SET_COMMAND_D(break, "usage: set break id [<on|off>]", 'b', set_break, NULL, "l|b"), - PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks [<on|off>]", 'B', set_breaks, NULL, "|b"), - PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet [<on|off>]", 'q', set_quiet, NULL, "|b"), - PHPDBG_SET_COMMAND_D(stepping, "usage: set stepping [<line|op>]", 's', set_stepping, NULL, "|s"), - PHPDBG_SET_COMMAND_D(refcount, "usage: set refcount [<on|off>]", 'r', set_refcount, NULL, "|b"), + PHPDBG_SET_COMMAND_D(oplog, "usage: set oplog [<output>]", 'O', set_oplog, NULL, "|s", 0), + PHPDBG_SET_COMMAND_D(break, "usage: set break id [<on|off>]", 'b', set_break, NULL, "l|b", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(breaks, "usage: set breaks [<on|off>]", 'B', set_breaks, NULL, "|b", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(quiet, "usage: set quiet [<on|off>]", 'q', set_quiet, NULL, "|b", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(stepping, "usage: set stepping [<line|op>]", 's', set_stepping, NULL, "|s", PHPDBG_ASYNC_SAFE), + PHPDBG_SET_COMMAND_D(refcount, "usage: set refcount [<on|off>]", 'r', set_refcount, NULL, "|b", PHPDBG_ASYNC_SAFE), PHPDBG_END_COMMAND }; PHPDBG_SET(prompt) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("%s", phpdbg_get_prompt(TSRMLS_C)); - } else phpdbg_set_prompt(param->str TSRMLS_CC); - + phpdbg_writeln("setprompt", "str=\"%s\"", "Current prompt: %s", phpdbg_get_prompt(TSRMLS_C)); + } else { + phpdbg_set_prompt(param->str TSRMLS_CC); + } + return SUCCESS; } /* }}} */ @@ -61,21 +63,21 @@ PHPDBG_SET(break) /* {{{ */ if (param->next) { if (param->next->num) { phpdbg_enable_breakpoint(param->num TSRMLS_CC); - } else phpdbg_disable_breakpoint(param->num TSRMLS_CC); + } else { + phpdbg_disable_breakpoint(param->num TSRMLS_CC); + } } else { phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num TSRMLS_CC); if (brake) { - phpdbg_writeln( - "%s", brake->disabled ? "off" : "on"); + phpdbg_writeln("setbreak", "id=\"%ld\" active=\"%s\"", "Breakpoint #%ld %s", param->num, brake->disabled ? "off" : "on"); } else { - phpdbg_error("Failed to find breakpoint #%ld", param->num); + phpdbg_error("setbreak", "type=\"nobreak\" id=\"%ld\"", "Failed to find breakpoint #%ld", param->num); } } } break; default: - phpdbg_error( - "set break used incorrectly: set break [id] <on|off>"); + phpdbg_error("setbreak", "type=\"wrongargs\"", "set break used incorrectly: set break [id] <on|off>"); } return SUCCESS; @@ -84,18 +86,18 @@ PHPDBG_SET(break) /* {{{ */ PHPDBG_SET(breaks) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("%s", - PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off"); - } else switch (param->type) { + phpdbg_writeln("setbreaks", "active=\"%s\"", "Breakpoints %s",PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off"); + } else switch (param->type) { case NUMERIC_PARAM: { if (param->num) { phpdbg_enable_breakpoints(TSRMLS_C); - } else phpdbg_disable_breakpoints(TSRMLS_C); + } else { + phpdbg_disable_breakpoints(TSRMLS_C); + } } break; default: - phpdbg_error( - "set break used incorrectly: set break [id] <on|off>"); + phpdbg_error("setbreaks", "type=\"wrongargs\"", "set breaks used incorrectly: set breaks <on|off>"); } return SUCCESS; @@ -104,41 +106,35 @@ PHPDBG_SET(breaks) /* {{{ */ #ifndef _WIN32 PHPDBG_SET(color) /* {{{ */ { - const phpdbg_color_t *color = phpdbg_get_color( - param->next->str, param->next->len TSRMLS_CC); - + const phpdbg_color_t *color = phpdbg_get_color(param->next->str, param->next->len TSRMLS_CC); + if (!color) { - phpdbg_error( - "Failed to find the requested color (%s)", param->next->str); + phpdbg_error("setcolor", "type=\"nocolor\"", "Failed to find the requested color (%s)", param->next->str); return SUCCESS; } - + switch (phpdbg_get_element(param->str, param->len TSRMLS_CC)) { case PHPDBG_COLOR_PROMPT: - phpdbg_notice( - "setting prompt color to %s (%s)", color->name, color->code); + phpdbg_notice("setcolor", "type=\"prompt\" color=\"%s\" code=\"%s\"", "setting prompt color to %s (%s)", color->name, color->code); if (PHPDBG_G(prompt)[1]) { free(PHPDBG_G(prompt)[1]); PHPDBG_G(prompt)[1]=NULL; } phpdbg_set_color(PHPDBG_COLOR_PROMPT, color TSRMLS_CC); break; - + case PHPDBG_COLOR_ERROR: - phpdbg_notice( - "setting error color to %s (%s)", color->name, color->code); + phpdbg_notice("setcolor", "type=\"error\" color=\"%s\" code=\"%s\"", "setting error color to %s (%s)", color->name, color->code); phpdbg_set_color(PHPDBG_COLOR_ERROR, color TSRMLS_CC); break; - + case PHPDBG_COLOR_NOTICE: - phpdbg_notice( - "setting notice color to %s (%s)", color->name, color->code); + phpdbg_notice("setcolor", "type=\"notice\" color=\"%s\" code=\"%s\"", "setting notice color to %s (%s)", color->name, color->code); phpdbg_set_color(PHPDBG_COLOR_NOTICE, color TSRMLS_CC); break; - + default: - phpdbg_error( - "Failed to find the requested element (%s)", param->str); + phpdbg_error("setcolor", "type=\"invalidtype\"", "Failed to find the requested element (%s)", param->str); } return SUCCESS; @@ -147,7 +143,7 @@ PHPDBG_SET(color) /* {{{ */ PHPDBG_SET(colors) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("%s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off"); + phpdbg_writeln("setcolors", "active=\"%s\"", "Colors %s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off"); } else switch (param->type) { case NUMERIC_PARAM: { if (param->num) { @@ -156,10 +152,9 @@ PHPDBG_SET(colors) /* {{{ */ PHPDBG_G(flags) &= ~PHPDBG_IS_COLOURED; } } break; - + default: - phpdbg_error( - "set colors used incorrectly: set colors <on|off>"); + phpdbg_error("setcolors", "type=\"wrongargs\"", "set colors used incorrectly: set colors <on|off>"); } return SUCCESS; @@ -169,7 +164,7 @@ PHPDBG_SET(colors) /* {{{ */ PHPDBG_SET(oplog) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_notice("Oplog %s", PHPDBG_G(oplog) ? "enabled" : "disabled"); + phpdbg_notice("setoplog", "active=\"%s\"", "Oplog %s", PHPDBG_G(oplog) ? "on" : "off"); } else switch (param->type) { case STR_PARAM: { /* open oplog */ @@ -177,14 +172,15 @@ PHPDBG_SET(oplog) /* {{{ */ PHPDBG_G(oplog) = fopen(param->str, "w+"); if (!PHPDBG_G(oplog)) { - phpdbg_error("Failed to open %s for oplog", param->str); + phpdbg_error("setoplog", "type=\"openfailure\" file=\"%s\"", "Failed to open %s for oplog", param->str); PHPDBG_G(oplog) = old; } else { if (old) { - phpdbg_notice("Closing previously open oplog"); + phpdbg_notice("setoplog", "type=\"closingold\"", "Closing previously open oplog"); fclose(old); } - phpdbg_notice("Successfully opened oplog %s", param->str); + + phpdbg_notice("setoplog", "file=\"%s\"", "Successfully opened oplog %s", param->str); } } break; @@ -197,8 +193,7 @@ PHPDBG_SET(oplog) /* {{{ */ PHPDBG_SET(quiet) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("Quietness %s", - PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); + phpdbg_writeln("setquiet", "active=\"%s\"", "Quietness %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); } else switch (param->type) { case NUMERIC_PARAM: { if (param->num) { @@ -217,18 +212,15 @@ PHPDBG_SET(quiet) /* {{{ */ PHPDBG_SET(stepping) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("Stepping %s", - PHPDBG_G(flags) & PHPDBG_STEP_OPCODE ? "opcode" : "line"); + phpdbg_writeln("setstepping", "type=\"%s\"", "Stepping %s", PHPDBG_G(flags) & PHPDBG_STEP_OPCODE ? "opcode" : "line"); } else switch (param->type) { - case STR_PARAM: { - if ((param->len == sizeof("opcode")-1) && - (memcmp(param->str, "opcode", sizeof("opcode")) == SUCCESS)) { + case STR_PARAM: { + if (param->len == sizeof("opcode") - 1 && !memcmp(param->str, "opcode", sizeof("opcode"))) { PHPDBG_G(flags) |= PHPDBG_STEP_OPCODE; - } else if ((param->len == sizeof("line")-1) && - (memcmp(param->str, "line", sizeof("line")) == SUCCESS)) { + } else if (param->len == sizeof("line") - 1 && !memcmp(param->str, "line", sizeof("line"))) { PHPDBG_G(flags) &= ~PHPDBG_STEP_OPCODE; } else { - phpdbg_error("usage set stepping [<opcode|line>]"); + phpdbg_error("setstepping", "type=\"wrongargs\"", "usage set stepping [<opcode|line>]"); } } break; @@ -241,7 +233,7 @@ PHPDBG_SET(stepping) /* {{{ */ PHPDBG_SET(refcount) /* {{{ */ { if (!param || param->type == EMPTY_PARAM) { - phpdbg_writeln("Refcount %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); + phpdbg_writeln("setrefcount", "active=\"%s\"", "Showing refcounts %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off"); } else switch (param->type) { case NUMERIC_PARAM: { if (param->num) { diff --git a/sapi/phpdbg/phpdbg_set.h b/sapi/phpdbg/phpdbg_set.h index 18618cd007..dea61ed382 100644 --- a/sapi/phpdbg/phpdbg_set.h +++ b/sapi/phpdbg/phpdbg_set.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ diff --git a/sapi/phpdbg/phpdbg_sigio_win32.c b/sapi/phpdbg/phpdbg_sigio_win32.c new file mode 100644 index 0000000000..24e9ac0e0a --- /dev/null +++ b/sapi/phpdbg/phpdbg_sigio_win32.c @@ -0,0 +1,120 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 7-4 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + + +#include <signal.h> + +#include "phpdbg.h" +#include "phpdbg_sigio_win32.h" + + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + + +VOID +SigIoWatcherThread(VOID *p) +{ + zend_uchar sig; + struct win32_sigio_watcher_data *swd = (struct win32_sigio_watcher_data *)p; +#ifdef ZTS + void ***tsrm_ls = swd->tsrm_ls; +top: + (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1, tsrm_ls); +#else +top: + (void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1); +#endif + + + if (3 == sig) { + printf("signaled, got %d", sig); + /* XXX completely not sure it is done right here */ + if (swd->flags & PHPDBG_IS_INTERACTIVE) { + if (raise(sig)) { + /* just out*/ + exit(0); + } + } + if (swd->flags & PHPDBG_IS_SIGNALED) { + phpdbg_set_sigsafe_mem(&sig TSRMLS_CC); + zend_try { + phpdbg_force_interruption(TSRMLS_C); + } zend_end_try(); + phpdbg_clear_sigsafe_mem(TSRMLS_C); + } + /* XXX set signaled flag to the caller thread, question is - whether it's needed */ + ExitThread(sig); + } else { + goto top; + } +} + + +/* Start this only for the time of the run or eval command, +for so long that the main thread is busy serving some debug +session. */ +void +sigio_watcher_start(void) +{ + TSRMLS_FETCH(); + + PHPDBG_G(swd).fd = PHPDBG_G(io)[PHPDBG_STDIN].fd; + PHPDBG_G(swd).running = 1; + PHPDBG_G(swd).flags = PHPDBG_G(flags); +#ifdef ZTS + PHPDBG_G(swd).tsrm_ls = tsrm_ls; +#endif + + PHPDBG_G(sigio_watcher_thread) = CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)SigIoWatcherThread, + &PHPDBG_G(swd), + 0, + NULL); +} + +void +sigio_watcher_stop(void) +{ + DWORD waited; + TSRMLS_FETCH(); + + if (INVALID_HANDLE_VALUE == PHPDBG_G(sigio_watcher_thread)) { + /* it probably did bail out already */ + return; + } + + waited = WaitForSingleObject(PHPDBG_G(sigio_watcher_thread), 300); + + if (WAIT_OBJECT_0 != waited) { + if (!CancelSynchronousIo(PHPDBG_G(sigio_watcher_thread))) { + /* error out */ + } + + if (!TerminateThread(PHPDBG_G(sigio_watcher_thread), 0)) { + /* error out */ + } + } + + PHPDBG_G(swd).fd = -1; + PHPDBG_G(swd).running = 0; + PHPDBG_G(swd).flags = 0; + PHPDBG_G(sigio_watcher_thread) = INVALID_HANDLE_VALUE; +} + diff --git a/sapi/phpdbg/phpdbg_sigio_win32.h b/sapi/phpdbg/phpdbg_sigio_win32.h new file mode 100644 index 0000000000..796b477f93 --- /dev/null +++ b/sapi/phpdbg/phpdbg_sigio_win32.h @@ -0,0 +1,42 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 7-4 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + + +#ifndef PHPDBG_SIGIO_WIN32_H +#define PHPDBG_SIGIO_WIN32_H + +#include "phpdbg.h" +#include "phpdbg_prompt.h" +#include "phpdbg_io.h" + +struct win32_sigio_watcher_data { + zend_ulong flags; +#ifdef ZTS + void ***tsrm_ls; +#endif + int fd; + zend_uchar running; +}; + +void +sigio_watcher_start(void); + +void +sigio_watcher_stop(void); + +#endif /* PHPDBG_SIGIO_WIN32_H */ diff --git a/sapi/phpdbg/phpdbg_sigsafe.c b/sapi/phpdbg/phpdbg_sigsafe.c new file mode 100644 index 0000000000..1ca7bf230c --- /dev/null +++ b/sapi/phpdbg/phpdbg_sigsafe.c @@ -0,0 +1,56 @@ +#include "phpdbg_sigsafe.h" +#include "phpdbg.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); + +#define STR(x) #x +#define EXP_STR(x) STR(x) + +static void* zend_mm_mem_alloc(zend_mm_storage *storage, size_t size, size_t alignment) { + TSRMLS_FETCH(); + + if (EXPECTED(size == PHPDBG_SIGSAFE_MEM_SIZE && !PHPDBG_G(sigsafe_mem).allocated)) { + PHPDBG_G(sigsafe_mem).allocated = 1; + return PHPDBG_G(sigsafe_mem).mem; + } + + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Tried to allocate more than " EXP_STR(PHPDBG_SIGSAFE_MEM_SIZE) " bytes from stack memory in signal handler ... bailing out of signal handler\n")); + + if (*EG(bailout)) { + LONGJMP(*EG(bailout), FAILURE); + } + + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("Bailed out without a bailout address in signal handler!\n")); + + return NULL; +} + +static void zend_mm_mem_free(zend_mm_storage *storage, void *ptr, size_t size) { +} + +void phpdbg_set_sigsafe_mem(char *buffer TSRMLS_DC) { + phpdbg_signal_safe_mem *mem = &PHPDBG_G(sigsafe_mem); + mem->mem = buffer; + mem->allocated = 0; + + mem->storage.chunk_alloc = zend_mm_mem_alloc; + mem->storage.chunk_free = zend_mm_mem_free; + + mem->heap = zend_mm_startup_ex(&mem->storage); + + mem->old_heap = zend_mm_set_heap(mem->heap TSRMLS_CC); +} + +zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D) { + return PHPDBG_G(sigsafe_mem).old_heap; +} + +void phpdbg_clear_sigsafe_mem(TSRMLS_D) { + zend_mm_set_heap(phpdbg_original_heap_sigsafe_mem(TSRMLS_C) TSRMLS_CC); + PHPDBG_G(sigsafe_mem).mem = NULL; +} + +zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D) { + return !!PHPDBG_G(sigsafe_mem).mem; +} + diff --git a/sapi/phpdbg/phpdbg_sigsafe.h b/sapi/phpdbg/phpdbg_sigsafe.h new file mode 100644 index 0000000000..9ef723fdca --- /dev/null +++ b/sapi/phpdbg/phpdbg_sigsafe.h @@ -0,0 +1,28 @@ +#ifndef PHPDBG_SIGSAFE_H +#define PHPDBG_SIGSAFE_H + +//#include "zend_mm_structs.h" + +#define PHPDBG_SIGSAFE_MEM_SIZE ZEND_MM_CHUNK_SIZE +//(1 << 20) + +#include "zend.h" + +typedef struct { + char *mem; + zend_bool allocated; + zend_mm_heap *heap; + zend_mm_heap *old_heap; + zend_mm_storage storage; +} phpdbg_signal_safe_mem; + +#include "phpdbg.h" + +zend_bool phpdbg_active_sigsafe_mem(TSRMLS_D); + +void phpdbg_set_sigsafe_mem(char *mem TSRMLS_DC); +void phpdbg_clear_sigsafe_mem(TSRMLS_D); + +zend_mm_heap *phpdbg_original_heap_sigsafe_mem(TSRMLS_D); + +#endif diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c index b57986b55c..bff971d4cf 100644 --- a/sapi/phpdbg/phpdbg_utils.c +++ b/sapi/phpdbg/phpdbg_utils.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -18,19 +18,14 @@ +----------------------------------------------------------------------+ */ -#include <stdio.h> -#include <ctype.h> -#include <string.h> #include "zend.h" + #include "php.h" -#include "spprintf.h" #include "phpdbg.h" #include "phpdbg_opcode.h" #include "phpdbg_utils.h" -#ifdef _WIN32 -# include "win32/time.h" -#elif defined(HAVE_SYS_IOCTL_H) +#if defined(HAVE_SYS_IOCTL_H) # include "sys/ioctl.h" # ifndef GWINSZ_IN_SYS_IOCTL # include <termios.h> @@ -128,12 +123,12 @@ PHPDBG_API int phpdbg_is_class_method(const char *str, size_t len, char **class, } if (class != NULL) { - + if (str[0] == '\\') { str++; len--; } - + *class = estrndup(str, sep - str); (*class)[sep - str] = 0; } @@ -170,27 +165,25 @@ PHPDBG_API const char *phpdbg_current_file(TSRMLS_D) /* {{{ */ PHPDBG_API const zend_function *phpdbg_get_function(const char *fname, const char *cname TSRMLS_DC) /* {{{ */ { zend_function *func = NULL; - size_t fname_len = strlen(fname); - char *lcname = zend_str_tolower_dup(fname, fname_len); + zend_string *lfname = zend_string_alloc(strlen(fname), 0); + memcpy(lfname->val, zend_str_tolower_dup(fname, lfname->len), lfname->len + 1); if (cname) { - zend_class_entry **ce; - size_t cname_len = strlen(cname); - char *lc_cname = zend_str_tolower_dup(cname, cname_len); - int ret = zend_lookup_class(lc_cname, cname_len, &ce TSRMLS_CC); + zend_class_entry *ce; + zend_string *lcname = zend_string_alloc(strlen(cname), 0); + memcpy(lcname->val, zend_str_tolower_dup(cname, lcname->len), lcname->len + 1); + ce = zend_lookup_class(lcname TSRMLS_CC); - efree(lc_cname); + efree(lcname); - if (ret == SUCCESS) { - zend_hash_find(&(*ce)->function_table, lcname, fname_len+1, - (void**)&func); + if (ce) { + func = zend_hash_find_ptr(&ce->function_table, lfname); } } else { - zend_hash_find(EG(function_table), lcname, fname_len+1, - (void**)&func); + func = zend_hash_find_ptr(EG(function_table), lfname); } - efree(lcname); + efree(lfname); return func; } /* }}} */ @@ -224,103 +217,6 @@ PHPDBG_API char *phpdbg_trim(const char *str, size_t len, size_t *new_len) /* {{ } /* }}} */ -PHPDBG_API int phpdbg_print(int type TSRMLS_DC, FILE *fp, const char *format, ...) /* {{{ */ -{ - int rc = 0; - char *buffer = NULL; - va_list args; - - if (format != NULL && strlen(format) > 0L) { - va_start(args, format); - vspprintf(&buffer, 0, format, args); - va_end(args); - } - - /* TODO(anyone) colours */ - - switch (type) { - case P_ERROR: - if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { - rc = fprintf(fp, - "\033[%sm[%s]\033[0m\n", - PHPDBG_G(colors)[PHPDBG_COLOR_ERROR]->code, buffer); - } else { - rc = fprintf(fp, "[%s]\n", buffer); - } - break; - - case P_NOTICE: - if (PHPDBG_G(flags) & PHPDBG_IS_COLOURED) { - rc = fprintf(fp, - "\033[%sm[%s]\033[0m\n", - PHPDBG_G(colors)[PHPDBG_COLOR_NOTICE]->code, buffer); - } else { - rc = fprintf(fp, "[%s]\n", buffer); - } - break; - - case P_WRITELN: { - if (buffer) { - rc = fprintf(fp, "%s\n", buffer); - } else { - rc = fprintf(fp, "\n"); - } - } break; - - case P_WRITE: - if (buffer) { - rc = fprintf(fp, "%s", buffer); - } - break; - - /* no formatting on logging output */ - case P_LOG: - if (buffer) { - struct timeval tp; - if (gettimeofday(&tp, NULL) == SUCCESS) { - rc = fprintf(fp, "[%ld %.8F]: %s\n", tp.tv_sec, tp.tv_usec / 1000000.00, buffer); - } else { - rc = FAILURE; - } - } - break; - } - - if (buffer) { - efree(buffer); - } - - return rc; -} /* }}} */ - -PHPDBG_API int phpdbg_rlog(FILE *fp, const char *fmt, ...) { /* {{{ */ - int rc = 0; - - va_list args; - struct timeval tp; - - va_start(args, fmt); - if (gettimeofday(&tp, NULL) == SUCCESS) { - char friendly[100]; - char *format = NULL, *buffer = NULL; - const time_t tt = tp.tv_sec; - - strftime(friendly, 100, "%a %b %d %T.%%04d %Y", localtime(&tt)); - asprintf( - &buffer, friendly, tp.tv_usec/1000); - asprintf( - &format, "[%s]: %s\n", buffer, fmt); - rc = vfprintf( - fp, format, args); - - free(format); - free(buffer); - } - va_end(args); - - return rc; -} /* }}} */ - PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC) /* {{{ */ { const phpdbg_color_t *color = colors; @@ -328,15 +224,13 @@ PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_ while (color && color->name) { if (name_length == color->name_length && memcmp(name, color->name, name_length) == SUCCESS) { - phpdbg_debug( - "phpdbg_get_color(%s, %lu): %s", name, name_length, color->code); + phpdbg_debug("phpdbg_get_color(%s, %lu): %s", name, name_length, color->code); return color; } ++color; } - phpdbg_debug( - "phpdbg_get_color(%s, %lu): failed", name, name_length); + phpdbg_debug("phpdbg_get_color(%s, %lu): failed", name, name_length); return NULL; } /* }}} */ @@ -362,7 +256,7 @@ PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D) /* {{{ */ PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC) { const phpdbg_element_t *element = elements; - + while (element && element->name) { if (len == element->name_length) { if (strncasecmp(name, element->name, len) == SUCCESS) { @@ -371,7 +265,7 @@ PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC) { } element++; } - + return PHPDBG_COLOR_INVALID; } @@ -419,18 +313,14 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */ } /* }}} */ int phpdbg_rebuild_symtable(TSRMLS_D) { - if (!EG(active_op_array)) { - phpdbg_error("No active op array!"); + if (!EG(current_execute_data) || !EG(current_execute_data)->func) { + phpdbg_error("inactive", "type=\"op_array\"", "No active op array!"); return FAILURE; } - if (!EG(active_symbol_table)) { - zend_rebuild_symbol_table(TSRMLS_C); - - if (!EG(active_symbol_table)) { - phpdbg_error("No active symbol table!"); - return FAILURE; - } + if (!zend_rebuild_symbol_table(TSRMLS_C)) { + phpdbg_error("inactive", "type=\"symbol_table\"", "No active symbol table!"); + return FAILURE; } return SUCCESS; @@ -438,13 +328,13 @@ int phpdbg_rebuild_symtable(TSRMLS_D) { PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */ { - int columns; + int columns; #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); columns = csbi.srWindow.Right - csbi.srWindow.Left + 1; -#elif defined(HAVE_SYS_IOCTL_H) && defined (TIOCGWINSZ) +#elif defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) struct winsize w; columns = ioctl(fileno(stdout), TIOCGWINSZ, &w) == 0 ? w.ws_col : 80; @@ -453,3 +343,328 @@ PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D) /* {{{ */ #endif return columns; } /* }}} */ + +PHPDBG_API void phpdbg_set_async_io(int fd) { +#ifndef _WIN32 + int flags; + fcntl(STDIN_FILENO, F_SETOWN, getpid()); + flags = fcntl(STDIN_FILENO, F_GETFL); + fcntl(STDIN_FILENO, F_SETFL, flags | FASYNC); +#endif +} + +int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry **ce TSRMLS_DC) { + if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { + char *lc_name, *lc_free; + int lc_length; + + if (name == NULL || !name_length) { + return FAILURE; + } + + lc_free = lc_name = emalloc(name_length + 1); + zend_str_tolower_copy(lc_name, name, name_length); + lc_length = name_length + 1; + + if (lc_name[0] == '\\') { + lc_name += 1; + lc_length -= 1; + } + + phpdbg_try_access { + *ce = zend_hash_str_find_ptr(EG(class_table), lc_name, lc_length); + } phpdbg_catch_access { + phpdbg_error("signalsegv", "class=\"%.*s\"", "Could not fetch class %.*s, invalid data source", name_length, name); + } phpdbg_end_try_access(); + + efree(lc_free); + } else { + zend_string *str_name = zend_string_init(name, name_length, 0); + *ce = zend_lookup_class(str_name TSRMLS_CC); + efree(str_name); + } + + return ce ? SUCCESS : FAILURE; +} + +char *phpdbg_get_property_key(char *key) { + if (*key != 0) { + return key; + } + return strchr(key + 1, 0) + 1; +} + +static int phpdbg_parse_variable_arg_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv, phpdbg_parse_var_func callback TSRMLS_DC) { + return callback(name, len, keyname, keylen, parent, zv TSRMLS_CC); +} + +PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC) { + return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_parse_variable_arg_wrapper, silent, callback TSRMLS_CC); +} + +PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC) { + int ret = FAILURE; + zend_bool new_index = 1; + char *last_index; + size_t index_len = 0; + zval *zv; + + if (len < 2 || *input != '$') { + goto error; + } + + while (i++ < len) { + if (i == len) { + new_index = 1; + } else { + switch (input[i]) { + case '[': + new_index = 1; + break; + case ']': + break; + case '>': + if (last_index[index_len - 1] == '-') { + new_index = 1; + index_len--; + } + break; + + default: + if (new_index) { + last_index = input + i; + new_index = 0; + } + if (input[i - 1] == ']') { + goto error; + } + index_len++; + } + } + + if (new_index && index_len == 0) { + zend_ulong numkey; + zend_string *strkey; + ZEND_HASH_FOREACH_KEY_PTR(parent, numkey, strkey, zv) { + while (Z_TYPE_P(zv) == IS_INDIRECT) { + zv = Z_INDIRECT_P(zv); + } + + if (i == len || (i == len - 1 && input[len - 1] == ']')) { + char *key, *propkey; + size_t namelen, keylen; + char *name; + char *keyname = estrndup(last_index, index_len); + if (strkey) { + key = strkey->val; + keylen = strkey->len; + } else { + keylen = spprintf(&key, 0, "%llu", numkey); + } + propkey = phpdbg_get_property_key(key); + name = emalloc(i + keylen + 2); + namelen = sprintf(name, "%.*s%.*s%s", (int) i, input, keylen - (propkey - key), propkey, input[len - 1] == ']'?"]":""); + if (!strkey) { + efree(key); + } + + ret = callback(name, namelen, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; + } else if (Z_TYPE_P(zv) == IS_OBJECT) { + phpdbg_parse_variable_with_arg(input, len, Z_OBJPROP_P(zv), i, callback, silent, arg TSRMLS_CC); + } else if (Z_TYPE_P(zv) == IS_ARRAY) { + phpdbg_parse_variable_with_arg(input, len, Z_ARRVAL_P(zv), i, callback, silent, arg TSRMLS_CC); + } else { + /* Ignore silently */ + } + } ZEND_HASH_FOREACH_END(); + return ret; + } else if (new_index) { + char last_chr = last_index[index_len]; + last_index[index_len] = 0; + if (!(zv = zend_symtable_str_find(parent, last_index, index_len))) { + if (!silent) { + phpdbg_error("variable", "type=\"undefined\" variable=\"%.*s\"", "%.*s is undefined", (int) i, input); + } + return FAILURE; + } + while (Z_TYPE_P(zv) == IS_INDIRECT) { + zv = Z_INDIRECT_P(zv); + } + + last_index[index_len] = last_chr; + if (i == len) { + char *name = estrndup(input, len); + char *keyname = estrndup(last_index, index_len); + + ret = callback(name, len, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; + } else if (Z_TYPE_P(zv) == IS_OBJECT) { + parent = Z_OBJPROP_P(zv); + } else if (Z_TYPE_P(zv) == IS_ARRAY) { + parent = Z_ARRVAL_P(zv); + } else { + phpdbg_error("variable", "type=\"notiterable\" variable=\"%.*s\"", "%.*s is nor an array nor an object", (int) i, input); + return FAILURE; + } + index_len = 0; + } + } + + return ret; + error: + phpdbg_error("variable", "type=\"invalidinput\"", "Malformed input"); + return FAILURE; +} + +int phpdbg_is_auto_global(char *name, int len TSRMLS_DC) { + int ret; + zend_string *str = zend_string_init(name, len, 0); + ret = zend_is_auto_global(str TSRMLS_CC); + efree(str); + return ret; +} + +static int phpdbg_xml_array_element_dump(zval *zv, zend_string *key, zend_ulong num TSRMLS_DC) { + phpdbg_xml("<element"); + + phpdbg_try_access { + if (key) { /* string key */ + phpdbg_xml(" name=\"%.*s\"", key->len, key->val); + } else { /* numeric key */ + phpdbg_xml(" name=\"%ld\"", num); + } + } phpdbg_catch_access { + phpdbg_xml(" severity=\"error\" ></element>"); + return 0; + } phpdbg_end_try_access(); + + phpdbg_xml(">"); + + phpdbg_xml_var_dump(zv TSRMLS_CC); + + phpdbg_xml("</element>"); + + return 0; +} + +static int phpdbg_xml_object_property_dump(zval *zv, zend_string *key, zend_ulong num TSRMLS_DC) { + phpdbg_xml("<property"); + + phpdbg_try_access { + if (key) { /* string key */ + const char *prop_name, *class_name; + int unmangle = zend_unmangle_property_name(key, &class_name, &prop_name); + + if (class_name && unmangle == SUCCESS) { + phpdbg_xml(" name=\"%s\"", prop_name); + if (class_name[0] == '*') { + phpdbg_xml(" protection=\"protected\""); + } else { + phpdbg_xml(" class=\"%s\" protection=\"private\"", class_name); + } + } else { + phpdbg_xml(" name=\"%.*s\" protection=\"public\"", key->len, key->val); + } + } else { /* numeric key */ + phpdbg_xml(" name=\"%ld\" protection=\"public\"", num); + } + } phpdbg_catch_access { + phpdbg_xml(" severity=\"error\" ></property>"); + return 0; + } phpdbg_end_try_access(); + + phpdbg_xml(">"); + + phpdbg_xml_var_dump(zv TSRMLS_CC); + + phpdbg_xml("</property>"); + + return 0; +} + +#define COMMON (is_ref ? "&" : "") + +PHPDBG_API void phpdbg_xml_var_dump(zval *zv TSRMLS_DC) { + HashTable *myht; + zend_string *class_name, *key; + zend_ulong num; + zval *val; + int (*element_dump_func)(zval *zv, zend_string *key, zend_ulong num TSRMLS_DC); + zend_bool is_ref = 0; + + int is_temp; + + phpdbg_try_access { + is_ref = Z_ISREF_P(zv) && GC_REFCOUNT(Z_COUNTED_P(zv)) > 1; + ZVAL_DEREF(zv); + + switch (Z_TYPE_P(zv)) { + case IS_TRUE: + phpdbg_xml("<bool refstatus=\"%s\" value=\"true\" />", COMMON); + break; + case IS_FALSE: + phpdbg_xml("<bool refstatus=\"%s\" value=\"false\" />", COMMON); + break; + case IS_NULL: + phpdbg_xml("<null refstatus=\"%s\" />", COMMON); + break; + case IS_LONG: + phpdbg_xml("<int refstatus=\"%s\" value=\"" ZEND_LONG_FMT "\" />", COMMON, Z_LVAL_P(zv)); + break; + case IS_DOUBLE: + phpdbg_xml("<float refstatus=\"%s\" value=\"%.*G\" />", COMMON, (int) EG(precision), Z_DVAL_P(zv)); + break; + case IS_STRING: + phpdbg_xml("<string refstatus=\"%s\" length=\"%d\" value=\"%.*s\" />", COMMON, Z_STRLEN_P(zv), Z_STRLEN_P(zv), Z_STRVAL_P(zv)); + break; + case IS_ARRAY: + myht = Z_ARRVAL_P(zv); + if (ZEND_HASH_APPLY_PROTECTION(myht) && ++myht->u.v.nApplyCount > 1) { + phpdbg_xml("<recursion />"); + --myht->u.v.nApplyCount; + break; + } + phpdbg_xml("<array refstatus=\"%s\" num=\"%d\">", COMMON, zend_hash_num_elements(myht)); + element_dump_func = phpdbg_xml_array_element_dump; + is_temp = 0; + goto head_done; + case IS_OBJECT: + myht = Z_OBJDEBUG_P(zv, is_temp); + if (myht && ++myht->u.v.nApplyCount > 1) { + phpdbg_xml("<recursion />"); + --myht->u.v.nApplyCount; + break; + } + + class_name = Z_OBJ_HANDLER_P(zv, get_class_name)(Z_OBJ_P(zv) TSRMLS_CC); + phpdbg_xml("<object refstatus=\"%s\" class=\"%.*s\" id=\"%d\" num=\"%d\">", COMMON, class_name->len, class_name->val, Z_OBJ_HANDLE_P(zv), myht ? zend_hash_num_elements(myht) : 0); + zend_string_release(class_name); + + element_dump_func = phpdbg_xml_object_property_dump; +head_done: + if (myht) { + ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) { + element_dump_func(val, key, num TSRMLS_CC); + } ZEND_HASH_FOREACH_END(); + zend_hash_apply_with_arguments(myht TSRMLS_CC, (apply_func_args_t) element_dump_func, 0); + --myht->u.v.nApplyCount; + if (is_temp) { + zend_hash_destroy(myht); + efree(myht); + } + } + if (Z_TYPE_P(zv) == IS_ARRAY) { + phpdbg_xml("</array>"); + } else { + phpdbg_xml("</object>"); + } + break; + case IS_RESOURCE: { + const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(zv) TSRMLS_CC); + phpdbg_xml("<resource refstatus=\"%s\" id=\"%pd\" type=\"%ld\" />", COMMON, Z_RES_P(zv)->handle, type_name ? type_name : "unknown"); + break; + } + default: + break; + } + } phpdbg_end_try_access(); +} diff --git a/sapi/phpdbg/phpdbg_utils.h b/sapi/phpdbg/phpdbg_utils.h index 0edc40a262..83dc8e9694 100644 --- a/sapi/phpdbg/phpdbg_utils.h +++ b/sapi/phpdbg/phpdbg_utils.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -33,52 +33,6 @@ PHPDBG_API char *phpdbg_resolve_path(const char* TSRMLS_DC); PHPDBG_API char *phpdbg_trim(const char*, size_t, size_t*); PHPDBG_API const zend_function *phpdbg_get_function(const char*, const char* TSRMLS_DC); -/** - * Error/notice/formatting helpers - */ -enum { - P_ERROR = 1, - P_NOTICE, - P_WRITELN, - P_WRITE, - P_LOG -}; - -#ifdef ZTS -PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5); -#else -PHPDBG_API int phpdbg_print(int TSRMLS_DC, FILE*, const char*, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); -#endif - -PHPDBG_API int phpdbg_rlog(FILE *stream, const char *fmt, ...); - -#define phpdbg_error(fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) -#define phpdbg_notice(fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) -#define phpdbg_writeln(fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) -#define phpdbg_write(fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) -#define phpdbg_log(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDOUT], fmt, ##__VA_ARGS__) - -#define phpdbg_error_ex(out, fmt, ...) phpdbg_print(P_ERROR TSRMLS_CC, out, fmt, ##__VA_ARGS__) -#define phpdbg_notice_ex(out, fmt, ...) phpdbg_print(P_NOTICE TSRMLS_CC, out, fmt, ##__VA_ARGS__) -#define phpdbg_writeln_ex(out, fmt, ...) phpdbg_print(P_WRITELN TSRMLS_CC, out, fmt, ##__VA_ARGS__) -#define phpdbg_write_ex(out, fmt, ...) phpdbg_print(P_WRITE TSRMLS_CC, out, fmt, ##__VA_ARGS__) -#define phpdbg_log_ex(out, fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, out, fmt, ##__VA_ARGS__) - -#if PHPDBG_DEBUG -# define phpdbg_debug(fmt, ...) phpdbg_print(P_LOG TSRMLS_CC, PHPDBG_G(io)[PHPDBG_STDERR], fmt, ##__VA_ARGS__) -#else -# define phpdbg_debug(fmt, ...) -#endif - -/* {{{ For writing blank lines */ -#define EMPTY NULL /* }}} */ - -/* {{{ For prompt lines */ -#define PROMPT "phpdbg>" /* }}} */ - -/* {{{ For separation */ -#define SEPARATE "------------------------------------------------" /* }}} */ - /* {{{ Color Management */ #define PHPDBG_COLOR_LEN 12 #define PHPDBG_COLOR_D(color, code) \ @@ -112,7 +66,7 @@ typedef struct _phpdbg_element_t { PHPDBG_API const phpdbg_color_t *phpdbg_get_color(const char *name, size_t name_length TSRMLS_DC); PHPDBG_API void phpdbg_set_color(int element, const phpdbg_color_t *color TSRMLS_DC); PHPDBG_API void phpdbg_set_color_ex(int element, const char *name, size_t name_length TSRMLS_DC); -PHPDBG_API const phpdbg_color_t* phpdbg_get_colors(TSRMLS_D); +PHPDBG_API const phpdbg_color_t *phpdbg_get_colors(TSRMLS_D); PHPDBG_API int phpdbg_get_element(const char *name, size_t len TSRMLS_DC); /* }}} */ /* {{{ Prompt Management */ @@ -122,26 +76,22 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D); /* }}} */ /* {{{ Console Width */ PHPDBG_API int phpdbg_get_terminal_width(TSRMLS_D); /* }}} */ +PHPDBG_API void phpdbg_set_async_io(int fd); + int phpdbg_rebuild_symtable(TSRMLS_D); -#if PHP_VERSION_ID < 50500 -/* copy from zend_hash.c PHP 5.5 for 5.4 compatibility */ -static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) { - Bucket *p; - - p = pos ? (*pos) : ht->pInternalPointer; - - if (!p) { - Z_TYPE_P(key) = IS_NULL; - } else if (p->nKeyLength) { - Z_TYPE_P(key) = IS_STRING; - Z_STRVAL_P(key) = IS_INTERNED(p->arKey) ? (char*)p->arKey : estrndup(p->arKey, p->nKeyLength - 1); - Z_STRLEN_P(key) = p->nKeyLength - 1; - } else { - Z_TYPE_P(key) = IS_LONG; - Z_LVAL_P(key) = p->h; - } -} -#endif +int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry **ce TSRMLS_DC); + +char *phpdbg_get_property_key(char *key); + +typedef int (*phpdbg_parse_var_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv TSRMLS_DC); +typedef int (*phpdbg_parse_var_with_arg_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv, void *arg TSRMLS_DC); + +PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC); +PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC); + +int phpdbg_is_auto_global(char *name, int len TSRMLS_DC); + +PHPDBG_API void phpdbg_xml_var_dump(zval *zv TSRMLS_DC); #endif /* PHPDBG_UTILS_H */ diff --git a/sapi/phpdbg/phpdbg_wait.c b/sapi/phpdbg/phpdbg_wait.c new file mode 100644 index 0000000000..9051ca379f --- /dev/null +++ b/sapi/phpdbg/phpdbg_wait.c @@ -0,0 +1,400 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg_wait.h" +#include "phpdbg_prompt.h" +#include "ext/json/JSON_parser.h" +#include "ext/standard/basic_functions.h" + +ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +ZEND_EXTERN_MODULE_GLOBALS(json); + +static void phpdbg_rebuild_http_globals_array(int type, const char *name TSRMLS_DC) { + zval *zvp; + if (Z_TYPE(PG(http_globals)[type]) != IS_UNDEF) { + zval_dtor(&PG(http_globals)[type]); + } + if ((zvp = zend_hash_str_find(&EG(symbol_table).ht, name, strlen(name)))) { + Z_ADDREF_P(zvp); + PG(http_globals)[type] = *zvp; + } +} + + +static int phpdbg_dearm_autoglobals(zend_auto_global *auto_global TSRMLS_DC) { + if (auto_global->name->len != sizeof("GLOBALS") - 1 || memcmp(auto_global->name->val, "GLOBALS", sizeof("GLOBALS") - 1)) { + auto_global->armed = 0; + } + + return ZEND_HASH_APPLY_KEEP; +} + +typedef struct { + HashTable *ht[2]; + HashPosition pos[2]; +} phpdbg_intersect_ptr; + +static int phpdbg_array_data_compare(const void *a, const void *b TSRMLS_DC) { + Bucket *f, *s; + zval result; + zval *first, *second; + + f = *((Bucket **) a); + s = *((Bucket **) b); + + first = &f->val; + second = &s->val; + + if (string_compare_function(&result, first, second TSRMLS_CC) == FAILURE) { + return 0; + } + + if (Z_LVAL(result) < 0) { + return -1; + } else if (Z_LVAL(result) > 0) { + return 1; + } + + return 0; +} + +static void phpdbg_array_intersect_init(phpdbg_intersect_ptr *info, HashTable *ht1, HashTable *ht2 TSRMLS_DC) { + info->ht[0] = ht1; + info->ht[1] = ht2; + + zend_hash_sort(info->ht[0], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC); + zend_hash_sort(info->ht[1], zend_qsort, (compare_func_t) phpdbg_array_data_compare, 0 TSRMLS_CC); + + zend_hash_internal_pointer_reset_ex(info->ht[0], &info->pos[0]); + zend_hash_internal_pointer_reset_ex(info->ht[1], &info->pos[1]); +} + +/* -1 => first array, 0 => both arrays equal, 1 => second array */ +static int phpdbg_array_intersect(phpdbg_intersect_ptr *info, zval **ptr) { + int ret; + zval *zvp[2]; + int invalid = !info->ht[0] + !info->ht[1]; + + if (invalid > 0) { + invalid = !info->ht[0]; + + if (!(*ptr = zend_hash_get_current_data_ex(info->ht[invalid], &info->pos[invalid]))) { + return 0; + } + + zend_hash_move_forward_ex(info->ht[invalid], &info->pos[invalid]); + + return invalid ? 1 : -1; + } + + if (!(zvp[0] = zend_hash_get_current_data_ex(info->ht[0], &info->pos[0]))) { + info->ht[0] = NULL; + return phpdbg_array_intersect(info, ptr); + } + if (!(zvp[1] = zend_hash_get_current_data_ex(info->ht[1], &info->pos[1]))) { + info->ht[1] = NULL; + return phpdbg_array_intersect(info, ptr); + } + + ret = zend_binary_zval_strcmp(zvp[0], zvp[1]); + + if (ret <= 0) { + *ptr = zvp[0]; + zend_hash_move_forward_ex(info->ht[0], &info->pos[0]); + } + if (ret >= 0) { + *ptr = zvp[1]; + zend_hash_move_forward_ex(info->ht[1], &info->pos[1]); + } + + return ret; +} + +void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC) { +#ifdef HAVE_JSON + zval *free_zv = NULL; + zval zv, *zvp; + HashTable *ht; + php_json_decode(&zv, msg, len, 1, 1000 /* enough */ TSRMLS_CC); + + if (JSON_G(error_code) != PHP_JSON_ERROR_NONE) { + phpdbg_error("wait", "type=\"invaliddata\" import=\"fail\"", "Malformed JSON was sent to this socket, arborting"); + return; + } + + ht = Z_ARRVAL(zv); + + /* Reapply symbol table */ + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("GLOBALS"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + { + zval *srv; + if ((srv = zend_hash_str_find(Z_ARRVAL_P(zvp), ZEND_STRL("_SERVER"))) && Z_TYPE_P(srv) == IS_ARRAY) { + zval *script; + if ((script = zend_hash_str_find(Z_ARRVAL_P(srv), ZEND_STRL("SCRIPT_FILENAME"))) && Z_TYPE_P(script) == IS_STRING) { + phpdbg_param_t param; + param.str = Z_STRVAL_P(script); + PHPDBG_COMMAND_HANDLER(exec)(¶m TSRMLS_CC); + } + } + } + + PG(auto_globals_jit) = 0; + zend_hash_apply(CG(auto_globals), (apply_func_t) phpdbg_dearm_autoglobals TSRMLS_CC); + + zend_hash_clean(&EG(symbol_table).ht); + EG(symbol_table) = *Z_ARR_P(zvp); + + /* Rebuild cookies, env vars etc. from GLOBALS (PG(http_globals)) */ + phpdbg_rebuild_http_globals_array(TRACK_VARS_POST, "_POST" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_GET, "_GET" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_COOKIE, "_COOKIE" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_SERVER, "_SERVER" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_ENV, "_ENV" TSRMLS_CC); + phpdbg_rebuild_http_globals_array(TRACK_VARS_FILES, "_FILES" TSRMLS_CC); + + Z_ADDREF_P(zvp); + free_zv = zvp; + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("input"))) && Z_TYPE_P(zvp) == IS_STRING) { + if (SG(request_info).request_body) { + php_stream_close(SG(request_info).request_body); + } + SG(request_info).request_body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir)); + php_stream_truncate_set_size(SG(request_info).request_body, 0); + php_stream_write(SG(request_info).request_body, Z_STRVAL_P(zvp), Z_STRLEN_P(zvp)); + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("cwd"))) && Z_TYPE_P(zvp) == IS_STRING) { + if (VCWD_CHDIR(Z_STRVAL_P(zvp)) == SUCCESS) { + if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentStatFile), strlen(BG(CurrentStatFile)))) { + efree(BG(CurrentStatFile)); + BG(CurrentStatFile) = NULL; + } + if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentLStatFile), strlen(BG(CurrentLStatFile)))) { + efree(BG(CurrentLStatFile)); + BG(CurrentLStatFile) = NULL; + } + } + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("sapi_name"))) && (Z_TYPE_P(zvp) == IS_STRING || Z_TYPE_P(zvp) == IS_NULL)) { + if (PHPDBG_G(sapi_name_ptr)) { + free(PHPDBG_G(sapi_name_ptr)); + } + if (Z_TYPE_P(zvp) == IS_STRING) { + PHPDBG_G(sapi_name_ptr) = sapi_module.name = strdup(Z_STRVAL_P(zvp)); + } else { + PHPDBG_G(sapi_name_ptr) = sapi_module.name = NULL; + } + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("modules"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + phpdbg_intersect_ptr pos; + zval *module; + zend_module_entry *mod; + HashTable zv_registry; + + /* intersect modules, unregister modules loaded "too much", announce not yet registered modules (phpdbg_notice) */ + + zend_hash_init(&zv_registry, zend_hash_num_elements(&module_registry), 0, ZVAL_PTR_DTOR, 0); + ZEND_HASH_FOREACH_PTR(&module_registry, mod) { + if (mod->name) { + zval value; + ZVAL_NEW_STR(&value, zend_string_init(mod->name, strlen(mod->name), 0)); + zend_hash_next_index_insert(&zv_registry, &value); + } + } ZEND_HASH_FOREACH_END(); + + phpdbg_array_intersect_init(&pos, &zv_registry, Z_ARRVAL_P(zvp) TSRMLS_CC); + do { + int mode = phpdbg_array_intersect(&pos, &module); + if (mode < 0) { + // loaded module, but not needed + if (strcmp(PHPDBG_NAME, Z_STRVAL_P(module))) { + zend_hash_del(&module_registry, Z_STR_P(module)); + } + } else if (mode > 0) { + // not loaded module + if (!sapi_module.name || strcmp(sapi_module.name, Z_STRVAL_P(module))) { + phpdbg_notice("wait", "missingmodule=\"%.*s\"", "The module %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/module/%.*s.so", Z_STRLEN_P(module), Z_STRVAL_P(module), Z_STRLEN_P(module), Z_STRVAL_P(module)); + } + } + } while (module); + + zend_hash_clean(&zv_registry); + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("extensions"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + zend_extension *extension; + zend_llist_position pos; + zval *name = NULL; + zend_string *strkey; + + extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos); + while (extension) { + extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos); + + /* php_serach_array() body should be in some ZEND_API function... */ + ZEND_HASH_FOREACH_STR_KEY_PTR(Z_ARRVAL_P(zvp), strkey, name) { + if (Z_TYPE_P(name) == IS_STRING && !zend_binary_strcmp(extension->name, strlen(extension->name), Z_STRVAL_P(name), Z_STRLEN_P(name))) { + break; + } + name = NULL; + } ZEND_HASH_FOREACH_END(); + + if (name) { + /* sigh, breaking the encapsulation, there aren't any functions manipulating the llist at the place of the zend_llist_position */ + zend_llist_element *elm = pos; + if (elm->prev) { + elm->prev->next = elm->next; + } else { + zend_extensions.head = elm->next; + } + if (elm->next) { + elm->next->prev = elm->prev; + } else { + zend_extensions.tail = elm->prev; + } +#if ZEND_EXTENSIONS_SUPPORT + if (extension->shutdown) { + extension->shutdown(extension); + } +#endif + if (zend_extensions.dtor) { + zend_extensions.dtor(elm->data); + } + pefree(elm, zend_extensions.persistent); + zend_extensions.count--; + } else { +/* zend_hash_get_current_key_zval_ex(Z_ARRVAL_PP(zvpp), &key, &hpos); + if (Z_TYPE(key) == IS_LONG) { + zend_hash_index_del(Z_ARRVAL_PP(zvpp), Z_LVAL(key)); + } +*/ + zend_hash_del(Z_ARRVAL_P(zvp), strkey); + } + } + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zvp), name) { + if (Z_TYPE_P(name) == IS_STRING) { + phpdbg_notice("wait", "missingextension=\"%.*s\"", "The Zend extension %.*s isn't present in " PHPDBG_NAME ", you still can load via dl /path/to/extension.so", Z_STRLEN_P(name), Z_STRVAL_P(name)); + } + } ZEND_HASH_FOREACH_END(); + } + + zend_ini_deactivate(TSRMLS_C); + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("systemini"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + zval *ini_entry; + zend_ini_entry *original_ini; + zend_string *key; + + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) { + if (key && Z_TYPE_P(ini_entry) == IS_STRING) { + if ((original_ini = zend_hash_find_ptr(EG(ini_directives), key))) { + if (!original_ini->on_modify || original_ini->on_modify(original_ini, Z_STR_P(ini_entry), original_ini->mh_arg1, original_ini->mh_arg2, original_ini->mh_arg3, ZEND_INI_STAGE_ACTIVATE TSRMLS_CC) == SUCCESS) { + if (original_ini->modified && original_ini->orig_value != original_ini->value) { + efree(original_ini->value); + } + original_ini->value = Z_STR_P(ini_entry); + Z_ADDREF_P(ini_entry); /* don't free the string */ + } + } + } + } ZEND_HASH_FOREACH_END(); + } + + if ((zvp = zend_hash_str_find(ht, ZEND_STRL("userini"))) && Z_TYPE_P(zvp) == IS_ARRAY) { + zval *ini_entry; + zend_string *key; + + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zvp), key, ini_entry) { + if (key && Z_TYPE_P(ini_entry) == IS_STRING) { + zend_alter_ini_entry_ex(key, Z_STR_P(ini_entry), ZEND_INI_PERDIR, ZEND_INI_STAGE_HTACCESS, 1 TSRMLS_CC); + } + } ZEND_HASH_FOREACH_END(); + } + + zval_dtor(&zv); + if (free_zv) { + /* separate freeing to not dtor the symtable too, just the container zval... */ + efree(free_zv); + } + + /* Reapply raw input */ + /* ??? */ +#endif +} + +PHPDBG_COMMAND(wait) /* {{{ */ +{ +#ifdef HAVE_JSON + struct sockaddr_un local, remote; + int rlen, sr, sl; + unlink(PHPDBG_G(socket_path)); + if (PHPDBG_G(socket_server_fd) == -1) { + int len; + PHPDBG_G(socket_server_fd) = sl = socket(AF_UNIX, SOCK_STREAM, 0); + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, PHPDBG_G(socket_path)); + len = strlen(local.sun_path) + sizeof(local.sun_family); + if (bind(sl, (struct sockaddr *)&local, len) == -1) { + phpdbg_error("wait", "type=\"nosocket\" import=\"fail\"", "Unable to connect to UNIX domain socket at %s defined by phpdbg.path ini setting", PHPDBG_G(socket_path)); + return FAILURE; + } + + chmod(PHPDBG_G(socket_path), 0666); + + listen(sl, 2); + } else { + sl = PHPDBG_G(socket_server_fd); + } + + rlen = sizeof(remote); + sr = accept(sl, (struct sockaddr *) &remote, (socklen_t *) &rlen); + + char msglen[5]; + int recvd = 4; + + do { + recvd -= recv(sr, &(msglen[4 - recvd]), recvd, 0); + } while (recvd > 0); + + recvd = *(size_t *) msglen; + char *data = emalloc(recvd); + + do { + recvd -= recv(sr, &(data[(*(int *) msglen) - recvd]), recvd, 0); + } while (recvd > 0); + + phpdbg_webdata_decompress(data, *(int *) msglen TSRMLS_CC); + + if (PHPDBG_G(socket_fd) != -1) { + close(PHPDBG_G(socket_fd)); + } + PHPDBG_G(socket_fd) = sr; + + efree(data); + + phpdbg_notice("wait", "import=\"success\"", "Successfully imported request data, stopped before executing"); + + return SUCCESS; +#endif +} /* }}} */ diff --git a/sapi/phpdbg/phpdbg_wait.h b/sapi/phpdbg/phpdbg_wait.h new file mode 100644 index 0000000000..7cf95919cc --- /dev/null +++ b/sapi/phpdbg/phpdbg_wait.h @@ -0,0 +1,29 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_WAIT_H +#define PHPDBG_WAIT_H + +#include "zend.h" +#include "phpdbg.h" + +PHPDBG_COMMAND(wait); + +void phpdbg_webdata_decompress(char *msg, int len TSRMLS_DC); + +#endif /* PHPDBG_WAIT_H */ diff --git a/sapi/phpdbg/phpdbg_watch.c b/sapi/phpdbg/phpdbg_watch.c index 054bea6d00..7a39d3ee1a 100644 --- a/sapi/phpdbg/phpdbg_watch.c +++ b/sapi/phpdbg/phpdbg_watch.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -30,6 +30,15 @@ ZEND_EXTERN_MODULE_GLOBALS(phpdbg); +const phpdbg_command_t phpdbg_watch_commands[] = { + PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s", 0), + PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s", 0), + PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s", 0), + PHPDBG_END_COMMAND +}; + +//#define HT_FROM_WATCH(watch) (watch->type == WATCH_ON_OBJECT ? watch->addr.obj->handlers->get_properties(watch->parent_container.zv TSRMLS_CC) : watch->type == WATCH_ON_ARRAY ? &watch->addr.arr->ht : NULL) +#define HT_FROM_ZVP(zvp) (Z_TYPE_P(zvp) == IS_OBJECT ? Z_OBJPROP_P(zvp) : Z_TYPE_P(zvp) == IS_ARRAY ? Z_ARRVAL_P(zvp) : NULL) typedef struct { void *page; @@ -53,7 +62,7 @@ static phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *addr TSRMLS_DC) { watch = result->ptr; /* check if that addr is in a mprotect()'ed memory area */ - if ((char *)phpdbg_get_page_boundary(watch->addr.ptr) > (char *)addr || (char *)phpdbg_get_page_boundary(watch->addr.ptr) + phpdbg_get_total_page_size(watch->addr.ptr, watch->size) < (char *)addr) { + if ((char *) phpdbg_get_page_boundary(watch->addr.ptr) > (char *) addr || (char *) phpdbg_get_page_boundary(watch->addr.ptr) + phpdbg_get_total_page_size(watch->addr.ptr, watch->size) < (char *) addr) { /* failure */ return NULL; } @@ -62,10 +71,8 @@ static phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *addr TSRMLS_DC) { } static void phpdbg_change_watchpoint_access(phpdbg_watchpoint_t *watch, int access TSRMLS_DC) { - int m; - /* pagesize is assumed to be in the range of 2^x */ - m = mprotect(phpdbg_get_page_boundary(watch->addr.ptr), phpdbg_get_total_page_size(watch->addr.ptr, watch->size), access); + mprotect(phpdbg_get_page_boundary(watch->addr.ptr), phpdbg_get_total_page_size(watch->addr.ptr, watch->size), access); } static inline void phpdbg_activate_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { @@ -77,11 +84,11 @@ static inline void phpdbg_deactivate_watchpoint(phpdbg_watchpoint_t *watch TSRML } static inline void phpdbg_store_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { - phpdbg_btree_insert(&PHPDBG_G(watchpoint_tree), (zend_ulong)watch->addr.ptr, watch); + phpdbg_btree_insert(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr, watch); } static inline void phpdbg_remove_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { - phpdbg_btree_delete(&PHPDBG_G(watchpoint_tree), (zend_ulong)watch->addr.ptr); + phpdbg_btree_delete(&PHPDBG_G(watchpoint_tree), (zend_ulong) watch->addr.ptr); } void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch) { @@ -99,17 +106,95 @@ void phpdbg_create_ht_watchpoint(HashTable *ht, phpdbg_watchpoint_t *watch) { watch->type = WATCH_ON_HASHTABLE; } -void phpdbg_watch_HashTable_dtor(zval **ptr); +void phpdbg_watch_HashTable_dtor(zval *ptr); + +static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC); +static void phpdbg_delete_ht_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC); +static void phpdbg_delete_zval_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC); +static void phpdbg_delete_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC); + +/* TODO: Store all the possible watches the refcounted may refer to (for displaying & deleting by identifier) */ + +static phpdbg_watchpoint_t *phpdbg_create_refcounted_watchpoint(phpdbg_watchpoint_t *parent, zend_refcounted *ref) { + phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); + watch->flags = parent->flags; + watch->parent = parent; + phpdbg_create_addr_watchpoint(&ref->refcount, sizeof(uint32_t), watch); + watch->type = WATCH_ON_REFCOUNTED; + + return watch; +} + +static void phpdbg_add_watch_collision(phpdbg_watchpoint_t *watch TSRMLS_DC) { + phpdbg_watch_collision *cur; + if ((cur = zend_hash_index_find_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) watch->addr.ref))) { + cur->num++; + if (watch->flags == PHPDBG_WATCH_RECURSIVE) { + cur->refs++; + } + } else { + phpdbg_watch_collision coll; + coll.num = 1; + coll.refs = watch->flags == PHPDBG_WATCH_RECURSIVE; + coll.watch = *watch; + zend_hash_init(&coll.watches, 8, NULL, NULL, 0); + cur = zend_hash_index_add_mem(&PHPDBG_G(watch_collisions), (zend_ulong) watch->addr.ref, &coll, sizeof(phpdbg_watch_collision)); + phpdbg_store_watchpoint(&cur->watch TSRMLS_CC); + phpdbg_activate_watchpoint(&cur->watch TSRMLS_CC); + } + + zend_hash_str_add_ptr(&cur->watches, watch->parent->str, watch->parent->str_len, watch->parent); +} + +static void phpdbg_remove_watch_collision(zend_refcounted *ref TSRMLS_DC) { + phpdbg_watch_collision *cur; + if ((cur = zend_hash_index_find_ptr(&PHPDBG_G(watch_collisions), (zend_ulong) ref))) { + phpdbg_watchpoint_t *watch = cur->watch.parent; + + if (watch->flags == PHPDBG_WATCH_RECURSIVE && !--cur->refs) { + phpdbg_delete_watchpoints_recursive(watch TSRMLS_CC); + } + + zend_hash_str_del(&cur->watches, watch->str, watch->str_len); + + if (!--cur->num) { + phpdbg_deactivate_watchpoint(&cur->watch TSRMLS_CC); + phpdbg_remove_watchpoint(&cur->watch TSRMLS_CC); + + phpdbg_delete_watchpoint(watch TSRMLS_CC); + + zend_hash_index_del(&PHPDBG_G(watch_collisions), (zend_ulong) ref); + } + } +} static int phpdbg_create_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { watch->flags |= PHPDBG_WATCH_SIMPLE; phpdbg_store_watchpoint(watch TSRMLS_CC); - zend_hash_add(&PHPDBG_G(watchpoints), watch->str, watch->str_len, &watch, sizeof(phpdbg_watchpoint_t *), NULL); + zend_hash_str_add_ptr(&PHPDBG_G(watchpoints), watch->str, watch->str_len, watch); + + if (watch->parent && watch->parent->type == WATCH_ON_ZVAL && Z_REFCOUNTED_P(watch->parent->addr.zv)) { + phpdbg_add_watch_collision(phpdbg_create_refcounted_watchpoint(watch, Z_COUNTED_P(watch->parent->addr.zv)) TSRMLS_CC); + } if (watch->type == WATCH_ON_ZVAL) { - phpdbg_btree_insert(&PHPDBG_G(watch_HashTables), (zend_ulong)watch->parent_container, watch->parent_container->pDestructor); - watch->parent_container->pDestructor = (dtor_func_t)phpdbg_watch_HashTable_dtor; + if (watch->parent_container) { + phpdbg_btree_insert(&PHPDBG_G(watch_HashTables), (zend_ulong) watch->parent_container, watch->parent_container->pDestructor); + watch->parent_container->pDestructor = (dtor_func_t) phpdbg_watch_HashTable_dtor; + } + + if (Z_ISREF_P(watch->addr.zv)) { + phpdbg_watchpoint_t *ref = emalloc(sizeof(phpdbg_watchpoint_t)); + ref->flags = watch->flags; + ref->str = watch->str; + ref->str_len = watch->str_len; + ref->parent = watch; + ref->parent_container = NULL; + phpdbg_create_zval_watchpoint(Z_REFVAL_P(watch->addr.zv), ref); + + phpdbg_create_watchpoint(ref TSRMLS_CC); + } } phpdbg_activate_watchpoint(watch TSRMLS_CC); @@ -117,36 +202,35 @@ static int phpdbg_create_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { return SUCCESS; } -static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { - HashTable *ht; +static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *zv_watch TSRMLS_DC) { + zval *zv = zv_watch->addr.zv; + phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); + HashTable *ht = HT_FROM_ZVP(zv); - switch (Z_TYPE_P(watch->addr.zv)) { - case IS_ARRAY: - ht = Z_ARRVAL_P(watch->addr.zv); - break; - case IS_OBJECT: - ht = Z_OBJPROP_P(watch->addr.zv); - break; - default: - return FAILURE; + watch->parent = zv_watch; + + if (!ht) { + return FAILURE; } phpdbg_create_ht_watchpoint(ht, watch); phpdbg_create_watchpoint(watch TSRMLS_CC); - return SUCCESS; -} - -static char *phpdbg_get_property_key(char *key) { - if (*key != 0) { - return key; + if (Z_TYPE_P(zv) == IS_ARRAY) { + watch->flags |= PHPDBG_WATCH_ARRAY; + } else { + watch->flags |= PHPDBG_WATCH_OBJECT; } - return strchr(key + 1, 0) + 1; + + phpdbg_add_watch_collision(phpdbg_create_refcounted_watchpoint(watch, Z_COUNTED_P(zv)) TSRMLS_CC); + + return SUCCESS; } static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) { HashTable *ht; + zval *zvp = watch->addr.zv; if (watch->type != WATCH_ON_ZVAL) { return FAILURE; @@ -155,25 +239,18 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_ watch->flags |= PHPDBG_WATCH_RECURSIVE; phpdbg_create_watchpoint(watch TSRMLS_CC); - switch (Z_TYPE_P(watch->addr.zv)) { - case IS_ARRAY: - ht = Z_ARRVAL_P(watch->addr.zv); - break; - case IS_OBJECT: - ht = Z_OBJPROP_P(watch->addr.zv); - break; - default: - return SUCCESS; + ZVAL_DEREF(zvp); + + if (!(ht = HT_FROM_ZVP(zvp))) { + return SUCCESS; } { HashPosition position; - zval **zv; + zval *zv; zval key; - for (zend_hash_internal_pointer_reset_ex(ht, &position); - zend_hash_get_current_data_ex(ht, (void **)&zv, &position) == SUCCESS; - zend_hash_move_forward_ex(ht, &position)) { + ZEND_HASH_FOREACH_VAL(ht, zv) { phpdbg_watchpoint_t *new_watch = emalloc(sizeof(phpdbg_watchpoint_t)); new_watch->flags = PHPDBG_WATCH_RECURSIVE; @@ -182,19 +259,21 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_ zend_hash_get_current_key_zval_ex(ht, &key, &position); if (Z_TYPE(key) == IS_STRING) { - new_watch->name_in_parent = zend_strndup(Z_STRVAL(key), Z_STRLEN(key)); + new_watch->name_in_parent = estrndup(Z_STRVAL(key), Z_STRLEN(key)); new_watch->name_in_parent_len = Z_STRLEN(key); } else { - new_watch->name_in_parent = NULL; - new_watch->name_in_parent_len = asprintf(&new_watch->name_in_parent, "%ld", Z_LVAL(key)); + new_watch->name_in_parent_len = spprintf(&new_watch->name_in_parent, 0, "%lld", Z_LVAL(key)); } - new_watch->str = NULL; - new_watch->str_len = asprintf(&new_watch->str, "%.*s%s%s%s", (int)watch->str_len, watch->str, Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"[":"->", phpdbg_get_property_key(new_watch->name_in_parent), Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"]":""); + new_watch->str_len = spprintf(&new_watch->str, 0, "%.*s%s%s%s", (int) watch->str_len, watch->str, Z_TYPE_P(zvp) == IS_ARRAY ? "[" : "->", phpdbg_get_property_key(new_watch->name_in_parent), Z_TYPE_P(zvp) == IS_ARRAY ? "]" : ""); + + while (Z_TYPE_P(zv) == IS_INDIRECT) { + zv = Z_INDIRECT_P(zv); + } - phpdbg_create_zval_watchpoint(*zv, new_watch); + phpdbg_create_zval_watchpoint(zv, new_watch); phpdbg_create_recursive_watchpoint(new_watch TSRMLS_CC); - } + } ZEND_HASH_FOREACH_END(); } { @@ -202,12 +281,18 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_ new_watch->parent = watch; new_watch->parent_container = watch->parent_container; - new_watch->name_in_parent = zend_strndup(watch->name_in_parent, watch->name_in_parent_len); + new_watch->name_in_parent = estrndup(watch->name_in_parent, watch->name_in_parent_len); new_watch->name_in_parent_len = watch->name_in_parent_len; new_watch->str = NULL; - new_watch->str_len = asprintf(&new_watch->str, "%.*s[]", (int)watch->str_len, watch->str); + new_watch->str_len = spprintf(&new_watch->str, 0, "%.*s[]", (int) watch->str_len, watch->str); new_watch->flags = PHPDBG_WATCH_RECURSIVE; + if (Z_TYPE_P(zvp) == IS_ARRAY) { + new_watch->flags |= PHPDBG_WATCH_ARRAY; + } else { + new_watch->flags |= PHPDBG_WATCH_OBJECT; + } + phpdbg_create_ht_watchpoint(ht, new_watch); phpdbg_create_watchpoint(new_watch TSRMLS_CC); } @@ -216,52 +301,58 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_ } static int phpdbg_delete_watchpoint_recursive(phpdbg_watchpoint_t *watch, zend_bool user_request TSRMLS_DC) { - if (watch->type == WATCH_ON_HASHTABLE || (watch->type == WATCH_ON_ZVAL && (Z_TYPE_P(watch->addr.zv) == IS_ARRAY || Z_TYPE_P(watch->addr.zv) == IS_OBJECT))) { + if (watch->type == WATCH_ON_HASHTABLE) { HashTable *ht; phpdbg_btree_result *result; if (watch->type == WATCH_ON_HASHTABLE && user_request) { - HashPosition position; - zval **zv; - zval key; - char *str; - int str_len; - phpdbg_watchpoint_t **watchpoint; - - ht = watch->addr.ht; - - for (zend_hash_internal_pointer_reset_ex(ht, &position); - zend_hash_get_current_data_ex(ht, (void **)&zv, &position) == SUCCESS; - zend_hash_move_forward_ex(ht, &position)) { - zend_hash_get_current_key_zval_ex(ht, &key, &position); - str = NULL; - if (Z_TYPE(key) == IS_STRING) { - str_len = asprintf(&str, "%.*s%s%s%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", phpdbg_get_property_key(Z_STRVAL(key)), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":""); - } else { - str_len = asprintf(&str, "%.*s%s%li%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", Z_LVAL(key), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":""); - } - - if (zend_hash_find(&PHPDBG_G(watchpoints), str, str_len, (void **) &watchpoint) == SUCCESS) { - phpdbg_delete_watchpoint_recursive(*watchpoint, 1 TSRMLS_CC); - } - } + phpdbg_delete_ht_watchpoints_recursive(watch TSRMLS_CC); } else { - switch (Z_TYPE_P(watch->addr.zv)) { - case IS_ARRAY: - ht = Z_ARRVAL_P(watch->addr.zv); - break; - case IS_OBJECT: - ht = Z_OBJPROP_P(watch->addr.zv); - break; - } + ht = HT_FROM_ZVP(watch->addr.zv); if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) ht))) { phpdbg_delete_watchpoint_recursive((phpdbg_watchpoint_t *) result->ptr, user_request TSRMLS_CC); } } + } else if (watch->type == WATCH_ON_ZVAL) { + phpdbg_delete_zval_watchpoints_recursive(watch TSRMLS_CC); + } + + return zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); +} + +static void phpdbg_delete_ht_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC) { + zend_string *strkey; + zend_long numkey; + char *str; + int str_len; + phpdbg_watchpoint_t *watchpoint; + + ZEND_HASH_FOREACH_KEY(watch->addr.ht, numkey, strkey) { + if (strkey) { + str_len = asprintf(&str, "%.*s%s%s%s", (int) watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_ARRAY) ? "[" : "->", phpdbg_get_property_key(strkey->val), (watch->flags & PHPDBG_WATCH_ARRAY) ? "]" : ""); + } else { + str_len = asprintf(&str, "%.*s%s%lli%s", (int) watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_ARRAY) ? "[" : "->", numkey, (watch->flags & PHPDBG_WATCH_ARRAY) ? "]" : ""); + } + + if ((watchpoint = zend_hash_str_find_ptr(&PHPDBG_G(watchpoints), str, str_len))) { + phpdbg_delete_watchpoint_recursive(watchpoint, 1 TSRMLS_CC); + } + } ZEND_HASH_FOREACH_END(); +} + +static void phpdbg_delete_zval_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC) { + if (Z_REFCOUNTED_P(watch->addr.zv)) { + phpdbg_remove_watch_collision(Z_COUNTED_P(watch->addr.zv) TSRMLS_CC); } +} - return zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); +static void phpdbg_delete_watchpoints_recursive(phpdbg_watchpoint_t *watch TSRMLS_DC) { + if (watch->type == WATCH_ON_ZVAL) { + phpdbg_delete_zval_watchpoints_recursive(watch TSRMLS_CC); + } else if (watch->type == WATCH_ON_HASHTABLE) { + phpdbg_delete_ht_watchpoints_recursive(watch TSRMLS_CC); + } } static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) { @@ -269,7 +360,7 @@ static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) { phpdbg_watchpoint_t *watch; phpdbg_btree_result *result; - if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)tmp_watch->addr.ptr)) == NULL) { + if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) tmp_watch->addr.ptr)) == NULL) { return FAILURE; } @@ -278,133 +369,52 @@ static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) { if (watch->flags & PHPDBG_WATCH_RECURSIVE) { ret = phpdbg_delete_watchpoint_recursive(watch, 1 TSRMLS_CC); } else { - ret = zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); + ret = zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); } - free(tmp_watch->str); + efree(tmp_watch->str); + efree(tmp_watch->name_in_parent); efree(tmp_watch); return ret; } -static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) { - int ret = FAILURE; - zend_bool new_index = 1; - char *last_index; - int index_len = 0; - zval **zv; - - if (len < 2 || *input != '$') { - goto error; - } - - while (i++ < len) { - if (i == len) { - new_index = 1; - } else { - switch (input[i]) { - case '[': - new_index = 1; - break; - case ']': - break; - case '>': - if (last_index[index_len - 1] == '-') { - new_index = 1; - index_len--; - } - break; - - default: - if (new_index) { - last_index = input + i; - new_index = 0; - } - if (input[i - 1] == ']') { - goto error; - } - index_len++; - } - } - - if (new_index && index_len == 0) { - HashPosition position; - for (zend_hash_internal_pointer_reset_ex(parent, &position); - zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS; - zend_hash_move_forward_ex(parent, &position)) { - if (i == len || (i == len - 1 && input[len - 1] == ']')) { - zval *key = emalloc(sizeof(zval)); - phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); - watch->flags = 0; - zend_hash_get_current_key_zval_ex(parent, key, &position); - convert_to_string(key); - watch->str = malloc(i + Z_STRLEN_P(key) + 2); - watch->str_len = sprintf(watch->str, "%.*s%s%s", (int)i, input, phpdbg_get_property_key(Z_STRVAL_P(key)), input[len - 1] == ']'?"]":""); - efree(key); - watch->name_in_parent = zend_strndup(last_index, index_len); - watch->name_in_parent_len = index_len; - watch->parent_container = parent; - phpdbg_create_zval_watchpoint(*zv, watch); - - ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; - } else if (Z_TYPE_PP(zv) == IS_OBJECT) { - phpdbg_watchpoint_parse_input(input, len, Z_OBJPROP_PP(zv), i, callback, silent TSRMLS_CC); - } else if (Z_TYPE_PP(zv) == IS_ARRAY) { - phpdbg_watchpoint_parse_input(input, len, Z_ARRVAL_PP(zv), i, callback, silent TSRMLS_CC); - } else { - /* Ignore silently */ - } - } - return ret; - } else if (new_index) { - char last_chr = last_index[index_len]; - last_index[index_len] = 0; - if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) { - if (!silent) { - phpdbg_error("%.*s is undefined", (int)i, input); - } - return FAILURE; - } - last_index[index_len] = last_chr; - if (i == len) { - phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); - watch->flags = 0; - watch->str = zend_strndup(input, len); - watch->str_len = len; - watch->name_in_parent = zend_strndup(last_index, index_len); - watch->name_in_parent_len = index_len; - watch->parent_container = parent; - phpdbg_create_zval_watchpoint(*zv, watch); - - ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE; - } else if (Z_TYPE_PP(zv) == IS_OBJECT) { - parent = Z_OBJPROP_PP(zv); - } else if (Z_TYPE_PP(zv) == IS_ARRAY) { - parent = Z_ARRVAL_PP(zv); - } else { - phpdbg_error("%.*s is nor an array nor an object", (int)i, input); - return FAILURE; - } - index_len = 0; - } +static int phpdbg_watchpoint_parse_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) { + int ret; + phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t)); + watch->flags = 0; + watch->str = name; + watch->str_len = len; + watch->name_in_parent = keyname; + watch->name_in_parent_len = keylen; + watch->parent_container = parent; + phpdbg_create_zval_watchpoint(zv, watch); + + ret = callback(watch TSRMLS_CC); + + if (ret != SUCCESS) { + efree(watch); + efree(name); + efree(keyname); } return ret; - error: - phpdbg_error("Malformed input"); - return FAILURE; +} + +PHPDBG_API int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) { + return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_wrapper, 0, callback TSRMLS_CC); } static int phpdbg_watchpoint_parse_symtables(char *input, size_t len, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) { - if (EG(This) && len >= 5 && !memcmp("$this", input, 5)) { - zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), NULL); + if (EG(scope) && len >= 5 && !memcmp("$this", input, 5)) { + zend_hash_str_add(&EG(current_execute_data)->symbol_table->ht, ZEND_STRL("this"), &EG(current_execute_data)->This); } - if (zend_is_auto_global(input, len TSRMLS_CC) && phpdbg_watchpoint_parse_input(input, len, &EG(symbol_table), 0, callback, 1 TSRMLS_CC) != FAILURE) { + if (phpdbg_is_auto_global(input, len TSRMLS_CC) && phpdbg_watchpoint_parse_input(input, len, &EG(symbol_table).ht, 0, callback, 1 TSRMLS_CC) != FAILURE) { return SUCCESS; } - return phpdbg_watchpoint_parse_input(input, len, EG(active_symbol_table), 0, callback, 0 TSRMLS_CC); + return phpdbg_watchpoint_parse_input(input, len, &EG(current_execute_data)->symbol_table->ht, 0, callback, 0 TSRMLS_CC); } PHPDBG_WATCH(delete) /* {{{ */ @@ -412,9 +422,9 @@ PHPDBG_WATCH(delete) /* {{{ */ switch (param->type) { case STR_PARAM: if (phpdbg_delete_var_watchpoint(param->str, param->len TSRMLS_CC) == FAILURE) { - phpdbg_error("Nothing was deleted, no corresponding watchpoint found"); + phpdbg_error("watchdelete", "type=\"nowatch\"", "Nothing was deleted, no corresponding watchpoint found"); } else { - phpdbg_notice("Removed watchpoint %.*s", (int)param->len, param->str); + phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Removed watchpoint %.*s", (int) param->len, param->str); } break; @@ -433,7 +443,7 @@ PHPDBG_WATCH(recursive) /* {{{ */ switch (param->type) { case STR_PARAM: if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_recursive_watchpoint TSRMLS_CC) != FAILURE) { - phpdbg_notice("Set recursive watchpoint on %.*s", (int)param->len, param->str); + phpdbg_notice("watchrecursive", "variable=\"%.*s\"", "Set recursive watchpoint on %.*s", (int)param->len, param->str); } break; @@ -452,7 +462,7 @@ PHPDBG_WATCH(array) /* {{{ */ switch (param->type) { case STR_PARAM: if (phpdbg_watchpoint_parse_symtables(param->str, param->len, phpdbg_create_array_watchpoint TSRMLS_CC) != FAILURE) { - phpdbg_notice("Set array watchpoint on %.*s", (int)param->len, param->str); + phpdbg_notice("watcharray", "variable=\"%.*s\"", "Set array watchpoint on %.*s", (int)param->len, param->str); } break; @@ -462,23 +472,23 @@ PHPDBG_WATCH(array) /* {{{ */ return SUCCESS; } /* }}} */ -void phpdbg_watch_HashTable_dtor(zval **zv) { +void phpdbg_watch_HashTable_dtor(zval *zv) { phpdbg_btree_result *result; TSRMLS_FETCH(); zval_ptr_dtor_wrapper(zv); - if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)*zv))) { + if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong) zv))) { phpdbg_watchpoint_t *watch = result->ptr; PHPDBG_G(watchpoint_hit) = 1; - phpdbg_notice("%.*s was removed, removing watchpoint%s", (int)watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_RECURSIVE)?" recursively":""); + phpdbg_notice("watchdelete", "variable=\"%.*s\" recursive=\"%s\"", "%.*s was removed, removing watchpoint%s", (int) watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_RECURSIVE) ? " recursively" : ""); if (watch->flags & PHPDBG_WATCH_RECURSIVE) { phpdbg_delete_watchpoint_recursive(watch, 0 TSRMLS_CC); } else { - zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); + zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); } } } @@ -543,27 +553,26 @@ void phpdbg_watchpoints_clean(TSRMLS_D) { zend_hash_clean(&PHPDBG_G(watchpoints)); } -static void phpdbg_watch_dtor(void *pDest) { - phpdbg_watchpoint_t *watch = *(phpdbg_watchpoint_t **)pDest; +static void phpdbg_watch_dtor(zval *pDest) { + phpdbg_watchpoint_t *watch = (phpdbg_watchpoint_t *) Z_PTR_P(pDest); TSRMLS_FETCH(); phpdbg_deactivate_watchpoint(watch TSRMLS_CC); phpdbg_remove_watchpoint(watch TSRMLS_CC); - free(watch->str); - free(watch->name_in_parent); - efree(watch); + efree(watch->str); + efree(watch->name_in_parent); } static void phpdbg_watch_mem_dtor(void *llist_data) { - phpdbg_watch_memdump *dump = *(phpdbg_watch_memdump **)llist_data; + phpdbg_watch_memdump *dump = *(phpdbg_watch_memdump **) llist_data; /* Disble writing again */ if (dump->reenable_writing) { mprotect(dump->page, dump->size, PROT_READ); } - free(*(void **)llist_data); + free(*(void **) llist_data); } void phpdbg_setup_watchpoints(TSRMLS_D) { @@ -580,131 +589,145 @@ void phpdbg_setup_watchpoints(TSRMLS_D) { zend_llist_init(&PHPDBG_G(watchlist_mem), sizeof(void *), phpdbg_watch_mem_dtor, 1); phpdbg_btree_init(&PHPDBG_G(watchpoint_tree), sizeof(void *) * 8); phpdbg_btree_init(&PHPDBG_G(watch_HashTables), sizeof(void *) * 8); - zend_hash_init(&PHPDBG_G(watchpoints), 8, NULL, phpdbg_watch_dtor, 0 ZEND_FILE_LINE_CC); + zend_hash_init(&PHPDBG_G(watchpoints), 8, NULL, phpdbg_watch_dtor, 0); + zend_hash_init(&PHPDBG_G(watch_collisions), 8, NULL, NULL, 0); } static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) { /* fetch all changes between dump->page and dump->page + dump->size */ - phpdbg_btree_position pos = phpdbg_btree_find_between(&PHPDBG_G(watchpoint_tree), (zend_ulong)dump->page, (zend_ulong)dump->page + dump->size); - phpdbg_btree_result *result, *htresult; + phpdbg_btree_position pos = phpdbg_btree_find_between(&PHPDBG_G(watchpoint_tree), (zend_ulong) dump->page, (zend_ulong) dump->page + dump->size); + phpdbg_btree_result *result; int elementDiff; void *curTest; dump->reenable_writing = 0; while ((result = phpdbg_btree_next(&pos))) { - phpdbg_watchpoint_t *watch = result->ptr, *htwatch; - void *oldPtr = (char *)&dump->data + ((size_t)watch->addr.ptr - (size_t)dump->page); + phpdbg_watchpoint_t *watch = result->ptr; + void *oldPtr = (char *) &dump->data + ((size_t) watch->addr.ptr - (size_t) dump->page); char reenable = 1; + int removed = 0; - if ((size_t)watch->addr.ptr < (size_t)dump->page || (size_t)watch->addr.ptr + watch->size > (size_t)dump->page + dump->size) { + if ((size_t) watch->addr.ptr < (size_t) dump->page || (size_t) watch->addr.ptr + watch->size > (size_t) dump->page + dump->size) { continue; } /* Test if the zval was separated and if necessary move the watchpoint */ - if (zend_hash_find(watch->parent_container, watch->name_in_parent, watch->name_in_parent_len + 1, &curTest) == SUCCESS) { - if (watch->type == WATCH_ON_HASHTABLE) { - switch (Z_TYPE_PP((zval **)curTest)) { - case IS_ARRAY: - curTest = (void *)Z_ARRVAL_PP((zval **)curTest); - break; - case IS_OBJECT: - curTest = (void *)Z_OBJPROP_PP((zval **)curTest); - break; + if ((watch->type == WATCH_ON_HASHTABLE || watch->type == WATCH_ON_ZVAL) && watch->parent_container) { + if ((curTest = zend_hash_str_find(watch->parent_container, watch->name_in_parent, watch->name_in_parent_len))) { + while (Z_TYPE_P((zval *) curTest) == IS_INDIRECT) { + curTest = Z_INDIRECT_P((zval *) curTest); } - } else { - curTest = *(void **)curTest; - } - if (curTest != watch->addr.ptr) { - phpdbg_deactivate_watchpoint(watch TSRMLS_CC); - phpdbg_remove_watchpoint(watch TSRMLS_CC); - watch->addr.ptr = curTest; - phpdbg_store_watchpoint(watch TSRMLS_CC); - phpdbg_activate_watchpoint(watch TSRMLS_CC); + if (watch->type == WATCH_ON_HASHTABLE) { + switch (Z_TYPE_P((zval *) curTest)) { + case IS_ARRAY: + curTest = (void *) Z_ARRVAL_P((zval *) curTest); + break; + case IS_OBJECT: + curTest = (void *) Z_OBJPROP_P((zval *) curTest); + break; + } + } - reenable = 0; + if (curTest != watch->addr.ptr) { + phpdbg_deactivate_watchpoint(watch TSRMLS_CC); + phpdbg_remove_watchpoint(watch TSRMLS_CC); + watch->addr.ptr = curTest; + phpdbg_store_watchpoint(watch TSRMLS_CC); + phpdbg_activate_watchpoint(watch TSRMLS_CC); + + reenable = 0; + } + } else { + removed = 1; } } /* Show to the user what changed and delete watchpoint upon removal */ if (memcmp(oldPtr, watch->addr.ptr, watch->size) != SUCCESS) { - if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS || (watch->type == WATCH_ON_ZVAL && memcmp(oldPtr, watch->addr.zv, sizeof(zvalue_value))) || (watch->type == WATCH_ON_HASHTABLE -#if ZEND_DEBUG - && !watch->addr.ht->inconsistent -#endif - && zend_hash_num_elements((HashTable *)oldPtr) != zend_hash_num_elements(watch->addr.ht))) { + zend_bool do_break = 0; + + switch (watch->type) { + case WATCH_ON_ZVAL: + do_break = memcmp(oldPtr, watch->addr.zv, sizeof(zend_value) + sizeof(uint32_t) /* value + typeinfo */); + break; + case WATCH_ON_HASHTABLE: + do_break = zend_hash_num_elements((HashTable *) oldPtr) != zend_hash_num_elements(watch->addr.ht); + break; + case WATCH_ON_REFCOUNTED: + if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS) { + do_break = memcmp(oldPtr, watch->addr.ref, sizeof(uint32_t) /* no zend_refcounted metadata info */); + } + break; + } + + + if (do_break) { PHPDBG_G(watchpoint_hit) = 1; - phpdbg_notice("Breaking on watchpoint %s", watch->str); + phpdbg_notice("watchhit", "variable=\"%s\"", "Breaking on watchpoint %.*s", (int) watch->str_len, watch->str); + phpdbg_xml("<watchdata %r>"); } switch (watch->type) { case WATCH_ON_ZVAL: { - int removed = ((zval *)oldPtr)->refcount__gc != watch->addr.zv->refcount__gc && !zend_symtable_exists(watch->parent_container, watch->name_in_parent, watch->name_in_parent_len + 1); - int show_value = memcmp(oldPtr, watch->addr.zv, sizeof(zvalue_value)); - int show_ref = ((zval *)oldPtr)->refcount__gc != watch->addr.zv->refcount__gc || ((zval *)oldPtr)->is_ref__gc != watch->addr.zv->is_ref__gc; + int show_value = memcmp(oldPtr, watch->addr.zv, sizeof(zval) - sizeof(uint32_t) /* no metadata info */); if (removed || show_value) { - phpdbg_write("Old value: "); - if ((Z_TYPE_P((zval *)oldPtr) == IS_ARRAY || Z_TYPE_P((zval *)oldPtr) == IS_OBJECT) && removed) { - phpdbg_writeln("Value inaccessible, HashTable already destroyed"); + if (removed && (Z_TYPE_P((zval *) oldPtr) == IS_ARRAY || Z_TYPE_P((zval *) oldPtr) == IS_OBJECT)) { + phpdbg_writeln("watchvalue", "type=\"old\" inaccessible=\"inaccessible\"", "Old value inaccessible, array or object (HashTable) already destroyed"); } else { - zend_print_flat_zval_r((zval *)oldPtr TSRMLS_CC); - phpdbg_writeln(""); + phpdbg_out("Old value: "); + phpdbg_xml("<watchvalue %r type=\"old\">"); + zend_print_flat_zval_r((zval *) oldPtr TSRMLS_CC); + phpdbg_xml("</watchvalue>"); + phpdbg_out("\n"); } } - if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS && (removed || show_ref)) { - phpdbg_writeln("Old refcount: %d; Old is_ref: %d", ((zval *)oldPtr)->refcount__gc, ((zval *)oldPtr)->is_ref__gc); - } /* check if zval was removed */ if (removed) { - phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str); - zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); + phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Watchpoint %.*s was unset, removing watchpoint", (int) watch->str_len, watch->str); + zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); reenable = 0; - if (Z_TYPE_P((zval *)oldPtr) == IS_ARRAY || Z_TYPE_P((zval *)oldPtr) == IS_OBJECT) { - goto remove_ht_watch; + if (Z_REFCOUNTED_P((zval *) oldPtr)) { + phpdbg_remove_watch_collision(Z_COUNTED_P((zval *) oldPtr) TSRMLS_CC); } - break; } if (show_value) { - phpdbg_write("New value: "); + phpdbg_out("New value: "); + phpdbg_xml("<watchvalue %r type=\"new\">"); zend_print_flat_zval_r(watch->addr.zv TSRMLS_CC); - phpdbg_writeln(""); - } - if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS && show_ref) { - phpdbg_writeln("New refcount: %d; New is_ref: %d", watch->addr.zv->refcount__gc, watch->addr.zv->is_ref__gc); + phpdbg_xml("</watchvalue>"); + phpdbg_out("\n"); } - if ((Z_TYPE_P(watch->addr.zv) == IS_ARRAY && Z_ARRVAL_P(watch->addr.zv) != Z_ARRVAL_P((zval *)oldPtr)) || (Z_TYPE_P(watch->addr.zv) != IS_OBJECT && Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *)oldPtr))) { - /* add new watchpoints if necessary */ - if (watch->flags & PHPDBG_WATCH_RECURSIVE) { - phpdbg_create_recursive_watchpoint(watch TSRMLS_CC); + /* add new watchpoints if necessary */ + if (Z_PTR_P(watch->addr.zv) != Z_PTR_P((zval *) oldPtr)) { + if (Z_REFCOUNTED_P((zval *) oldPtr)) { + phpdbg_remove_watch_collision(Z_COUNTED_P((zval *) oldPtr) TSRMLS_CC); + } + if (Z_REFCOUNTED_P(watch->addr.zv)) { + if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS) { + phpdbg_writeln("watchrefcount", "type=\"new\" refcount=\"%d\"", "New refcount: %d", Z_COUNTED_P(watch->addr.zv)->refcount); + } + if (watch->flags & PHPDBG_WATCH_RECURSIVE) { + phpdbg_create_recursive_watchpoint(watch TSRMLS_CC); + } } - } - - if ((Z_TYPE_P((zval *)oldPtr) != IS_ARRAY || Z_ARRVAL_P(watch->addr.zv) == Z_ARRVAL_P((zval *)oldPtr)) && (Z_TYPE_P((zval *)oldPtr) != IS_OBJECT || Z_OBJ_HANDLE_P(watch->addr.zv) == Z_OBJ_HANDLE_P((zval *)oldPtr))) { - break; - } - -remove_ht_watch: - if ((htresult = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)Z_ARRVAL_P((zval *)oldPtr)))) { - htwatch = htresult->ptr; - zend_hash_del(&PHPDBG_G(watchpoints), htwatch->str, htwatch->str_len); } break; } case WATCH_ON_HASHTABLE: - -#if ZEND_DEBUG - if (watch->addr.ht->inconsistent) { - phpdbg_notice("Watchpoint %s was unset, removing watchpoint", watch->str); +#if 0 && ZEND_DEBUG + if (watch->addr.arr->ht->inconsistent) { + phpdbg_notice("watchdelete", "variable=\"%.*s\"", "Watchpoint %.*s was unset, removing watchpoint", (int) watch->str_len, watch->str); zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); reenable = 0; @@ -712,13 +735,12 @@ remove_ht_watch: break; } #endif - - elementDiff = zend_hash_num_elements((HashTable *)oldPtr) - zend_hash_num_elements(watch->addr.ht); + elementDiff = zend_hash_num_elements((HashTable *) oldPtr) - zend_hash_num_elements(watch->addr.ht); if (elementDiff) { if (elementDiff > 0) { - phpdbg_writeln("%d elements were removed from the array", elementDiff); + phpdbg_writeln("watchsize", "removed=\"%d\"", "%d elements were removed from the array", elementDiff); } else { - phpdbg_writeln("%d elements were added to the array", -elementDiff); + phpdbg_writeln("watchsize", "added=\"%d\"", "%d elements were added to the array", -elementDiff); /* add new watchpoints if necessary */ if (watch->flags & PHPDBG_WATCH_RECURSIVE) { @@ -726,10 +748,25 @@ remove_ht_watch: } } } - if (((HashTable *)oldPtr)->pInternalPointer != watch->addr.ht->pInternalPointer) { - phpdbg_writeln("Internal pointer of array was changed"); + if (watch->addr.ht->nInternalPointer != ((HashTable *) oldPtr)->nInternalPointer) { + phpdbg_writeln("watcharrayptr", "", "Internal pointer of array was changed"); + } + break; + case WATCH_ON_REFCOUNTED: { + if (PHPDBG_G(flags) & PHPDBG_SHOW_REFCOUNTS) { + phpdbg_writeln("watchrefcount", "type=\"old\" refcount=\"%d\"", "Old refcount: %d", ((zend_refcounted *) oldPtr)->refcount); + + if (!removed) { + phpdbg_writeln("watchrefcount", "type=\"old\" refcount=\"%d\"", "Old refcount: %d", ((zend_refcounted *) oldPtr)->refcount); + } } + break; + } + } + + if (do_break) { + phpdbg_xml("</watchdata>"); } } @@ -746,42 +783,46 @@ int phpdbg_print_changed_zvals(TSRMLS_D) { return FAILURE; } - dump = (phpdbg_watch_memdump **)zend_llist_get_last_ex(&PHPDBG_G(watchlist_mem), &pos); + dump = (phpdbg_watch_memdump **) zend_llist_get_last_ex(&PHPDBG_G(watchlist_mem), &pos); do { phpdbg_print_changed_zval(*dump TSRMLS_CC); - } while ((dump = (phpdbg_watch_memdump **)zend_llist_get_prev_ex(&PHPDBG_G(watchlist_mem), &pos))); + } while ((dump = (phpdbg_watch_memdump **) zend_llist_get_prev_ex(&PHPDBG_G(watchlist_mem), &pos))); zend_llist_clean(&PHPDBG_G(watchlist_mem)); - ret = PHPDBG_G(watchpoint_hit)?SUCCESS:FAILURE; + ret = PHPDBG_G(watchpoint_hit) ? SUCCESS : FAILURE; PHPDBG_G(watchpoint_hit) = 0; return ret; } void phpdbg_list_watchpoints(TSRMLS_D) { - HashPosition position; - phpdbg_watchpoint_t **watch; + phpdbg_watchpoint_t *watch; - for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(watchpoints), &position); - zend_hash_get_current_data_ex(&PHPDBG_G(watchpoints), (void**) &watch, &position) == SUCCESS; - zend_hash_move_forward_ex(&PHPDBG_G(watchpoints), &position)) { - phpdbg_writeln("%.*s", (int)(*watch)->str_len, (*watch)->str); - } + phpdbg_xml("<watchlist %r>"); + + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(watchpoints), watch) { + phpdbg_writeln("watchvariable", "variable=\"%.*s\" on=\"%s\" type=\"%s\"", "%.*s (%s, %s)", (int) watch->str_len, watch->str, watch->type == WATCH_ON_HASHTABLE ? "array" : watch->type == WATCH_ON_REFCOUNTED ? "refcount" : "variable", watch->flags == PHPDBG_WATCH_RECURSIVE ? "recursive" : "simple"); + } ZEND_HASH_FOREACH_END(); + + phpdbg_xml("</watchlist>"); } void phpdbg_watch_efree(void *ptr) { phpdbg_btree_result *result; TSRMLS_FETCH(); - result = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong)ptr); + result = phpdbg_btree_find_closest(&PHPDBG_G(watchpoint_tree), (zend_ulong) ptr); if (result) { phpdbg_watchpoint_t *watch = result->ptr; - if ((size_t)watch->addr.ptr + watch->size > (size_t)ptr) { - zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); + if ((size_t) watch->addr.ptr + watch->size > (size_t) ptr) { + if (watch->type == WATCH_ON_ZVAL) { + phpdbg_remove_watch_collision(Z_COUNTED_P(watch->addr.zv) TSRMLS_CC); + } + zend_hash_str_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); } } diff --git a/sapi/phpdbg/phpdbg_watch.h b/sapi/phpdbg/phpdbg_watch.h index 7a4e49ec8f..35cab10dc1 100644 --- a/sapi/phpdbg/phpdbg_watch.h +++ b/sapi/phpdbg/phpdbg_watch.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -25,7 +25,7 @@ #include "phpdbg_cmd.h" #ifdef _WIN32 -# include "phpdbg_win.h" +# include "phpdbg_win.h" #endif #define PHPDBG_WATCH(name) PHPDBG_COMMAND(watch_##name) @@ -37,47 +37,49 @@ PHPDBG_WATCH(array); PHPDBG_WATCH(delete); PHPDBG_WATCH(recursive); -/** - * Commands - */ - -static const phpdbg_command_t phpdbg_watch_commands[] = { - PHPDBG_COMMAND_D_EX(array, "create watchpoint on an array", 'a', watch_array, NULL, "s"), - PHPDBG_COMMAND_D_EX(delete, "delete watchpoint", 'd', watch_delete, NULL, "s"), - PHPDBG_COMMAND_D_EX(recursive, "create recursive watchpoints", 'r', watch_recursive, NULL, "s"), - PHPDBG_END_COMMAND -}; +extern const phpdbg_command_t phpdbg_watch_commands[]; /* Watchpoint functions/typedefs */ typedef enum { WATCH_ON_ZVAL, WATCH_ON_HASHTABLE, + WATCH_ON_REFCOUNTED, } phpdbg_watchtype; -#define PHPDBG_WATCH_SIMPLE 0x0 -#define PHPDBG_WATCH_RECURSIVE 0x1 +#define PHPDBG_WATCH_SIMPLE 0x0 +#define PHPDBG_WATCH_RECURSIVE 0x1 +#define PHPDBG_WATCH_ARRAY 0x2 +#define PHPDBG_WATCH_OBJECT 0x4 typedef struct _phpdbg_watchpoint_t phpdbg_watchpoint_t; struct _phpdbg_watchpoint_t { - phpdbg_watchpoint_t *parent; - HashTable *parent_container; - char *name_in_parent; - size_t name_in_parent_len; - char *str; - size_t str_len; union { zval *zv; HashTable *ht; + zend_refcounted *ref; void *ptr; } addr; size_t size; phpdbg_watchtype type; char flags; + phpdbg_watchpoint_t *parent; + HashTable *parent_container; + char *name_in_parent; + size_t name_in_parent_len; + char *str; + size_t str_len; }; +typedef struct { + phpdbg_watchpoint_t watch; + unsigned int num; + unsigned int refs; + HashTable watches; +} phpdbg_watch_collision; + void phpdbg_setup_watchpoints(TSRMLS_D); #ifndef _WIN32 @@ -102,11 +104,11 @@ void phpdbg_watch_efree(void *ptr); static long phpdbg_pagesize; static zend_always_inline void *phpdbg_get_page_boundary(void *addr) { - return (void *)((size_t)addr & ~(phpdbg_pagesize - 1)); + return (void *) ((size_t) addr & ~(phpdbg_pagesize - 1)); } static zend_always_inline size_t phpdbg_get_total_page_size(void *addr, size_t size) { - return (size_t)phpdbg_get_page_boundary((void *)((size_t)addr + size - 1)) - (size_t)phpdbg_get_page_boundary(addr) + phpdbg_pagesize; + return (size_t) phpdbg_get_page_boundary((void *) ((size_t) addr + size - 1)) - (size_t) phpdbg_get_page_boundary(addr) + phpdbg_pagesize; } #endif diff --git a/sapi/phpdbg/phpdbg_webdata_transfer.c b/sapi/phpdbg/phpdbg_webdata_transfer.c new file mode 100644 index 0000000000..2f18b9d082 --- /dev/null +++ b/sapi/phpdbg/phpdbg_webdata_transfer.c @@ -0,0 +1,170 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "phpdbg_webdata_transfer.h" +#include "ext/json/php_json.h" + +static int phpdbg_is_auto_global(char *name, int len TSRMLS_DC) { + int ret; + zend_string *str = zend_string_init(name, len, 0); + ret = zend_is_auto_global(str TSRMLS_CC); + efree(str); + return ret; +} + +PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC) { +#ifdef HAVE_JSON + smart_str buf = {0}; + zval array; + HashTable *ht; + zval zv[9] = {{{0}}}; + + array_init(&array); + ht = Z_ARRVAL(array); + + /* fetch superglobals */ + { + phpdbg_is_auto_global(ZEND_STRL("GLOBALS") TSRMLS_CC); + /* might be JIT */ + phpdbg_is_auto_global(ZEND_STRL("_ENV") TSRMLS_CC); + phpdbg_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC); + phpdbg_is_auto_global(ZEND_STRL("_REQUEST") TSRMLS_CC); + array_init(&zv[1]); + zend_hash_copy(Z_ARRVAL(zv[1]), &EG(symbol_table).ht, NULL); + Z_ARRVAL(zv[1])->pDestructor = NULL; /* we're operating on a copy! Don't double free zvals */ + zend_hash_str_del(Z_ARRVAL(zv[1]), ZEND_STRL("GLOBALS")); /* do not use the reference to itself in json */ + zend_hash_str_add(ht, ZEND_STRL("GLOBALS"), &zv[1]); + } + + /* save php://input */ + { + php_stream *stream; + zend_string *str; + + stream = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir)); + if ((str = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0))) { + ZVAL_STR(&zv[2], str); + } else { + ZVAL_EMPTY_STRING(&zv[2]); + } + Z_SET_REFCOUNT(zv[2], 1); + zend_hash_str_add(ht, ZEND_STRL("input"), &zv[2]); + } + + /* change sapi name */ + { + if (sapi_module.name) { + ZVAL_STRING(&zv[6], sapi_module.name); + } else { + Z_TYPE_INFO(zv[6]) = IS_NULL; + } + zend_hash_str_add(ht, ZEND_STRL("sapi_name"), &zv[6]); + Z_SET_REFCOUNT(zv[6], 1); + } + + /* handle modules / extensions */ + { + zend_module_entry *module; + zend_extension *extension; + zend_llist_position pos; + + array_init(&zv[7]); + ZEND_HASH_FOREACH_PTR(&module_registry, module) { + zval *value = ecalloc(sizeof(zval), 1); + ZVAL_STRING(value, module->name); + zend_hash_next_index_insert(Z_ARRVAL(zv[7]), value); + } ZEND_HASH_FOREACH_END(); + zend_hash_str_add(ht, ZEND_STRL("modules"), &zv[7]); + + array_init(&zv[8]); + extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos); + while (extension) { + zval *value = ecalloc(sizeof(zval), 1); + ZVAL_STRING(value, extension->name); + zend_hash_next_index_insert(Z_ARRVAL(zv[8]), value); + extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos); + } + zend_hash_str_add(ht, ZEND_STRL("extensions"), &zv[8]); + } + + /* switch cwd */ + if (SG(options) & SAPI_OPTION_NO_CHDIR) { + char *ret = NULL; + char path[MAXPATHLEN]; + +#if HAVE_GETCWD + ret = VCWD_GETCWD(path, MAXPATHLEN); +#elif HAVE_GETWD + ret = VCWD_GETWD(path); +#endif + if (ret) { + ZVAL_STRING(&zv[5], path); + Z_SET_REFCOUNT(zv[5], 1); + zend_hash_str_add(ht, ZEND_STRL("cwd"), &zv[5]); + } + } + + /* get system ini entries */ + { + zend_ini_entry *ini_entry; + + array_init(&zv[3]); + ZEND_HASH_FOREACH_PTR(EG(ini_directives), ini_entry) { + zval *value = ecalloc(sizeof(zval), 1); + if (ini_entry->modified) { + if (!ini_entry->orig_value) { + efree(value); + continue; + } + ZVAL_STR(value, ini_entry->orig_value); + } else { + if (!ini_entry->value) { + efree(value); + continue; + } + ZVAL_STR(value, ini_entry->value); + } + zend_hash_add(Z_ARRVAL(zv[3]), ini_entry->name, value); + } ZEND_HASH_FOREACH_END(); + zend_hash_str_add(ht, ZEND_STRL("systemini"), &zv[3]); + } + + /* get perdir ini entries */ + if (EG(modified_ini_directives)) { + zend_ini_entry *ini_entry; + + array_init(&zv[4]); + ZEND_HASH_FOREACH_PTR(EG(ini_directives), ini_entry) { + zval *value = ecalloc(sizeof(zval), 1); + if (!ini_entry->value) { + efree(value); + continue; + } + ZVAL_STR(value, ini_entry->value); + zend_hash_add(Z_ARRVAL(zv[4]), ini_entry->name, value); + } ZEND_HASH_FOREACH_END(); + zend_hash_str_add(ht, ZEND_STRL("userini"), &zv[4]); + } + + /* encode data */ + php_json_encode(&buf, &array, 0 TSRMLS_CC); + *msg = buf.s->val; + *len = buf.s->len; + zval_dtor(&array); +#endif +} diff --git a/sapi/phpdbg/phpdbg_webdata_transfer.h b/sapi/phpdbg/phpdbg_webdata_transfer.h new file mode 100644 index 0000000000..d70175ad99 --- /dev/null +++ b/sapi/phpdbg/phpdbg_webdata_transfer.h @@ -0,0 +1,27 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_WEBDATA_TRANSFER_H +#define PHPDBG_WEBDATA_TRANSFER_H + +#include "zend.h" +#include "phpdbg.h" + +PHPDBG_API void phpdbg_webdata_compress(char **msg, int *len TSRMLS_DC); + +#endif /* PHPDBG_WEBDATA_TRANSFER_H */ diff --git a/sapi/phpdbg/phpdbg_win.c b/sapi/phpdbg/phpdbg_win.c index b55abd9e1b..b0cbdf267a 100644 --- a/sapi/phpdbg/phpdbg_win.c +++ b/sapi/phpdbg/phpdbg_win.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ diff --git a/sapi/phpdbg/phpdbg_win.h b/sapi/phpdbg/phpdbg_win.h index 3f87c216f6..68c3052790 100644 --- a/sapi/phpdbg/phpdbg_win.h +++ b/sapi/phpdbg/phpdbg_win.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ diff --git a/sapi/phpdbg/tests/commands/0002_set.test b/sapi/phpdbg/tests/commands/0002_set.test index 468ac6d9ea..6a14a15adc 100644 --- a/sapi/phpdbg/tests/commands/0002_set.test +++ b/sapi/phpdbg/tests/commands/0002_set.test @@ -8,7 +8,7 @@ # setting error color # setting notice color # Failed to find breakpoint #0 -# oplog disabled +# [Oplog off] # opened oplog test.log # nothing ################################################# diff --git a/sapi/phpdbg/tests/commands/0102_print.test b/sapi/phpdbg/tests/commands/0102_print.test index de4acb7651..c174564e07 100644 --- a/sapi/phpdbg/tests/commands/0102_print.test +++ b/sapi/phpdbg/tests/commands/0102_print.test @@ -4,15 +4,14 @@ # expect: TEST::FORMAT # options: -rr ################################################# -#[User Class: test] -#Methods (3): +#[User Class: test (3 methods)] #L%d-%d test::testMethod() %s # L%d %s ZEND_RETURN C%d <unused> <unused> # L%d-%d test::testPrivateMethod() %s # L%d %s ZEND_RETURN C%d <unused> <unused> # L%d-%d test::testProtectedMethod() %s # L%d %s ZEND_RETURN C%d <unused> <unused> -#[User Method testMethod] +#[User Method testMethod (1 ops)] # L%d-%d test::testMethod() %s # L%d %s ZEND_RETURN C%d <unused> <unused> ################################################# diff --git a/sapi/phpdbg/tests/commands/0104_clean.test b/sapi/phpdbg/tests/commands/0104_clean.test index c7a579be17..d50903c479 100644 --- a/sapi/phpdbg/tests/commands/0104_clean.test +++ b/sapi/phpdbg/tests/commands/0104_clean.test @@ -4,11 +4,11 @@ # expect: TEST::FORMAT # options: -rr ################################################# -#[Cleaning Execution Environment] -#Classes %d -#Functions %d -#Constants %d -#Includes %d +#Cleaning Execution Environment +#Classes %d +#Functions %d +#Constants %d +#Includes %d #[Nothing to execute!] ################################################# clean diff --git a/sapi/phpdbg/tests/commands/0105_clear.test b/sapi/phpdbg/tests/commands/0105_clear.test index b547b0d6ba..8ce1002491 100644 --- a/sapi/phpdbg/tests/commands/0105_clear.test +++ b/sapi/phpdbg/tests/commands/0105_clear.test @@ -4,7 +4,7 @@ # expect: TEST::FORMAT # options: -rr ################################################# -#[Clearing Breakpoints] +#Clearing Breakpoints #File%w%d #Functions%w%d #Methods%w%d diff --git a/sapi/phpdbg/tests/commands/0106_compile.test b/sapi/phpdbg/tests/commands/0106_compile.test index 7193600ea3..b4d801670b 100644 --- a/sapi/phpdbg/tests/commands/0106_compile.test +++ b/sapi/phpdbg/tests/commands/0106_compile.test @@ -4,9 +4,9 @@ # expect: TEST::FORMAT # options: -rr ################################################# -#[Attempting compilation of %s] -#[Success] +#[Successful compilation of %s] #Hello World +#[Script ended normally] ################################################# <: define('OUT', diff --git a/sapi/phpdbg/tests/run-tests.php b/sapi/phpdbg/tests/run-tests.php index 1cc31d815e..4afb64561c 100644 --- a/sapi/phpdbg/tests/run-tests.php +++ b/sapi/phpdbg/tests/run-tests.php @@ -389,7 +389,7 @@ namespace phpdbg\testing { } break; default: { - $this->$chunks[0] = $chunks[1]; + $this->{$chunks[0]} = $chunks[1]; } } } else switch(substr($trim, 1, 1)) { diff --git a/sapi/phpdbg/xml.md b/sapi/phpdbg/xml.md new file mode 100644 index 0000000000..7871b31376 --- /dev/null +++ b/sapi/phpdbg/xml.md @@ -0,0 +1,651 @@ +phpdbg XML format +================= + +Common attributes +================= + +severity +-------- + +- indicates the genre of phpdbg system output +- usually one of these values: + - normal + - notice + - error + +msgout +------ + +- text message output related to the xml data (e.g. <intro severity="normal" help="help" msgout="To get help using phpdbg type &quot;help&quot; and press enter" />) + +req +--- + +- the request id, if one was passed to the last command (via -r %d, where %d is the id) (and the output is related to that message) + +file +---- + +- refers to a filename + +method +------ + +- format classname::methodname +- refers to a method + +function +-------- + +- refers to a function + +symbol +------ + +- either function or method (is method if "::" are present) + +opline +------ + +- in hexadecimal format +- refers to a specific pointer to a (zend_)op + +opcode +------ + +- refers to an opcode (ZEND_*) + +type +---- + +- general attribute for most errors, describes the genre of the error + +General tags +============ + +intro +----- + +- appears on startup if -q flag wasn't provided as command line arg +- before any input possibility +- attributes may be spread over multiple tags +- wrapped in <intros> tag + +### attributes ### + +- version: current phpdbg version (as string) +- help: command name for help +- report: URL for bug reporting + + +phpdbg +------ + +- general text message output from phpdbg system + +stream +------ + +- any output by PHP itself (e.g. <stream type="stdout">test</stream>) + +### attributes ### + +- type: stderr or stdout + +php +--- + +- php error output + +### attributes ### + +- msg: the error message + + +General error tags +================== + +command +------- + +- general errors about commands + +### possible attributes ### + +- type + - toomanyargs: more arguments than allowed + - noarg: argument missing + - wrongarg: wrong type of argument (e.g. letters instead of integer) + - toofewargs: not enough arguments + - notfound: command (or subcommand) doesn't exist + - ambiguous: command was ambiguous + - invalidcommand: command input is totally invalid + - (nostack: should not happen: is an internal error) + - (emptystack: should not happen: is an internal error) +- command: passed command +- subcommand: passed subcommand (present if the error is related to the subcommand) +- expected: count of expected arguments +- got: type of argument for type "wrongarg" +- num: if possible, information about which parameter had a wrong argument + +inactive +-------- + +- by type + - op_array: nothing was yet compiled (probably because no execution context set) + - symbol_table: no symbol table present (not yet initiailized or already destructed) + - noexec: not in execution + - memory_manager: using the native memory manager (malloc, free, realloc) instead of e.g. the Zend MM + - notfound: file not found + - nocontext: execution context was not set (or compilation had failed) + - isrunning: command requires no running script + + +Commands +======== + +export +------ + +- tag: <exportbreakpoint /> +- usually triggered by successful export command +- may appear when cleaning to temporary store breakpoints +- errors by type + - openfailure: could not create file + +### attributes ### + +- count: number of exported breakpoints + +break / info break +------------------ + +- General tag for breakpoint creation, deletion and hits is "<breakpoint />" + +### possible attributes ### + +- id: the breakpoint id (if the leave command was executed, the id has the value "leave") +- num: the nth opline of a function/method/file +- add: has value "success"/"fail": a brekpoint was successfully/not added +- pending: the breakpoint is waiting for resolving (e.g. a file opline on a not yet loaded file) +- deleted: has value "success"/"fail": a breakpoint was successfully/not deleted +- eval: the condition on conditional breakpoints +- file +- opline +- opcode +- symbol +- function +- method +- line + + +- listing breakpoints always in a container element "<breakpoints>" + - Child nodes: + - function + - method + - file + - opline + - methodopline + - functionopline + - fileopline + - evalfunction + - evalfunctionopline + - evalmethod + - evalmethodopline + - evalfile + - evalopline + - eval + - opcode + - attributes: + - name: name of the symbol (function/method/file/opcode) + - disabled: empty value if enabled, non-empty if enabled + +- errors (by type) + - exists: the breakpoint already exists + - maxoplines: tries to break at an opline (usedoplinenum) higher than the number of present oplines (in maxoplinenum) + - nomethod: method doesn't exist + - internalfunction: one cannot break on an opline of an internal function + - notregular: tries to set a breakpoint in not a regular file + - (invalidparameter: should not happen: is an internal error) + +frame +----- + +- General tag for frames is "<frame>" +- always has id attribute; if it only has id attribute, it just indicates current frame number, no other elements follow +- may contain other elements (of type <arg>) when contained in <backtrace> tag +- <arg> always contains a <stream> element, the value of the variable + +### possible attributes ### + +- id: the frame id, current frame has id 0 (frames with internal function calls have the same id than their called frame) +- symbol ("{main}" is root frame) +- file +- line +- internal: has value "internal" when being an internal function call (one cannot inspect that frame) + +- being an error: (by type) + - maxnum: tried to access a frame with a number heigher than existing (or < 0) + +### attributes on <arg> ### + +- variadic: has a non-empty value if the argument is variadic +- name: variable name of parameter + +info (subcommands) +------------------ + +### break ### + +- See above ("break / info break") + +### files ### + +- lists included files +- <includedfileinfo num="" /> with num having an integer value, indicating the number of included files +- <includedfile name=""/>: one per file, with name being the file path of the included file + +### error ### + +- gets last error +- <lasterror error="" (file="" line="") /> +- error attribute contains the last error as a string, is empty if there's no last error + +### vars / globals ### + +- <variableinfo num="" /> with num having an integer value, indicating the number of (local or superglobal) variables +- if info vars was used it'll have also one of these attributes: + - method + - function + - file + - opline +- for each variable there is a <variable> followed by a <variabledetails> element +- <variable address="" refcount="" type="" name="" /> + - address: pointer to zval (hexadecimal) + - refcount: refcount of zval + - type: the variable type (long, string, ...). If the value is "unknown", the other attributes are meaningless + - name: the name of the variable + - refstatus: empty if the zval is not a reference + - class: the class the object in the zval is an instance of + - resource: the type of the resource in the zval + +### literal ### + +- <literalinfo num="" /> with num having an integer value, indicating the number of literals, optional arguments are: + - method + - function + - file + - opline +- for each literal there is a <literal> followed by a <stream type="stdout"> which prints the value of the literal +- <literal id="" />: where id is the internal identifier of the literal + +### memory ### + +- Format: + + <meminfo /> + <current /> + <used mem="" /> + <real mem="" /> + <peak /> + <used mem="" /> + <real mem="" /> + +- mem is an attribute whose value is a float. The memory is given in kilobytes (1 kB == 1024 bytes) + +### classes ### + +- <classinfo num="" /> with num having an integer value, indicating the number of loaded user-defined classes +- Each class is enumerated with first a <class>, then an optional <parents> container and then a <classsource> element +- The <parents> container contains the <class> elements of the parent of the last <class> element. +- <class type="" flags="" name="" methodcount="" /> + - type: either "User" or "Internal" + - flags: either "Interface", "Class" or "Abstract Class" +- <classsource /> where the class was defined, if there are no attributes, location is unknown, usually defined by + - file + - line + +### funcs ### + +- <functioninfo num="" /> with num having an integer value, indicating the number of loaded user-defined functions +- Each class is enumerated with first a <function> and then a <functionsource> element +- <function name="" /> +- <functionsource /> where the function was defined, if there are no attributes, location is unknown, usually defined by + - file + - line + +list +---- + +- consists of <line> elements wrapped in a <list> container +- <list file=""> is the container element with file being the filename +- <line line="" code="" /> with value of code being the whole line of code in the line specified in the line attribute + - current: this attribute is set to "current" if that line is the line where the executor currently is + +print +----- + +### without a subcommand ### + +- <print> elements are wrapped in a <printinfo> element +- there may be a variable number of <print> elements with a variable count of args inside the <printinfo> element +- possible args are: + - readline: yes/no - readline enabled or disabled + - libedit: yes/no - libedit enabled or disabled + - context: current executing context + - compiled: yes/no - are there actual compiled ops? + - stepping: @@ TODO (meaningless for now) @@ + - quiet: on/off - should it always print the opline being currently executed? + - oplog: on/off - are oplines logged in a file? + - ops: number of opcodes in current executing context + - vars: number of compiled variables (CV) + - executing: yes/no - in executor? + - vmret: the return value of the last executed opcode + - default: continue + - 1: return from vm + - 2: enter stack frame + - 3: leave stack frame + - classes: number of classes + - functions: number of functions + - constants: number of constants + - includes: number of included files + +### with a subcommand ### + +- introduced by <printinfo num="" /> (except for print opline) with num being the number of opcodes and one of these args: + - file + - method + - function + - class (then also type and flags attributes, see info classes command for their meanings) + - symbol (also type and flags attributes; here the value of flags is either "Method" or "Function") +- if there is a class method, the methods are all wrapped in a <printmethods> container +- then comes a <printoplineinfo type="" /> where type is either "User" or "Internal" +- the <printoplineinfo> has either a method or a function attribute +- if the type is "Internal" + - there are no oplines, it's an internal method or function +- if the type is "User" + - it has these attributes + - startline: the first line of code where the method or function is defined + - endline: the lastt line of code where the method or function is defined + - file: the file of code where the method or function is defined + - is followed by the oplines of that method or function (<print> elements) +- <print line="%u" opline="%p" opcode="%s" op="%s" /> +- in case of print opline it emits a single <opline line="" opline="" opcode="" op="" file="" /> + +exec +---- + +- command executing and compiling a given file + - <exec type="unset" context="" />: indicates unsetting of the old context + - <exec type="unsetops" />: indicates unsetting of the old compiled opcodes + - <exec type="unchanged" />: same execution context choosen again + - <exec type="set" context="" />: indicates setting of the new context +- errors by tag + - <compile> + - openfailure: couldn't open file + - compilefailure: The file indicated in context couldn't be compiled + - <exec> + - invalid: given context (attribute) is not matching a valid file or symlink + - notfound: given context (attribute) does not exist + +run / <stop> tag +------------------- + +- runs the script (set via exec command) +- <stop type="end" />: script execution ended normally +- (error) <stop type="bailout" /> the VM bailed out (usually because there was some error) +- compile failures see under exec, errors, <compile> + +step +---- + +- steps by one line or opcode (as defined via set stepping) default is one line +- returns back to the executor + +continue +-------- + +- returns back to the executor + +until +----- + +- temporarily disables all the breakpoints on that line until that line was left once +- returns back to the executor + +finish +------ + +- temporarily disables all the breakpoints until the end of the current frame +- returns back to the executor + +leave +------ + +- temporarily disables all the breakpoints past the end of the current frame and then stops +- returns back to the executor + +back +---- + +- prints backtrace +- see frame command + +ev +-- + +- eval()uates some code +- output wrapped in <eval> tags + +sh +-- + +- executes shell command +- still pipes to stdout ... without wrapping <stream> !!! (@@ TODO @@) + +source +------ + +- executes a file in .phpdbginit format +- errors by type + - notfound: file not found + +register +-------- + +- registers a function to be used like a command +- <register function="" />: successfully registered function +- errors by type + - notfound: no such function + - inuse: function already registered + +quit +---- + +- quits phpdbg +- if successful connection will be closed... + +clean +----- + +- cleans environment (basically a shutdown + new startup) +- <clean> tags wrapped in a <cleaninfo> container +- possible attributes of <clean> tag + - classes: number of classes + - functions: number of functions + - constants: number of constants + - includes: number of included files + +clear +----- + +- removes all breakpoints +- <clear> tags wrapped in a <clearinfo> container +- possible attributes of <clear> tag (value is always the number of defined breakpoints of that type) + - files + - functions + - methods + - oplines + - fileoplines + - functionoplines + - methodoplines + - eval + +watch +----- + +- watchpoints generally are identified by a variable (one may need to switch frames first...) +- <watch variable="" />, <watchrecursive variable="" /> and <watcharray variable="" /> (normal, array, recursive) +- <watch> if error, by type: + - undefined: tried to set a watchpoint on a not (yet) defined variable + - notiterable: element which is tried to be accessed as an object or array is nor array nor object + - invalidinput: generally malformed input +- <watchdelete variable="" />: when "watch delete" was used on a watchpoint +- (error) <watchdelete type="nowatch" />: that watchpoint doesn't exist, so couldn't be deleted +- for hit watchpoints etc., see Other tags, <watch*> +- when using watch list, <watchvariable> elements are wrapped in a <watchlist> container + - <watchvariable variable="" on="" type="" /> + - variable: watched variable (may be a variable of another scope!) + - on: values are array or variable, depending on what is watched + - type: values are recursive or simple, depending on whether the watchpoint is checked recursively or not + +set +--- + +- a general error is type="wrongargs" where a wrong argument was passed to a subcommand; tag is then <set*> + +### prompt ### + +- without other args, a <setpromt str="" /> tag is emitted where the value of the str attribue is the value of the prompt +- when there is another arg, the prompt is changed to that arg, no further xml answer + +### break ### + +- enables / disables a given breakpoint silently with no further xml answer +- if the boolean switch is omitted, it emits current state in a <setbreak id="" active="" /> where active is on or off +- error with type="nobreak", when no breakpoint with the given id exists + +### breaks ### + +- generally enables / disables breakpoint functionality silently with no futher xml answer +- if the boolean switch is omitted, it emits current state in a <setbreaks active="" /> where active is on or off + +### color ### + +- sets the color on prompt, error or notices +- <setcolor type="" color="" code="" />: code is the color code of color, type is either: + - prompt + - error + - notice +- errors by type: + - nocolor: color doesn't exist + - invalidtype: type wasn't one of the three allowed types + +### colors ### + +- generally enables / disables colors silently with no further xml answer +- if the boolean switch is omitted, it emits current state in a <setcolors active="" /> where active is on or off + +### oplog ### + +- sets oplog +- (error) <setoplog type="openfailure" file="" /> when it couldn't open the passed file path +- <setoplog type="closingold" /> is emitted when there was a previous open oplog (and a file is passed) +- if no further argument is passed, it emits current state in a <setoplog active="" /> where active is on or off + +### quiet ### + +- generally enables / disables quietness silently with no further xml answer +- if the boolean switch is omitted, it emits current state in a <setquiet active="" /> where active is on or off + +### setpping ### + +- sets stepping to either opcode or line (so a step command will either advance one op or one line) +- if no further argument is passed, it emits current state in a <setoplog type="" /> where active is opcode or line + +### refcount ### + +- generally enables / disables showing of refcount in watchpoint breaks silently with no further xml answer +- if the boolean switch is omitted, it emits current state in a <setrefcount active="" /> where active is on or off + +wait +---- + +- internally executes exec, so exec will output first (if binding to socket worked) + +### attributes ### + +- import: has value "success"/"fail" +- missingmodule/missingextension: modules/extensions loaded in the target SAPI, but not in phpdbg + +### errors (by type) ### + +- nosocket: couldn't establish socket +- invaliddata: invalid JSON passed to socket + +dl +-- + +- loads a module or Zend extension at a given path +- if a relative path is passed, it's relative to the extension_dir ini setting + +### attributes ### + +- extensiontype: "Zend extension" or "module" +- name: the extension name +- path: the path where it was loaded + +### errors (by type) ### + +- unsupported: dynamic extension loading is unsupported +- relpath: relative path given, but no extension_dir defined +- unknown: general error with internal DL_LOAD() (for message see msg attribute) +- wrongapi: wrong Zend engine version (apineeded / apiinstalled attributes give information about the API versions) +- wrongbuild: unmatched build versions (buildneeded / buildinstalled attributes give information about the build versions) +- registerfailure: registering module failed +- startupfailure: couldn't startup Zend extension / module +- initfailure: couldn't initialize module +- nophpso: passed shared object is not a valid Zend extension nor module + +- errors may have the module or extension attribute when their name is already known at the point of failure + +Other tags +========== + +<signal> +----------- + +- received caught signal + +### attributes ### + +- type: type of signal (e.g. SIGINT) + +### by type ### + +- SIGINT: interactive mode is entered... + +<watch*> +----------- + +- generally emitted on hit watchpoint +- <watchdelete variable="" />: when a variable was unset, the watchpoint is removed too +- <watchhit variable="" />: when ever a watched variable is changed, followed by a <watchdata> container +- <watchdata> may contain + - for watchpoints on variables: + - each of these <watch*> tags conatins a type attribute whose value is either "old" or "new") + - <watchvalue type="" inaccessible="inaccessible" />: old value is inaccessible + - <watchvalue type=""> may contain a <stream> element which indicates the old/new (type attribute) value of the variable + - <watchrefcount type="" refcount="" isref="" />: old/new (type attribute) refcount and isref, both numbers + - isref: if the value is 0, it's not a reference, else it is one + - for watchpoints on arrays: + - <watchsize> inspects size variations of an array (the sum): + - removed: number of elements removed + - added: number of elements added + - <watcharrayptr>: if this tag appears, the internal pointer of the array way changed + +<signalsegv> +--------------- + +- generally emitted when data couldn't be fetched (e.g. by accessing inconsistent data); only used in hard interrupt mode +- it might mean that data couldn't be fetched at all, or that only incomplete data was fetched (e.g. when a fixed number of following attributes are fetched, this tag will mark a stop of fetching if none or not all tags were printed) diff --git a/sapi/phpdbg/zend_mm_structs.h b/sapi/phpdbg/zend_mm_structs.h new file mode 100644 index 0000000000..ca64069e0f --- /dev/null +++ b/sapi/phpdbg/zend_mm_structs.h @@ -0,0 +1,102 @@ +#ifndef ZEND_MM_STRUCTS_H +#define ZEND_MM_STRUCTS_H + +/* structs and macros defined in Zend/zend_alloc.c + Needed for realizing watchpoints and sigsafe memory */ + +#include "zend.h" + +#ifndef ZEND_MM_COOKIES +# define ZEND_MM_COOKIES ZEND_DEBUG +#endif + +#define ZEND_MM_CACHE 1 +#ifndef ZEND_MM_CACHE_STAT +# define ZEND_MM_CACHE_STAT 0 +#endif + +typedef struct _zend_mm_block_info { +#if ZEND_MM_COOKIES + size_t _cookie; +#endif + size_t _size; + size_t _prev; +} zend_mm_block_info; + +typedef struct _zend_mm_small_free_block { + zend_mm_block_info info; +#if ZEND_DEBUG + unsigned int magic; +#ifdef ZTS + THREAD_T thread_id; +#endif +#endif + struct _zend_mm_free_block *prev_free_block; + struct _zend_mm_free_block *next_free_block; +} zend_mm_small_free_block; + +typedef struct _zend_mm_free_block { + zend_mm_block_info info; +#if ZEND_DEBUG + unsigned int magic; +#ifdef ZTS + THREAD_T thread_id; +#endif +#endif + struct _zend_mm_free_block *prev_free_block; + struct _zend_mm_free_block *next_free_block; + + struct _zend_mm_free_block **parent; + struct _zend_mm_free_block *child[2]; +} zend_mm_free_block; + +#define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \ + (zend_mm_free_block *) ((char *)&heap->free_buckets[index * 2] + \ + sizeof(zend_mm_free_block *) * 2 - \ + sizeof(zend_mm_small_free_block)) + +#define ZEND_MM_REST_BUCKET(heap) \ + (zend_mm_free_block *)((char *)&heap->rest_buckets[0] + \ + sizeof(zend_mm_free_block *) * 2 - \ + sizeof(zend_mm_small_free_block)) + +#define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3) +struct _zend_mm_heap { + int use_zend_alloc; + void *(*_malloc)(size_t); + void (*_free)(void *); + void *(*_realloc)(void *, size_t); + size_t free_bitmap; + size_t large_free_bitmap; + size_t block_size; + size_t compact_size; + zend_mm_segment *segments_list; + zend_mm_storage *storage; + size_t real_size; + size_t real_peak; + size_t limit; + size_t size; + size_t peak; + size_t reserve_size; + void *reserve; + int overflow; + int internal; +#if ZEND_MM_CACHE + unsigned int cached; + zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS]; +#endif + zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2]; + zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS]; + zend_mm_free_block *rest_buckets[2]; + int rest_count; +#if ZEND_MM_CACHE_STAT + struct { + int count; + int max_count; + int hit; + int miss; + } cache_stat[ZEND_MM_NUM_BUCKETS+1]; +#endif +}; + +#endif diff --git a/travis/compile.sh b/travis/compile.sh index 20228cda5a..9add843a2e 100755 --- a/travis/compile.sh +++ b/travis/compile.sh @@ -13,6 +13,7 @@ fi ./configure --quiet \ $DEBUG \ $TS \ +--enable-phpdbg \ --enable-fpm \ --with-pdo-mysql=mysqlnd \ --with-mysql=mysqlnd \ |