diff options
author | Anatol Belski <ab@php.net> | 2014-10-24 22:28:32 +0200 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2014-10-24 22:28:32 +0200 |
commit | c51a42076c0f92988115a25068b8ab01dfb8a6ff (patch) | |
tree | 87e1a4f1eec114067ca1d66beb02fb7ddd477cd6 | |
parent | 9cbdf3e66a76895861b6f39e1b1ef5cc46d76654 (diff) | |
parent | 1b4fd5825a820873e4ed0f326bcb890e660dc39c (diff) | |
download | php-git-c51a42076c0f92988115a25068b8ab01dfb8a6ff.tar.gz |
Merge remote-tracking branch 'origin/master' into native-tls
* origin/master: (214 commits)
fix datatype mismatch warnings
fix datatype mismatches
fix datatype mismatches
fix datatype mismatches
fix datatype mismatch warnings
fix datatype mismatch warnings
fix datatype mismatch warnings
fix datatype mismatch warning
fix datatype mismatches
fix datatype mismatch warnings
Re-add phpdbg to travis
Added some NEWS
Make xml valid (missing space between attrs)
Fix info classes file name in xml
Add note about <eval> tag for errors in xml.md
Name the tag <eval> if the error id during ev cmd
Do not print out xml as PHP print...
Fix output to wrong function
Fixed parameter order on %.*s
Too much copypaste...
...
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 \ |