diff options
author | Nikita Popov <nikic@php.net> | 2014-08-16 21:55:08 +0200 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2014-08-16 21:55:08 +0200 |
commit | 71675a4bf830d7b9400663275fe48275480d34f4 (patch) | |
tree | 8ce9b1fdda30d26121334fb5c228df7884f6f7c2 /Zend | |
parent | f72d6f97ecf976f00abc0dc21b5d1ef4838de60a (diff) | |
parent | 8b66d64b2343bc4fd8aeabb690024edb850a0155 (diff) | |
download | php-git-71675a4bf830d7b9400663275fe48275480d34f4.tar.gz |
Merge remote-tracking branch 'php-src/phpng' into ast
Conflicts:
Zend/zend_ast.c
Zend/zend_compile.c
Zend/zend_language_parser.y
Incomplete merge!
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/tests/constant_expressions_arrays.phpt | 35 | ||||
-rw-r--r-- | Zend/tests/constant_expressions_self_referencing_array.phpt | 2 | ||||
-rw-r--r-- | Zend/tests/errmsg_040.phpt | 12 | ||||
-rw-r--r-- | Zend/tests/gc_029.phpt | 4 | ||||
-rw-r--r-- | Zend/tests/ns_059.phpt | 5 | ||||
-rw-r--r-- | Zend/zend.c | 63 | ||||
-rw-r--r-- | Zend/zend.h | 2 | ||||
-rw-r--r-- | Zend/zend_API.c | 4 | ||||
-rw-r--r-- | Zend/zend_API.h | 261 | ||||
-rw-r--r-- | Zend/zend_ast.c | 29 | ||||
-rw-r--r-- | Zend/zend_compile.c | 39 | ||||
-rw-r--r-- | Zend/zend_compile.h | 11 | ||||
-rw-r--r-- | Zend/zend_constants.c | 6 | ||||
-rw-r--r-- | Zend/zend_execute.c | 88 | ||||
-rw-r--r-- | Zend/zend_execute.h | 5 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 1 | ||||
-rw-r--r-- | Zend/zend_gc.c | 129 | ||||
-rw-r--r-- | Zend/zend_gc.h | 5 | ||||
-rw-r--r-- | Zend/zend_hash.c | 5 | ||||
-rw-r--r-- | Zend/zend_hash.h | 11 | ||||
-rw-r--r-- | Zend/zend_ini.c | 4 | ||||
-rw-r--r-- | Zend/zend_multibyte.c | 4 | ||||
-rw-r--r-- | Zend/zend_object_handlers.c | 23 | ||||
-rw-r--r-- | Zend/zend_operators.c | 24 | ||||
-rw-r--r-- | Zend/zend_ts_hash.c | 33 | ||||
-rw-r--r-- | Zend/zend_ts_hash.h | 35 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 22 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 174 |
28 files changed, 690 insertions, 346 deletions
diff --git a/Zend/tests/constant_expressions_arrays.phpt b/Zend/tests/constant_expressions_arrays.phpt index 061fcc6a92..2ab03453de 100644 --- a/Zend/tests/constant_expressions_arrays.phpt +++ b/Zend/tests/constant_expressions_arrays.phpt @@ -22,7 +22,7 @@ class foo { var_dump(foo::bar); -var_dump(a); // Eventually allow that later with array dereferencing of constants +var_dump(a, a[0], a[2], a[2][1], a[3]); ?> --EXPECTF-- @@ -32,4 +32,35 @@ int(1) int(4) int(1) -Fatal error: Arrays are not allowed in constants at run-time in %s on line %d +Notice: Undefined offset: 3 in %s on line %d +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + array(2) { + [0]=> + int(3) + [1]=> + array(1) { + [0]=> + int(4) + } + } +} +int(1) +array(2) { + [0]=> + int(3) + [1]=> + array(1) { + [0]=> + int(4) + } +} +array(1) { + [0]=> + int(4) +} +NULL diff --git a/Zend/tests/constant_expressions_self_referencing_array.phpt b/Zend/tests/constant_expressions_self_referencing_array.phpt index 09f862e048..ae76a08602 100644 --- a/Zend/tests/constant_expressions_self_referencing_array.phpt +++ b/Zend/tests/constant_expressions_self_referencing_array.phpt @@ -1,7 +1,5 @@ --TEST-- Self-referencing constant expression (part of a constant AST) ---XFAIL-- -Not yet fixed, to be fixed for PHP 5.6 --FILE-- <?php class A { diff --git a/Zend/tests/errmsg_040.phpt b/Zend/tests/errmsg_040.phpt index f3d0afcf0a..d5d2bf38d3 100644 --- a/Zend/tests/errmsg_040.phpt +++ b/Zend/tests/errmsg_040.phpt @@ -6,8 +6,16 @@ errmsg: arrays are not allowed in class constants class test { const TEST = array(1,2,3); } - +var_dump(test::TEST); echo "Done\n"; ?> --EXPECTF-- -Fatal error: Arrays are not allowed in class constants in %s on line %d +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +Done diff --git a/Zend/tests/gc_029.phpt b/Zend/tests/gc_029.phpt index 18fef3c7d7..3873d8becd 100644 --- a/Zend/tests/gc_029.phpt +++ b/Zend/tests/gc_029.phpt @@ -33,5 +33,5 @@ unset($foo); unset($bar); var_dump(gc_collect_cycles()); ?> ---EXPECT-- -int(3) +--EXPECTREGEX-- +int\([23]\) diff --git a/Zend/tests/ns_059.phpt b/Zend/tests/ns_059.phpt index ea66037b43..301a6fc830 100644 --- a/Zend/tests/ns_059.phpt +++ b/Zend/tests/ns_059.phpt @@ -3,6 +3,7 @@ --FILE-- <?php const C = array(); +var_dump(C); --EXPECTF-- -Fatal error: Arrays are not allowed as constants in %sns_059.php on line 2 - +array(0) { +} diff --git a/Zend/zend.c b/Zend/zend.c index 5ab8ee3eb4..8bcdbd82c2 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -212,7 +212,7 @@ static void print_flat_hash(HashTable *ht TSRMLS_DC) /* {{{ */ } /* }}} */ -ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy) /* {{{ */ +ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy TSRMLS_DC) /* {{{ */ { if (Z_TYPE_P(expr) == IS_STRING) { return 0; @@ -221,15 +221,16 @@ ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy) /* {{{ */ again: switch (Z_TYPE_P(expr)) { case IS_NULL: - case IS_FALSE: { - TSRMLS_FETCH(); + case IS_FALSE: ZVAL_EMPTY_STRING(expr_copy); - break; - } + break; case IS_TRUE: - // TODO: use interned string ??? - ZVAL_NEW_STR(expr_copy, STR_INIT("1", 1, 0)); - break; + if (CG(one_char_string)['1']) { + ZVAL_INT_STR(expr_copy, CG(one_char_string)['1']); + } else { + ZVAL_NEW_STR(expr_copy, STR_INIT("1", 1, 0)); + } + break; case IS_RESOURCE: { char buf[sizeof("Resource id #") + MAX_LENGTH_OF_LONG]; int len; @@ -244,35 +245,31 @@ again: ZVAL_NEW_STR(expr_copy, STR_INIT("Array", sizeof("Array") - 1, 0)); break; case IS_OBJECT: - { - TSRMLS_FETCH(); - - if (Z_OBJ_HANDLER_P(expr, cast_object)) { - Z_ADDREF_P(expr); - if (Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_STRING TSRMLS_CC) == SUCCESS) { - zval_ptr_dtor(expr); - break; - } + if (Z_OBJ_HANDLER_P(expr, cast_object)) { + Z_ADDREF_P(expr); + if (Z_OBJ_HANDLER_P(expr, cast_object)(expr, expr_copy, IS_STRING TSRMLS_CC) == SUCCESS) { zval_ptr_dtor(expr); + break; } - if (!Z_OBJ_HANDLER_P(expr, cast_object) && Z_OBJ_HANDLER_P(expr, get)) { - zval rv; - zval *z = Z_OBJ_HANDLER_P(expr, get)(expr, &rv TSRMLS_CC); - - Z_ADDREF_P(z); - if (Z_TYPE_P(z) != IS_OBJECT) { - if (zend_make_printable_zval(z, expr_copy)) { - zval_ptr_dtor(z); - } else { - ZVAL_ZVAL(expr_copy, z, 0, 1); - } - return 1; + zval_ptr_dtor(expr); + } + if (!Z_OBJ_HANDLER_P(expr, cast_object) && Z_OBJ_HANDLER_P(expr, get)) { + zval rv; + zval *z = Z_OBJ_HANDLER_P(expr, get)(expr, &rv TSRMLS_CC); + + Z_ADDREF_P(z); + if (Z_TYPE_P(z) != IS_OBJECT) { + if (zend_make_printable_zval(z, expr_copy TSRMLS_CC)) { + zval_ptr_dtor(z); + } else { + ZVAL_ZVAL(expr_copy, z, 0, 1); } - zval_ptr_dtor(z); + return 1; } - zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %s could not be converted to string", Z_OBJCE_P(expr)->name->val); - ZVAL_EMPTY_STRING(expr_copy); + zval_ptr_dtor(z); } + zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %s could not be converted to string", Z_OBJCE_P(expr)->name->val); + ZVAL_EMPTY_STRING(expr_copy); break; case IS_DOUBLE: ZVAL_DUP(expr_copy, expr); @@ -540,7 +537,7 @@ static void compiler_globals_dtor(zend_compiler_globals *compiler_globals TSRMLS free(compiler_globals->static_members_table); } if (compiler_globals->script_encoding_list) { - pefree(compiler_globals->script_encoding_list, 1); + pefree((char*)compiler_globals->script_encoding_list, 1); } compiler_globals->last_static_member = 0; } diff --git a/Zend/zend.h b/Zend/zend.h index 5548c7be1b..0520d4dda1 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -609,7 +609,7 @@ END_EXTERN_C() BEGIN_EXTERN_C() ZEND_API char *get_zend_version(void); -ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy); +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 void zend_print_zval_r(zval *expr, int indent TSRMLS_DC); diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 5baa26ea54..9881740c06 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -249,7 +249,7 @@ static int parse_arg_object_to_string(zval *arg, char **p, int *pl, int type TSR if(Z_TYPE_P(z) != IS_OBJECT) { zval_dtor(arg); ZVAL_NULL(arg); - if (!zend_make_printable_zval(z, arg)) { + if (!zend_make_printable_zval(z, arg TSRMLS_CC)) { ZVAL_ZVAL(arg, z, 1, 1); } *pl = Z_STRLEN_P(arg); @@ -288,7 +288,7 @@ ZEND_API int parse_arg_object_to_str(zval *arg, zend_string **str, int type TSRM if(Z_TYPE_P(z) != IS_OBJECT) { zval_dtor(arg); ZVAL_NULL(arg); - if (!zend_make_printable_zval(z, arg)) { + if (!zend_make_printable_zval(z, arg TSRMLS_CC)) { ZVAL_ZVAL(arg, z, 1, 1); } *str = Z_STR_P(arg); diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 3a242c249e..b40afc162f 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -248,7 +248,7 @@ ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TS /* Parameter parsing API -- andrei */ -#define ZEND_PARSE_PARAMS_QUIET 1<<1 +#define ZEND_PARSE_PARAMS_QUIET (1<<1) ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC, const char *type_spec, ...); ZEND_API int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, const char *type_spec, ...); ZEND_API char *zend_zval_type_name(const zval *arg); @@ -646,6 +646,7 @@ END_EXTERN_C() } \ } while (0) #else // attempt to support calls to parent::__construct() ??? + // see: ext/date/tests/bug67118.phpt #define ZEND_CTOR_MAKE_NULL() do { \ if (EG(current_execute_data)->return_value) { \ zval_ptr_dtor(EG(current_execute_data)->return_value); \ @@ -716,53 +717,61 @@ ZEND_API void zend_wrong_paramer_class_error(int num, char *name, zval *arg TSRM ZEND_API void zend_wrong_callback_error(int severity, int num, char *error TSRMLS_DC); ZEND_API int _z_param_class(zval *arg, zend_class_entry **pce, int num, int check_null TSRMLS_DC); +#define ZPP_ERROR_OK 0 +#define ZPP_ERROR_FAILURE 1 +#define ZPP_ERROR_WRONG_CALLBACK 2 +#define ZPP_ERROR_WRONG_CLASS 3 +#define ZPP_ERROR_WRONG_ARG 4 +#define ZPP_ERROR_WRONG_COUNT 5 + #define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \ const int _flags = (flags); \ int _min_num_args = (min_num_args); \ int _max_num_args = (max_num_args); \ int _num_args = EG(current_execute_data)->num_args; \ int _i; \ - zval *_real_arg, *_arg; \ - zend_expected_type _expected_type; \ - char *_error; \ + zval *_real_arg, *_arg = NULL; \ + zend_expected_type _expected_type = IS_UNDEF; \ + char *_error = NULL; \ zend_bool _dummy; \ + zend_bool _optional = 0; \ + int error_code = ZPP_ERROR_OK; \ ((void)_i); \ ((void)_real_arg); \ ((void)_arg); \ ((void)_expected_type); \ ((void)_error); \ ((void)_dummy); \ - if (UNEXPECTED(_num_args < _min_num_args) || \ - (UNEXPECTED(_num_args > _max_num_args) && \ - EXPECTED(_max_num_args >= 0))) { \ - if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \ - zend_wrong_paramers_count_error(_num_args, _min_num_args, _max_num_args TSRMLS_CC); \ + ((void)_optional); \ + \ + do { \ + if (UNEXPECTED(_num_args < _min_num_args) || \ + (UNEXPECTED(_num_args > _max_num_args) && \ + EXPECTED(_max_num_args >= 0))) { \ + if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \ + zend_wrong_paramers_count_error(_num_args, _min_num_args, _max_num_args TSRMLS_CC); \ + } \ + error_code = ZPP_ERROR_FAILURE; \ + break; \ } \ - goto zend_parse_params_failure; \ - } \ - _i = 0; \ - _real_arg = ZEND_CALL_ARG(EG(current_execute_data), 0); + _i = 0; \ + _real_arg = ZEND_CALL_ARG(EG(current_execute_data), 0); #define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args) \ ZEND_PARSE_PARAMETERS_START_EX(0, min_num_args, max_num_args) #define ZEND_PARSE_PARAMETERS_END_EX(failure) \ - if (0) { \ -zend_parse_params_wrong_callback: ZEND_ATTRIBUTE_UNUSED_LABEL \ - if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \ - zend_wrong_callback_error(E_WARNING, _i, _error TSRMLS_CC); \ - } \ - goto zend_parse_params_failure; \ -zend_parse_params_wrong_class: ZEND_ATTRIBUTE_UNUSED_LABEL \ - if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \ - zend_wrong_paramer_class_error(_i, _error, _arg TSRMLS_CC); \ - } \ - goto zend_parse_params_failure; \ -zend_parse_params_wrong_arg: ZEND_ATTRIBUTE_UNUSED_LABEL \ + } while (0); \ + if (UNEXPECTED(error_code != ZPP_ERROR_OK)) { \ if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \ - zend_wrong_paramer_type_error(_i, _expected_type, _arg TSRMLS_CC); \ + if (error_code == ZPP_ERROR_WRONG_CALLBACK) { \ + zend_wrong_callback_error(E_WARNING, _i, _error TSRMLS_CC); \ + } else if (error_code == ZPP_ERROR_WRONG_CLASS) { \ + zend_wrong_paramer_class_error(_i, _error, _arg TSRMLS_CC); \ + } else if (error_code == ZPP_ERROR_WRONG_ARG) { \ + zend_wrong_paramer_type_error(_i, _expected_type, _arg TSRMLS_CC); \ + } \ } \ -zend_parse_params_failure: ZEND_ATTRIBUTE_UNUSED_LABEL \ failure; \ } \ } while (0) @@ -771,7 +780,10 @@ zend_parse_params_failure: ZEND_ATTRIBUTE_UNUSED_LABEL \ ZEND_PARSE_PARAMETERS_END_EX(return) #define Z_PARAM_PROLOGUE(separate) \ - if (UNEXPECTED(++_i >_num_args)) break; \ + ++_i; \ + if (_optional) { \ + if (UNEXPECTED(_i >_num_args)) break; \ + } \ _real_arg++; \ _arg = _real_arg; \ ZVAL_DEREF(_arg); \ @@ -780,224 +792,227 @@ zend_parse_params_failure: ZEND_ATTRIBUTE_UNUSED_LABEL \ } /* old "|" */ -#define Z_PARAM_OPTIONAL +#define Z_PARAM_OPTIONAL \ + _optional = 1; /* old "a" */ -#define Z_PARAM_ARRAY_EX(dest, check_null, separate) do { \ +#define Z_PARAM_ARRAY_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_array(_arg, &dest, check_null, 0)) { \ + if (UNEXPECTED(!_z_param_array(_arg, &dest, check_null, 0))) { \ _expected_type = Z_EXPECTED_ARRAY; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_ARRAY(dest) \ Z_PARAM_ARRAY_EX(dest, 0, 0) /* old "A" */ -#define Z_PARAM_ARRAY_OR_OBJECT_EX(dest, check_null, separate) do { \ +#define Z_PARAM_ARRAY_OR_OBJECT_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_array(_arg, &dest, check_null, 1)) { \ + if (UNEXPECTED(!_z_param_array(_arg, &dest, check_null, 1))) { \ _expected_type = Z_EXPECTED_ARRAY; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_ARRAY_OR_OBJECT(dest, check_null, separate) \ Z_PARAM_ARRAY_OR_OBJECT_EX(dest, 0, 0) /* old "b" */ -#define Z_PARAM_BOOL_EX(dest, is_null, check_null, separate) do { \ +#define Z_PARAM_BOOL_EX(dest, is_null, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_bool(_arg, &dest, &is_null, check_null TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_bool(_arg, &dest, &is_null, check_null TSRMLS_CC))) { \ _expected_type = Z_EXPECTED_BOOL; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_BOOL(dest) \ Z_PARAM_BOOL_EX(dest, _dummy, 0, 0) /* old "C" */ -#define Z_PARAM_CLASS_EX(dest, check_null, separate) do { \ +#define Z_PARAM_CLASS_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_class(_arg, &dest, _i, check_null TSRMLS_CC)) { \ - goto zend_parse_params_failure; \ - } \ - } while (0); + if (UNEXPECTED(!_z_param_class(_arg, &dest, _i, check_null TSRMLS_CC))) { \ + error_code = ZPP_ERROR_FAILURE; \ + break; \ + } #define Z_PARAM_CLASS(dest) \ Z_PARAM_CLASS_EX(dest, 0, 0) /* old "d" */ -#define Z_PARAM_DOUBLE_EX(dest, is_null, check_null, separate) do { \ +#define Z_PARAM_DOUBLE_EX(dest, is_null, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_double(_arg, &dest, &is_null, check_null)) { \ + if (UNEXPECTED(!_z_param_double(_arg, &dest, &is_null, check_null))) { \ _expected_type = Z_EXPECTED_DOUBLE; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_DOUBLE(dest) \ Z_PARAM_DOUBLE_EX(dest, _dummy, 0, 0) /* old "f" */ -#define Z_PARAM_FUNC_EX(dest_fci, dest_fcc, check_null, separate) do { \ +#define Z_PARAM_FUNC_EX(dest_fci, dest_fcc, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_func(_arg, &dest_fci, &dest_fcc, check_null, &_error TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_func(_arg, &dest_fci, &dest_fcc, check_null, &_error TSRMLS_CC))) { \ if (!_error) { \ _expected_type = Z_EXPECTED_FUNC; \ - goto zend_parse_params_wrong_arg; \ + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ } else { \ - goto zend_parse_params_wrong_callback; \ + error_code = ZPP_ERROR_WRONG_CALLBACK; \ + break; \ } \ - } else if (_error) { \ + } else if (UNEXPECTED(_error != NULL)) { \ zend_wrong_callback_error(E_STRICT, _i, _error TSRMLS_CC); \ - } \ - } while (0); + } #define Z_PARAM_FUNC(dest_fci, dest_fcc) \ Z_PARAM_FUNC_EX(dest_fci, dest_fcc, 0, 0) /* old "h" */ -#define Z_PARAM_ARRAY_HT_EX(dest, check_null, separate) do { \ +#define Z_PARAM_ARRAY_HT_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_array_ht(_arg, &dest, check_null, 0 TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_array_ht(_arg, &dest, check_null, 0 TSRMLS_CC))) { \ _expected_type = Z_EXPECTED_ARRAY; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_ARRAY_HT(dest) \ Z_PARAM_ARRAY_HT_EX(dest, 0, 0) /* old "H" */ -#define Z_PARAM_ARRAY_OR_OBJECT_HT_EX(dest, check_null, separate) do { \ +#define Z_PARAM_ARRAY_OR_OBJECT_HT_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_array_ht(_arg, &dest, check_null, 1 TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_array_ht(_arg, &dest, check_null, 1 TSRMLS_CC))) { \ _expected_type = Z_EXPECTED_ARRAY; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_ARRAY_OR_OBJECT_HT(dest) \ Z_PARAM_ARRAY_OR_OBJECT_HT_EX(dest, 0, 0) /* old "l" */ -#define Z_PARAM_LONG_EX(dest, is_null, check_null, separate) do { \ +#define Z_PARAM_LONG_EX(dest, is_null, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_long(_arg, &dest, &is_null, check_null, 0)) { \ + if (UNEXPECTED(!_z_param_long(_arg, &dest, &is_null, check_null, 0))) { \ _expected_type = Z_EXPECTED_LONG; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_LONG(dest) \ Z_PARAM_LONG_EX(dest, _dummy, 0, 0) /* old "L" */ -#define Z_PARAM_STRICT_LONG_EX(dest, is_null, check_null, separate) do { \ +#define Z_PARAM_STRICT_LONG_EX(dest, is_null, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_long(_arg, &dest, &is_null, check_null, 1)) { \ + if (UNEXPECTED(!_z_param_long(_arg, &dest, &is_null, check_null, 1))) { \ _expected_type = Z_EXPECTED_LONG; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_STRICT_LONG(dest) \ Z_PARAM_STRICT_LONG_EX(dest, _dummy, 0, 0) /* old "o" */ -#define Z_PARAM_OBJECT_EX(dest, check_null, separate) do { \ +#define Z_PARAM_OBJECT_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_object(_arg, &dest, NULL, check_null TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_object(_arg, &dest, NULL, check_null TSRMLS_CC))) { \ _expected_type = Z_EXPECTED_OBJECT; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_OBJECT(dest) \ Z_PARAM_OBJECT_EX(dest, 0, 0) /* old "O" */ -#define Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, check_null, separate) do { \ +#define Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_object(_arg, &dest, _ce, check_null TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_object(_arg, &dest, _ce, check_null TSRMLS_CC))) { \ if (_ce) { \ _error = (_ce)->name->val; \ - goto zend_parse_params_wrong_class; \ + error_code = ZPP_ERROR_WRONG_CLASS; \ + break; \ } else { \ _expected_type = Z_EXPECTED_OBJECT; \ - goto zend_parse_params_wrong_arg; \ + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ } \ - } \ - } while (0); + } #define Z_PARAM_OBJECT_OF_CLASS(dest, _ce) \ Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, 0, 0) /* old "p" */ -#define Z_PARAM_PATH_EX(dest, dest_len, check_null, separate) do { \ +#define Z_PARAM_PATH_EX(dest, dest_len, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_path(_arg, &dest, &dest_len, check_null TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_path(_arg, &dest, &dest_len, check_null TSRMLS_CC))) { \ _expected_type = Z_EXPECTED_PATH; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_PATH(dest, dest_len) \ Z_PARAM_PATH_EX(dest, dest_len, 0, 0) /* old "P" */ -#define Z_PARAM_PATH_STR_EX(dest, check_null, separate) do { \ +#define Z_PARAM_PATH_STR_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_path_str(_arg, &dest, check_null TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_path_str(_arg, &dest, check_null TSRMLS_CC))) { \ _expected_type = Z_EXPECTED_PATH; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_PATH_STR(dest) \ Z_PARAM_PATH_STR_EX(dest, 0, 0) /* old "r" */ -#define Z_PARAM_RESOURCE_EX(dest, check_null, separate) do { \ +#define Z_PARAM_RESOURCE_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_resource(_arg, &dest, check_null)) { \ + if (UNEXPECTED(!_z_param_resource(_arg, &dest, check_null))) { \ _expected_type = Z_EXPECTED_RESOURCE; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_RESOURCE(dest) \ Z_PARAM_RESOURCE_EX(dest, 0, 0) /* old "s" */ -#define Z_PARAM_STRING_EX(dest, dest_len, check_null, separate) do { \ +#define Z_PARAM_STRING_EX(dest, dest_len, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_string(_arg, &dest, &dest_len, check_null TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_string(_arg, &dest, &dest_len, check_null TSRMLS_CC))) { \ _expected_type = Z_EXPECTED_STRING; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_STRING(dest, dest_len) \ Z_PARAM_STRING_EX(dest, dest_len, 0, 0) /* old "S" */ -#define Z_PARAM_STR_EX(dest, check_null, separate) do { \ +#define Z_PARAM_STR_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - if (!_z_param_str(_arg, &dest, check_null TSRMLS_CC)) { \ + if (UNEXPECTED(!_z_param_str(_arg, &dest, check_null TSRMLS_CC))) { \ _expected_type = Z_EXPECTED_STRING; \ - goto zend_parse_params_wrong_arg; \ - } \ - } while (0); + error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } #define Z_PARAM_STR(dest) \ Z_PARAM_STR_EX(dest, 0, 0) /* old "z" */ -#define Z_PARAM_ZVAL_EX(dest, check_null, separate) do { \ +#define Z_PARAM_ZVAL_EX(dest, check_null, separate) \ if (separate) { \ Z_PARAM_PROLOGUE(separate); \ _z_param_zval_deref(_arg, &dest, check_null); \ @@ -1005,17 +1020,15 @@ zend_parse_params_failure: ZEND_ATTRIBUTE_UNUSED_LABEL \ if (UNEXPECTED(++_i >_num_args)) break; \ _real_arg++; \ _z_param_zval(_real_arg, &dest, check_null); \ - } \ - } while (0); + } #define Z_PARAM_ZVAL(dest) \ Z_PARAM_ZVAL_EX(dest, 0, 0) /* old "z" (with dereference) */ -#define Z_PARAM_ZVAL_DEREF_EX(dest, check_null, separate) do { \ +#define Z_PARAM_ZVAL_DEREF_EX(dest, check_null, separate) \ Z_PARAM_PROLOGUE(separate); \ - _z_param_zval_deref(_arg, &dest, check_null); \ - } while (0); + _z_param_zval_deref(_arg, &dest, check_null); #define Z_PARAM_ZVAL_DEREF(dest) \ Z_PARAM_ZVAL_DEREF_EX(dest, 0, 0) @@ -1023,7 +1036,7 @@ zend_parse_params_failure: ZEND_ATTRIBUTE_UNUSED_LABEL \ /* old "+" and "*" */ #define Z_PARAM_VARIADIC_EX(spec, dest, dest_num, post_varargs) do { \ int _num_varargs = _num_args - _i - (post_varargs); \ - if (_num_varargs > 0) { \ + if (EXPECTED(_num_varargs > 0)) { \ dest = _real_arg + 1; \ dest_num = _num_varargs; \ _i += _num_varargs; \ diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 2dd5b16f44..8e1d970c41 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -173,7 +173,6 @@ static void zend_ast_add_array_element(zval *result, zval *offset, zval *expr TS break; case IS_STRING: zend_symtable_update(Z_ARRVAL_P(result), Z_STR_P(offset), expr); -//??? zval_dtor(offset); break; case IS_NULL: @@ -234,11 +233,22 @@ ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *s break; } case ZEND_AST_ZVAL: - ZVAL_DUP(result, zend_ast_get_zval(ast)); - if (Z_OPT_CONSTANT_P(result)) { - zval_update_constant_ex(result, 1, scope TSRMLS_CC); + { + zval *zv = zend_ast_get_zval(ast); + if (scope) { + /* class constants may be updated in-place */ + if (Z_OPT_CONSTANT_P(zv)) { + zval_update_constant_ex(zv, 1, scope TSRMLS_CC); + } + ZVAL_DUP(result, zv); + } else { + ZVAL_DUP(result, zv); + if (Z_OPT_CONSTANT_P(result)) { + zval_update_constant_ex(result, 1, scope TSRMLS_CC); + } } break; + } case ZEND_AST_AND: zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC); if (zend_is_true(&op1 TSRMLS_CC)) { @@ -304,20 +314,17 @@ ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *s } } break; -//??? -#if 0 case ZEND_FETCH_DIM_R: - zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC); - zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC); + zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC); + zend_ast_evaluate(&op2, ast->child[1], scope TSRMLS_CC); { - zval *tmp; + zval tmp; zend_fetch_dimension_by_zval(&tmp, &op1, &op2 TSRMLS_CC); - ZVAL_ZVAL(result, tmp, 1, 1); + ZVAL_ZVAL(result, &tmp, 1, 1); } zval_dtor(&op1); zval_dtor(&op2); break; -#endif default: zend_error(E_ERROR, "Unsupported constant expression"); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 5a3359efa7..5e0ed6cf7b 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3149,44 +3149,6 @@ void zend_do_end_compilation(TSRMLS_D) /* {{{ */ } /* }}} */ -ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC) /* {{{ */ -{ - zend_constant *c; - - if (Z_IMMUTABLE_P(zv)) { - return; - } - - Z_TYPE_FLAGS_P(zv) = IS_TYPE_IMMUTABLE; - GC_REFCOUNT(Z_COUNTED_P(zv)) = 2; - Z_ARRVAL_P(zv)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; - - /* store as an anonymous constant */ - c = emalloc(sizeof(zend_constant)); - ZVAL_COPY_VALUE(&c->value, zv); - c->flags = 0; - c->name = NULL; - c->module_number = PHP_USER_CONSTANT; - zend_hash_next_index_insert_ptr(EG(zend_constants), c); -} -/* }}} */ - -void zend_make_immutable_array_r(zval *zv TSRMLS_DC) /* {{{ */ -{ - zval *el; - - if (Z_IMMUTABLE_P(zv)) { - return; - } - zend_make_immutable_array(zv TSRMLS_CC); - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), el) { - if (Z_TYPE_P(el) == IS_ARRAY) { - zend_make_immutable_array_r(el TSRMLS_CC); - } - } ZEND_HASH_FOREACH_END(); -} -/* }}} */ - /* {{{ zend_dirname Returns directory name component of path */ ZEND_API size_t zend_dirname(char *path, size_t len) @@ -6542,7 +6504,6 @@ static zend_bool zend_try_ct_eval_array(zval *result, zend_ast *ast TSRMLS_DC) { } } - zend_make_immutable_array(result TSRMLS_CC); return 1; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index d3d81d04d0..0d343f0b39 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -450,7 +450,6 @@ typedef int (*unary_op_type)(zval *, zval * TSRMLS_DC); typedef int (*binary_op_type)(zval *, zval *, zval * TSRMLS_DC); ZEND_API unary_op_type get_unary_op(int opcode); ZEND_API binary_op_type get_binary_op(int opcode); -ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC); void zend_stop_lexing(TSRMLS_D); void zend_emit_final_return(zval *zv TSRMLS_DC); @@ -562,12 +561,10 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC); #define ZEND_FETCH_CLASS_DEFAULT 0 #define ZEND_FETCH_CLASS_SELF 1 #define ZEND_FETCH_CLASS_PARENT 2 -#define ZEND_FETCH_CLASS_MAIN 3 /* unused ??? */ -#define ZEND_FETCH_CLASS_GLOBAL 4 /* unused ??? */ -#define ZEND_FETCH_CLASS_AUTO 5 -#define ZEND_FETCH_CLASS_INTERFACE 6 -#define ZEND_FETCH_CLASS_STATIC 7 -#define ZEND_FETCH_CLASS_TRAIT 14 +#define ZEND_FETCH_CLASS_STATIC 3 +#define ZEND_FETCH_CLASS_AUTO 4 +#define ZEND_FETCH_CLASS_INTERFACE 5 +#define ZEND_FETCH_CLASS_TRAIT 6 #define ZEND_FETCH_CLASS_MASK 0x0f #define ZEND_FETCH_CLASS_NO_AUTOLOAD 0x80 #define ZEND_FETCH_CLASS_SILENT 0x0100 diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 650a566159..64ea7060fa 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -32,9 +32,7 @@ void free_zend_constant(zval *zv) zend_constant *c = Z_PTR_P(zv); if (!(c->flags & CONST_PERSISTENT)) { - if (Z_REFCOUNTED(c->value) || Z_IMMUTABLE(c->value)) { - _zval_dtor_func(Z_COUNTED(c->value) ZEND_FILE_LINE_CC); - } + zval_dtor(&c->value); } else { zval_internal_dtor(&c->value); } @@ -398,7 +396,7 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, ret_constant = Z_REFVAL_P(ret_constant); } } - STR_FREE(class_name); + STR_RELEASE(class_name); STR_FREE(constant_name); if (ret_constant && Z_CONSTANT_P(ret_constant)) { zval_update_constant_ex(ret_constant, 1, ce TSRMLS_CC); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 7fca796137..f3e97d71d0 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -133,8 +133,7 @@ static const zend_internal_function zend_pass_function = { /* End of zend_execute_locks.h */ -// TODO: avoid global variable usage ??? -#define CV_DEF_OF(i) (EG(current_execute_data)->func->op_array.vars[i]) +#define CV_DEF_OF(i) (EX(func)->op_array.vars[i]) #define CTOR_CALL_BIT 0x1 #define CTOR_USED_BIT 0x2 @@ -182,7 +181,7 @@ static zend_always_inline zval *_get_zval_ptr_var_deref(zend_uint var, const zen return ret; } -static zend_never_inline zval *_get_zval_cv_lookup(zval *ptr, zend_uint var, int type TSRMLS_DC) +static zend_never_inline zval *_get_zval_cv_lookup(zval *ptr, zend_uint var, int type, const zend_execute_data *execute_data TSRMLS_DC) { zend_string *cv; @@ -206,7 +205,7 @@ static zend_never_inline zval *_get_zval_cv_lookup(zval *ptr, zend_uint var, int return ptr; } -static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_R(zval *ptr, zend_uint var TSRMLS_DC) +static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_R(zval *ptr, zend_uint var, const zend_execute_data *execute_data TSRMLS_DC) { zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var)); @@ -214,7 +213,7 @@ static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_R(zval *ptr, zend_uin return &EG(uninitialized_zval); } -static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_UNSET(zval *ptr, zend_uint var TSRMLS_DC) +static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_UNSET(zval *ptr, zend_uint var, const zend_execute_data *execute_data TSRMLS_DC) { zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var)); @@ -222,12 +221,12 @@ static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_UNSET(zval *ptr, zend return &EG(uninitialized_zval); } -static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_IS(zval *ptr, zend_uint var TSRMLS_DC) +static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_IS(zval *ptr, zend_uint var, const zend_execute_data *execute_data TSRMLS_DC) { return &EG(uninitialized_zval); } -static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_RW(zval *ptr, zend_uint var TSRMLS_DC) +static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_RW(zval *ptr, zend_uint var, const zend_execute_data *execute_data TSRMLS_DC) { zend_string *cv = CV_DEF_OF(EX_VAR_TO_NUM(var)); @@ -236,7 +235,7 @@ static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_RW(zval *ptr, zend_ui return ptr; } -static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_W(zval *ptr, zend_uint var TSRMLS_DC) +static zend_always_inline zval *_get_zval_cv_lookup_BP_VAR_W(zval *ptr, zend_uint var, const zend_execute_data *execute_data TSRMLS_DC) { ZVAL_NULL(ptr); return ptr; @@ -247,7 +246,7 @@ static zend_always_inline zval *_get_zval_ptr_cv(const zend_execute_data *execut zval *ret = EX_VAR(var); if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) { - return _get_zval_cv_lookup(ret, var, type TSRMLS_CC); + return _get_zval_cv_lookup(ret, var, type, execute_data TSRMLS_CC); } return ret; } @@ -257,7 +256,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_deref(const zend_execute_data * zval *ret = EX_VAR(var); if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) { - return _get_zval_cv_lookup(ret, var, type TSRMLS_CC); + return _get_zval_cv_lookup(ret, var, type, execute_data TSRMLS_CC); } ZVAL_DEREF(ret); return ret; @@ -268,7 +267,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(const zend_execute_dat zval *ret = EX_VAR(var); if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) { - return _get_zval_cv_lookup_BP_VAR_R(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_R(ret, var, execute_data TSRMLS_CC); } return ret; } @@ -278,7 +277,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_R(const zend_execu zval *ret = EX_VAR(var); if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) { - return _get_zval_cv_lookup_BP_VAR_R(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_R(ret, var, execute_data TSRMLS_CC); } ZVAL_DEREF(ret); return ret; @@ -289,7 +288,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_UNSET(const zend_execute zval *ret = EX_VAR(var); if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) { - return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var, execute_data TSRMLS_CC); } return ret; } @@ -299,7 +298,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_UNSET(const zend_e zval *ret = EX_VAR(var); if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) { - return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_UNSET(ret, var, execute_data TSRMLS_CC); } ZVAL_DEREF(ret); return ret; @@ -310,7 +309,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_IS(const zend_execute_da zval *ret = EX_VAR(var); if (Z_TYPE_P(ret) == IS_UNDEF) { - return _get_zval_cv_lookup_BP_VAR_IS(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_IS(ret, var, execute_data TSRMLS_CC); } return ret; } @@ -320,7 +319,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_IS(const zend_exec zval *ret = EX_VAR(var); if (Z_TYPE_P(ret) == IS_UNDEF) { - return _get_zval_cv_lookup_BP_VAR_IS(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_IS(ret, var, execute_data TSRMLS_CC); } ZVAL_DEREF(ret); return ret; @@ -331,7 +330,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(const zend_execute_da zval *ret = EX_VAR(var); if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) { - return _get_zval_cv_lookup_BP_VAR_RW(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_RW(ret, var, execute_data TSRMLS_CC); } return ret; } @@ -341,7 +340,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_RW(const zend_exec zval *ret = EX_VAR(var); if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) { - return _get_zval_cv_lookup_BP_VAR_RW(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_RW(ret, var, execute_data TSRMLS_CC); } ZVAL_DEREF(ret); return ret; @@ -352,7 +351,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(const zend_execute_dat zval *ret = EX_VAR(var); if (Z_TYPE_P(ret) == IS_UNDEF) { - return _get_zval_cv_lookup_BP_VAR_W(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_W(ret, var, execute_data TSRMLS_CC); } return ret; } @@ -367,7 +366,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execu zval *ret = EX_VAR(var); if (Z_TYPE_P(ret) == IS_UNDEF) { - return _get_zval_cv_lookup_BP_VAR_W(ret, var TSRMLS_CC); + return _get_zval_cv_lookup_BP_VAR_W(ret, var, execute_data TSRMLS_CC); } ZVAL_DEREF(ret); return ret; @@ -697,34 +696,23 @@ static inline void zend_assign_to_object(zval *retval, zval *object_ptr, zval *p if (Z_TYPE_P(object) == IS_NULL || Z_TYPE_P(object) == IS_FALSE || (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)) { -//??? The following block may handle only non-interned empty string, -//??? but it doesn't work anyway -//??? see: Zend/tests/bug54265.phpt -#if 0 - if (Z_REFCOUNTED_P(object)) { - if (!Z_ISREF_P(object_ptr)) { - SEPARATE_ZVAL(object); - } - Z_ADDREF_P(object); - zend_error(E_WARNING, "Creating default object from empty value"); - if (Z_REFCOUNT_P(object) == 1) { - /* object was removed by error handler, nothing to assign to */ - zval_ptr_dtor(object); - if (retval) { - ZVAL_NULL(retval); - } - FREE_OP(free_value); - return; + zend_object *obj; + + zval_ptr_dtor(object); + object_init(object); + Z_ADDREF_P(object); + obj = Z_OBJ_P(object); + zend_error(E_WARNING, "Creating default object from empty value"); + if (GC_REFCOUNT(obj) == 1) { + /* the enclosing container was deleted, obj is unreferenced */ + if (retval) { + ZVAL_NULL(retval); } - Z_DELREF_P(object); - } else { - zend_error(E_WARNING, "Creating default object from empty value"); + FREE_OP(free_value); + OBJ_RELEASE(obj); + return; } -#else - zend_error(E_WARNING, "Creating default object from empty value"); -#endif - zval_dtor(object); - object_init(object); + Z_DELREF_P(object); } else { zend_error(E_WARNING, "Attempt to assign property of non-object"); if (retval) { @@ -945,6 +933,9 @@ static inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value TSRM value = Z_REFVAL_P(value); } if (Z_REFCOUNTED_P(value)) { + if (UNEXPECTED(variable_ptr == value)) { + return variable_ptr; + } Z_ADDREF_P(value); } } @@ -1364,6 +1355,11 @@ static zend_never_inline void zend_fetch_dimension_address_read_IS(zval *result, zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS TSRMLS_CC); } +ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval *dim TSRMLS_DC) +{ + zend_fetch_dimension_address_read_R(result, container, dim, IS_TMP_VAR TSRMLS_CC); +} + static void zend_fetch_property_address(zval *result, zval *container_ptr, zval *prop_ptr, void **cache_slot, int type, int is_ref TSRMLS_DC) { zval *container = container_ptr; diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 812d4141b4..cb7ca70ef3 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -115,9 +115,6 @@ again: result = Z_TYPE(tmp) == IS_TRUE; break; } - - // TODO: do we really need this warning ??? - // Nikita, add your comments here. zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to boolean", Z_OBJ_P(op)->ce->name->val); } else if (Z_OBJ_HT_P(op)->get) { zval rv; @@ -289,6 +286,8 @@ ZEND_API zend_class_entry *zend_fetch_class(zend_string *class_name, int fetch_t ZEND_API zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, const zval *key, int fetch_type TSRMLS_DC); void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC); +ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval *dim TSRMLS_DC); + #ifdef ZEND_WIN32 void zend_init_timeout_thread(void); void zend_shutdown_timeout_thread(void); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index bdf87bd440..947d051ddd 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -859,6 +859,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS EG(scope) = func->common.scope; } call->prev_execute_data = EG(current_execute_data); + call->return_value = NULL; /* this is not a constructor call */ EG(current_execute_data) = call; if (EXPECTED(zend_execute_internal == NULL)) { /* saves one function call if zend_execute_internal is not used */ diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index eea4de8653..adc02a3eb0 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -472,7 +472,7 @@ static int gc_collect_white(zend_refcounted *ref TSRMLS_DC) Bucket *p; tail_call: - if (GC_INFO(ref) == GC_WHITE) { + if (GC_GET_COLOR(GC_INFO(ref)) == GC_WHITE) { ht = NULL; GC_SET_BLACK(GC_INFO(ref)); @@ -481,6 +481,30 @@ tail_call: count++; } +#if 1 + if ((GC_TYPE(ref) == IS_OBJECT || GC_TYPE(ref) == IS_ARRAY) && + !GC_ADDRESS(GC_INFO(ref))) { + /* add garbage into list */ + gc_root_buffer *buf = GC_G(unused); + + if (buf) { + GC_G(unused) = buf->prev; + } else if (GC_G(first_unused) != GC_G(last_unused)) { + buf = GC_G(first_unused); + GC_G(first_unused)++; + } + /* TODO: what should we do if we don't have room ??? */ + if (buf) { + buf->ref = ref; + buf->next = GC_G(roots).next; + buf->prev = &GC_G(roots); + GC_G(roots).next->prev = buf; + GC_G(roots).next = buf; + GC_SET_ADDRESS(GC_INFO(ref), buf - GC_G(buf)); + } + } +#endif + if (GC_TYPE(ref) == IS_OBJECT && EG(objects_store).object_buckets) { zend_object_get_gc_t get_gc; zend_object *obj = (zend_object*)ref; @@ -568,16 +592,23 @@ static int gc_collect_roots(TSRMLS_D) int count = 0; gc_root_buffer *current = GC_G(roots).next; + /* remove non-garbage from the list */ while (current != &GC_G(roots)) { - GC_SET_ADDRESS(GC_INFO(current->ref), 0); - if (GC_INFO(current->ref) == GC_WHITE) { - count += gc_collect_white(current->ref TSRMLS_CC); - GC_SET_ADDRESS(GC_INFO(current->ref), current - GC_G(buf)); - } else { + if (GC_GET_COLOR(GC_INFO(current->ref)) != GC_WHITE) { + GC_SET_ADDRESS(GC_INFO(current->ref), 0); GC_REMOVE_FROM_ROOTS(current); } current = current->next; } + + current = GC_G(roots).next; + while (current != &GC_G(roots)) { + if (GC_GET_COLOR(GC_INFO(current->ref)) == GC_WHITE) { + GC_REFCOUNT(current->ref)++; + count += gc_collect_white(current->ref TSRMLS_CC); + } + current = current->next; + } /* relink remaining roots into list to free */ if (GC_G(roots).next != &GC_G(roots)) { if (GC_G(to_free).next == &GC_G(to_free)) { @@ -600,6 +631,73 @@ static int gc_collect_roots(TSRMLS_D) return count; } +static void gc_remove_nested_data_from_buffer(zend_refcounted *ref TSRMLS_DC) +{ + HashTable *ht; + uint idx; + Bucket *p; + +tail_call: + if (GC_ADDRESS(GC_INFO(ref)) != 0) { + GC_REMOVE_FROM_BUFFER(ref); + + if (GC_TYPE(ref) == IS_OBJECT && EG(objects_store).object_buckets) { + zend_object_get_gc_t get_gc; + zend_object *obj = (zend_object*)ref; + + if (EXPECTED(IS_OBJ_VALID(EG(objects_store).object_buckets[obj->handle]) && + (get_gc = obj->handlers->get_gc) != NULL)) { + int i, n; + zval *table; + zval tmp; + HashTable *props; + + ZVAL_OBJ(&tmp, obj); + props = get_gc(&tmp, &table, &n TSRMLS_CC); + + while (n > 0 && !Z_REFCOUNTED(table[n-1])) n--; + for (i = 0; i < n; i++) { + if (Z_REFCOUNTED(table[i])) { + ref = Z_COUNTED(table[i]); + if (!props && i == n - 1) { + goto tail_call; + } else { + gc_remove_nested_data_from_buffer(ref TSRMLS_CC); + } + } + } + if (!props) { + return; + } + ht = props; + } + } else if (GC_TYPE(ref) == IS_ARRAY) { + ht = &((zend_array*)ref)->ht; + } else if (GC_TYPE(ref) == IS_REFERENCE) { + if (Z_REFCOUNTED(((zend_reference*)ref)->val)) { + if (UNEXPECTED(!EG(objects_store).object_buckets) && + Z_TYPE(((zend_reference*)ref)->val) == IS_OBJECT) { + return; + } + ref = Z_COUNTED(((zend_reference*)ref)->val); + goto tail_call; + } + return; + } + if (!ht) return; + for (idx = 0; idx < ht->nNumUsed; idx++) { + p = ht->arData + idx; + if (!Z_REFCOUNTED(p->val)) continue; + ref = Z_COUNTED(p->val); + if (idx == ht->nNumUsed-1) { + goto tail_call; + } else { + gc_remove_nested_data_from_buffer(ref TSRMLS_CC); + } + } + } +} + ZEND_API int gc_collect_cycles(TSRMLS_D) { int count = 0; @@ -636,7 +734,14 @@ ZEND_API int gc_collect_cycles(TSRMLS_D) orig_next_to_free = GC_G(next_to_free); - /* First call destructors */ + /* Remember reference counters before calling destructors */ + current = to_free.next; + while (current != &to_free) { + current->refcount = GC_REFCOUNT(current->ref); + current = current->next; + } + + /* Call destructors */ current = to_free.next; while (current != &to_free) { p = current->ref; @@ -659,6 +764,16 @@ ZEND_API int gc_collect_cycles(TSRMLS_D) current = GC_G(next_to_free); } + /* Remove values captured in destructors */ + current = to_free.next; + while (current != &to_free) { + GC_G(next_to_free) = current->next; + if (GC_REFCOUNT(current->ref) > current->refcount) { + gc_remove_nested_data_from_buffer(current->ref TSRMLS_CC); + } + current = GC_G(next_to_free); + } + /* Destroy zvals */ current = to_free.next; while (current != &to_free) { diff --git a/Zend/zend_gc.h b/Zend/zend_gc.h index d060fae9dd..8d619f2e5e 100644 --- a/Zend/zend_gc.h +++ b/Zend/zend_gc.h @@ -74,9 +74,10 @@ GC_SET_PURPLE(Z_GC_INFO_P(v)) typedef struct _gc_root_buffer { - struct _gc_root_buffer *prev; /* double-linked list */ - struct _gc_root_buffer *next; zend_refcounted *ref; + struct _gc_root_buffer *next; /* double-linked list */ + struct _gc_root_buffer *prev; + zend_uint refcount; } gc_root_buffer; typedef struct _zend_gc_globals { diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index e7aa255d78..78b38f7ea2 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -214,6 +214,7 @@ static zend_always_inline Bucket *zend_hash_str_find_bucket(const HashTable *ht, nIndex = h & ht->nTableMask; idx = ht->arHash[nIndex]; while (idx != INVALID_IDX) { + ZEND_ASSERT(idx < ht->nTableSize); p = ht->arData + idx; if ((p->h == h) && p->key @@ -235,6 +236,7 @@ static zend_always_inline Bucket *zend_hash_index_find_bucket(const HashTable *h nIndex = h & ht->nTableMask; idx = ht->arHash[nIndex]; while (idx != INVALID_IDX) { + ZEND_ASSERT(idx < ht->nTableSize); p = ht->arData + idx; if (p->h == h && !p->key) { return p; @@ -579,6 +581,9 @@ ZEND_API int zend_hash_rehash(HashTable *ht) IS_CONSISTENT(ht); if (UNEXPECTED(ht->nNumOfElements == 0)) { + if (ht->nTableMask) { + memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(zend_uint)); + } return SUCCESS; } diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index c196134657..d7b419225e 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -628,6 +628,17 @@ static inline void *zend_hash_index_find_ptr(const HashTable *ht, ulong h) return zv ? Z_PTR_P(zv) : NULL; } +static inline void *zend_symtable_str_find_ptr(HashTable *ht, const char *str, int len) +{ + ulong idx; + + if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) { + return zend_hash_index_find_ptr(ht, idx); + } else { + return zend_hash_str_find_ptr(ht, str, len); + } +} + static inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, HashPosition *pos) { zval *zv; diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 6232b8e2f1..c3a02d53a3 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -231,9 +231,11 @@ ZEND_API void zend_unregister_ini_entries(int module_number TSRMLS_DC) /* {{{ */ /* }}} */ #ifdef ZTS -static int zend_ini_refresh_cache(zval *el, int stage TSRMLS_DC) /* {{{ */ +static int zend_ini_refresh_cache(zval *el, void *arg TSRMLS_DC) /* {{{ */ { zend_ini_entry *p = (zend_ini_entry *)Z_PTR_P(el); + int stage = (int)(zend_intptr_t)arg; + if (p->on_modify) { p->on_modify(p, p->value, p->value_length, p->mh_arg1, p->mh_arg2, p->mh_arg3, stage TSRMLS_CC); } diff --git a/Zend/zend_multibyte.c b/Zend/zend_multibyte.c index 08251dfa5e..49056cfad4 100644 --- a/Zend/zend_multibyte.c +++ b/Zend/zend_multibyte.c @@ -168,7 +168,7 @@ ZEND_API const zend_encoding *zend_multibyte_get_script_encoding(TSRMLS_D) ZEND_API int zend_multibyte_set_script_encoding(const zend_encoding **encoding_list, size_t encoding_list_size TSRMLS_DC) { if (CG(script_encoding_list)) { - free(CG(script_encoding_list)); + free((char*)CG(script_encoding_list)); } CG(script_encoding_list) = encoding_list; CG(script_encoding_list_size) = encoding_list_size; @@ -195,7 +195,7 @@ ZEND_API int zend_multibyte_set_script_encoding_by_string(const char *new_value, } if (size == 0) { - pefree(list, 1); + pefree((void*)list, 1); return FAILURE; } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 30794a3054..d7d8bf0a52 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -593,11 +593,25 @@ found: ZVAL_COPY_VALUE(&garbage, Z_REFVAL_P(variable_ptr)); /* old value should be destroyed */ /* To check: can't *variable_ptr be some system variable like error_zval here? */ - ZVAL_COPY_VALUE(Z_REFVAL_P(variable_ptr), value); - if (Z_REFCOUNTED_P(value) && Z_REFCOUNT_P(value) > 0) { - zval_copy_ctor(Z_REFVAL_P(variable_ptr)); + if (UNEXPECTED(Z_REFCOUNTED_P(value))) { + if (EXPECTED(!Z_ISREF_P(value))) { + Z_ADDREF_P(value); + } else { + if (Z_REFCOUNT_P(value) == 1) { + ZVAL_UNREF(value); + } else { + value = Z_REFVAL_P(value); + } + if (Z_REFCOUNTED_P(value)) { + if (UNEXPECTED(Z_REFVAL_P(variable_ptr) == value)) { + goto exit; + } + Z_ADDREF_P(value); + } + } } - zval_dtor(&garbage); + ZVAL_COPY_VALUE(Z_REFVAL_P(variable_ptr), value); + zval_ptr_dtor(&garbage); } else { zval garbage; @@ -1455,6 +1469,7 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists, found: switch (has_set_exists) { case 0: + ZVAL_DEREF(value); result = (Z_TYPE_P(value) != IS_NULL); break; default: diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index dc2756fe09..921d71b685 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -819,6 +819,7 @@ try_again: goto try_again; EMPTY_SWITCH_DEFAULT_CASE() } + return 0; } /* }}} */ @@ -859,6 +860,7 @@ try_again: goto try_again; EMPTY_SWITCH_DEFAULT_CASE() } + return 0.0; } /* }}} */ @@ -912,6 +914,7 @@ try_again: goto try_again; EMPTY_SWITCH_DEFAULT_CASE() } + return NULL; } /* }}} */ @@ -1552,10 +1555,10 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{ ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT); if (Z_TYPE_P(op1) != IS_STRING) { - use_copy1 = zend_make_printable_zval(op1, &op1_copy); + 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); + use_copy2 = zend_make_printable_zval(op2, &op2_copy TSRMLS_CC); } } @@ -1783,6 +1786,14 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* { return SUCCESS; default: + if (Z_ISREF_P(op1)) { + op1 = Z_REFVAL_P(op1); + continue; + } else if (Z_ISREF_P(op2)) { + op2 = Z_REFVAL_P(op2); + continue; + } + if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) { return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC); } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) { @@ -1841,11 +1852,7 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* { return SUCCESS; } } - if (Z_ISREF_P(op1)) { - op1 = Z_REFVAL_P(op1); - } else if (Z_ISREF_P(op2)) { - op2 = Z_REFVAL_P(op2); - } else if (!converted) { + if (!converted) { if (Z_TYPE_P(op1) == IS_NULL || Z_TYPE_P(op1) == IS_FALSE) { zendi_convert_to_boolean(op2, op2_copy, result); ZVAL_LONG(result, (Z_TYPE_P(op2) == IS_TRUE) ? -1 : 0); @@ -1888,10 +1895,9 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* { } /* }}} */ -static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */ +static int hash_zval_identical_function(zval *z1, zval *z2 TSRMLS_DC) /* {{{ */ { zval result; - TSRMLS_FETCH(); /* is_identical_function() returns 1 in case of identity and 0 in case * of a difference; diff --git a/Zend/zend_ts_hash.c b/Zend/zend_ts_hash.c index 92cd62128e..f6523574ae 100644 --- a/Zend/zend_ts_hash.c +++ b/Zend/zend_ts_hash.c @@ -333,6 +333,39 @@ ZEND_API int zend_ts_hash_rehash(TsHashTable *ht) return retval; } +ZEND_API zval *zend_ts_hash_str_find(TsHashTable *ht, const char *key, int len) +{ + zval *retval; + + begin_read(ht); + retval = zend_hash_str_find(TS_HASH(ht), key, len); + end_read(ht); + + return retval; +} + +ZEND_API zval *_zend_ts_hash_str_update(TsHashTable *ht, const char *key, int len, zval *pData ZEND_FILE_LINE_DC) +{ + zval *retval; + + begin_write(ht); + retval = zend_hash_str_update(TS_HASH(ht), key, len, pData); + end_write(ht); + + return retval; +} + +ZEND_API zval *_zend_ts_hash_str_add(TsHashTable *ht, const char *key, int len, zval *pData ZEND_FILE_LINE_DC) +{ + zval *retval; + + begin_write(ht); + retval = zend_hash_str_add(TS_HASH(ht), key, len, pData); + end_write(ht); + + return retval; +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_ts_hash.h b/Zend/zend_ts_hash.h index 4b0a507368..fcf8c3cda1 100644 --- a/Zend/zend_ts_hash.h +++ b/Zend/zend_ts_hash.h @@ -102,6 +102,41 @@ void zend_ts_hash_display_pListTail(TsHashTable *ht); void zend_ts_hash_display(TsHashTable *ht); #endif +ZEND_API zval *zend_ts_hash_str_find(TsHashTable *ht, const char *key, int len); +ZEND_API zval *_zend_ts_hash_str_update(TsHashTable *ht, const char *key, int len, zval *pData ZEND_FILE_LINE_DC); +ZEND_API zval *_zend_ts_hash_str_add(TsHashTable *ht, const char *key, int len, zval *pData ZEND_FILE_LINE_DC); + +#define zend_ts_hash_str_update(ht, key, len, pData) \ + _zend_ts_hash_str_update(ht, key, len, pData ZEND_FILE_LINE_CC) +#define zend_ts_hash_str_add(ht, key, len, pData) \ + _zend_ts_hash_str_add(ht, key, len, pData ZEND_FILE_LINE_CC) + +static inline void *zend_ts_hash_str_find_ptr(TsHashTable *ht, const char *str, int len) +{ + zval *zv; + + zv = zend_ts_hash_str_find(ht, str, len); + return zv ? Z_PTR_P(zv) : NULL; +} + +static inline void *zend_ts_hash_str_update_ptr(TsHashTable *ht, const char *str, int len, void *pData) +{ + zval tmp, *zv; + + ZVAL_PTR(&tmp, pData); + zv = zend_ts_hash_str_update(ht, str, len, &tmp); + return zv ? Z_PTR_P(zv) : NULL; +} + +static inline void *zend_ts_hash_str_add_ptr(TsHashTable *ht, const char *str, int len, void *pData) +{ + zval tmp, *zv; + + ZVAL_PTR(&tmp, pData); + zv = zend_ts_hash_str_add(ht, str, len, &tmp); + return zv ? Z_PTR_P(zv) : NULL; +} + END_EXTERN_C() #define ZEND_TS_INIT_SYMTABLE(ht) \ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f45882e52f..3122119998 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1203,6 +1203,9 @@ ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMP|VAR|CV, UNUSED|CONST| ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -2127,7 +2130,7 @@ ZEND_VM_HANDLER(56, ZEND_ADD_VAR, TMP|UNUSED, TMP|VAR|CV) if (Z_TYPE_P(var) != IS_STRING) { ZVAL_DEREF(var); if (Z_TYPE_P(var) != IS_STRING) { - use_copy = zend_make_printable_zval(var, &var_copy); + use_copy = zend_make_printable_zval(var, &var_copy TSRMLS_CC); if (use_copy) { var = &var_copy; @@ -3477,7 +3480,7 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, ANY) // This solution breaks the following test (emit warning message) ??? // ext/pdo_sqlite/tests/pdo_005.phpt #endif - (!Z_ISREF_P(arg) && Z_REFCOUNT_P(arg) > 1)) { + (!Z_ISREF_P(arg) /*&& Z_REFCOUNT_P(arg) > 1???*/)) { if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { @@ -3841,7 +3844,7 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST) retval = EX_VAR(opline->result.var); ZVAL_COPY_VALUE(retval, &c->value); if (Z_OPT_COPYABLE_P(retval) || Z_OPT_REFCOUNTED_P(retval)) { - if (Z_OPT_COPYABLE_P(retval) && (c->flags & CONST_PERSISTENT)) { + if (Z_OPT_COPYABLE_P(retval)) { zval_copy_ctor_func(retval); } else { Z_ADDREF_P(retval); @@ -4484,6 +4487,8 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -4845,8 +4850,9 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) FREE_OP1(); } - if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (opline->extended_value & ZEND_ISSET) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -4924,7 +4930,8 @@ ZEND_VM_C_LABEL(num_index_prop): if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -4943,6 +4950,9 @@ ZEND_VM_C_LABEL(num_index_prop): result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 263f729962..8605333d05 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3093,6 +3093,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -3844,6 +3846,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_CONST(int type ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -4286,7 +4291,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO retval = EX_VAR(opline->result.var); ZVAL_COPY_VALUE(retval, &c->value); if (Z_OPT_COPYABLE_P(retval) || Z_OPT_REFCOUNTED_P(retval)) { - if (Z_OPT_COPYABLE_P(retval) && (c->flags & CONST_PERSISTENT)) { + if (Z_OPT_COPYABLE_P(retval)) { zval_copy_ctor_func(retval); } else { Z_ADDREF_P(retval); @@ -4603,7 +4608,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_CONST_HANDLER(ZEND_O } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -6343,6 +6349,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_VAR(int type, ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -6987,7 +6996,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_VAR_HANDLER(ZEND_OPC } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -7395,6 +7405,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_UNUSED(int typ ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -7846,7 +7859,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_UNUSED_HANDLER(ZEND_ } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -9807,6 +9821,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -10587,6 +10603,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMP_CONST(int type, ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -11200,7 +11219,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPC } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -11968,7 +11988,7 @@ static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ if (Z_TYPE_P(var) != IS_STRING) { ZVAL_DEREF(var); if (Z_TYPE_P(var) != IS_STRING) { - use_copy = zend_make_printable_zval(var, &var_copy); + use_copy = zend_make_printable_zval(var, &var_copy TSRMLS_CC); if (use_copy) { var = &var_copy; @@ -12864,6 +12884,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMP_VAR(int type, ZE ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -13101,7 +13124,7 @@ static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ if (Z_TYPE_P(var) != IS_STRING) { ZVAL_DEREF(var); if (Z_TYPE_P(var) != IS_STRING) { - use_copy = zend_make_printable_zval(var, &var_copy); + use_copy = zend_make_printable_zval(var, &var_copy TSRMLS_CC); if (use_copy) { var = &var_copy; @@ -13465,7 +13488,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCOD } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -13873,6 +13897,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMP_UNUSED(int type, ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -14208,7 +14235,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_UNUSED_HANDLER(ZEND_OP } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -14818,7 +14846,7 @@ static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_A if (Z_TYPE_P(var) != IS_STRING) { ZVAL_DEREF(var); if (Z_TYPE_P(var) != IS_STRING) { - use_copy = zend_make_printable_zval(var, &var_copy); + use_copy = zend_make_printable_zval(var, &var_copy TSRMLS_CC); if (use_copy) { var = &var_copy; @@ -16048,7 +16076,7 @@ static int ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR // This solution breaks the following test (emit warning message) ??? // ext/pdo_sqlite/tests/pdo_005.phpt #endif - (!Z_ISREF_P(arg) && Z_REFCOUNT_P(arg) > 1)) { + (!Z_ISREF_P(arg) /*&& Z_REFCOUNT_P(arg) > 1???*/)) { if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { @@ -16444,6 +16472,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -17875,6 +17905,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_CONST(int type, ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -18593,7 +18626,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE retval = EX_VAR(opline->result.var); ZVAL_COPY_VALUE(retval, &c->value); if (Z_OPT_COPYABLE_P(retval) || Z_OPT_REFCOUNTED_P(retval)) { - if (Z_OPT_COPYABLE_P(retval) && (c->flags & CONST_PERSISTENT)) { + if (Z_OPT_COPYABLE_P(retval)) { zval_copy_ctor_func(retval); } else { Z_ADDREF_P(retval); @@ -19038,7 +19071,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_CONST_HANDLER(ZEND_OPC } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -19116,7 +19150,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -19135,6 +19170,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -21105,7 +21143,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -21124,6 +21163,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -22248,6 +22290,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_VAR(int type, ZE ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -23383,7 +23428,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_VAR_HANDLER(ZEND_OPCOD } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -23461,7 +23507,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -23480,6 +23527,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -24148,6 +24198,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_VAR_UNUSED(int type, ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -24710,7 +24763,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_UNUSED_HANDLER(ZEND_OP } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -26693,7 +26747,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -26712,6 +26767,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_VAR == IS_CV || IS_VAR == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -27869,7 +27927,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC retval = EX_VAR(opline->result.var); ZVAL_COPY_VALUE(retval, &c->value); if (Z_OPT_COPYABLE_P(retval) || Z_OPT_REFCOUNTED_P(retval)) { - if (Z_OPT_COPYABLE_P(retval) && (c->flags & CONST_PERSISTENT)) { + if (Z_OPT_COPYABLE_P(retval)) { zval_copy_ctor_func(retval); } else { Z_ADDREF_P(retval); @@ -28153,7 +28211,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -28172,6 +28231,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_UNUSED == IS_CV || IS_UNUSED == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -29117,7 +29179,7 @@ static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDL if (Z_TYPE_P(var) != IS_STRING) { ZVAL_DEREF(var); if (Z_TYPE_P(var) != IS_STRING) { - use_copy = zend_make_printable_zval(var, &var_copy); + use_copy = zend_make_printable_zval(var, &var_copy TSRMLS_CC); if (use_copy) { var = &var_copy; @@ -29432,7 +29494,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -29451,6 +29514,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_UNUSED == IS_CV || IS_UNUSED == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -30398,7 +30464,7 @@ static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDL if (Z_TYPE_P(var) != IS_STRING) { ZVAL_DEREF(var); if (Z_TYPE_P(var) != IS_STRING) { - use_copy = zend_make_printable_zval(var, &var_copy); + use_copy = zend_make_printable_zval(var, &var_copy TSRMLS_CC); if (use_copy) { var = &var_copy; @@ -30713,7 +30779,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -30732,6 +30799,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_UNUSED == IS_CV || IS_UNUSED == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -32190,7 +32260,7 @@ static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLE if (Z_TYPE_P(var) != IS_STRING) { ZVAL_DEREF(var); if (Z_TYPE_P(var) != IS_STRING) { - use_copy = zend_make_printable_zval(var, &var_copy); + use_copy = zend_make_printable_zval(var, &var_copy TSRMLS_CC); if (use_copy) { var = &var_copy; @@ -32503,7 +32573,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -32522,6 +32593,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_UNUSED == IS_CV || IS_UNUSED == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -33414,7 +33488,7 @@ static int ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG // This solution breaks the following test (emit warning message) ??? // ext/pdo_sqlite/tests/pdo_005.phpt #endif - (!Z_ISREF_P(arg) && Z_REFCOUNT_P(arg) > 1)) { + (!Z_ISREF_P(arg) /*&& Z_REFCOUNT_P(arg) > 1???*/)) { if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { @@ -33795,6 +33869,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -35075,6 +35151,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_CONST(int type, Z ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -36024,7 +36103,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_CONST_HANDLER(ZEND_OPCO } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -36102,7 +36182,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -36121,6 +36202,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_CV == IS_CV || IS_CV == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -38002,7 +38086,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -38021,6 +38106,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_CV == IS_CV || IS_CV == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -39143,6 +39231,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_VAR(int type, ZEN ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -40160,7 +40251,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_VAR_HANDLER(ZEND_OPCODE } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -40238,7 +40330,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -40257,6 +40350,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_CV == IS_CV || IS_CV == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { @@ -40923,6 +41019,9 @@ static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_UNUSED(int type, ZEND_ASSERT(retval != NULL); if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } ZVAL_COPY(EX_VAR(opline->result.var), retval); } else { if (/*type == BP_VAR_W &&*/ (opline->extended_value & ZEND_FETCH_MAKE_REF)) { @@ -41369,7 +41468,8 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_UNUSED_HANDLER(ZEND_OPC } if (opline->extended_value & ZEND_ISSET) { - if (isset && Z_TYPE_P(value) != IS_NULL) { + if (isset && Z_TYPE_P(value) != IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL)) { ZVAL_BOOL(EX_VAR(opline->result.var), 1); } else { ZVAL_BOOL(EX_VAR(opline->result.var), 0); @@ -43214,7 +43314,8 @@ num_index_prop: if (opline->extended_value & ZEND_ISSET) { /* > IS_NULL means not IS_UNDEF and not IS_NULL */ - result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + result = value != NULL && Z_TYPE_P(value) > IS_NULL && + (!Z_ISREF_P(value) || Z_TYPE_P(Z_REFVAL_P(value)) != IS_NULL); } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); } @@ -43233,6 +43334,9 @@ num_index_prop: result = 0; if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (IS_CV == IS_CV || IS_CV == IS_VAR) { + ZVAL_DEREF(offset); + } if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { |