diff options
| author | Dmitry Stogov <dmitry@zend.com> | 2016-04-21 10:15:57 +0300 |
|---|---|---|
| committer | Dmitry Stogov <dmitry@zend.com> | 2016-04-21 10:15:57 +0300 |
| commit | c026ca6cdccc74ca78d8b0ab203281c19b93cdde (patch) | |
| tree | b74b4d46fba2974ac44b5d4492912e8f6b797cbe | |
| parent | 650c1c0a7d94d3bb052a93407b6e280df9c265a4 (diff) | |
| parent | ecf6392243b90e6c8f5597076b11b4959bac9dc1 (diff) | |
| download | php-git-c026ca6cdccc74ca78d8b0ab203281c19b93cdde.tar.gz | |
Merge branch 'master' into safe_timeout
* master:
Fixed bug #72059 - Reference the bug id directly in NEWS
Fix magic constants (__LINE__) with ?? for constant scalar exprs
Add NEWS entry for ?? in constant scalar expressions
allow null coalescing (??) on constant expressions
Fix intl tests for ICU < 52
Fix ZTS builds by adding a missing TSRMLS_FETCH().
Fix bug #71737
Update NEWS
Fix RECV opcode to handle all kinds of exceptions
Fix RECV opcode to handle all kinds of exceptions
| -rw-r--r-- | Zend/tests/bug41117_1.phpt | 3 | ||||
| -rw-r--r-- | Zend/tests/bug71737.phpt | 16 | ||||
| -rw-r--r-- | Zend/tests/bug72057.phpt | 21 | ||||
| -rw-r--r-- | Zend/tests/constant_expressions_coalesce.phpt | 47 | ||||
| -rw-r--r-- | Zend/tests/constant_expressions_coalesce_empty_dim.phpt | 11 | ||||
| -rw-r--r-- | Zend/tests/constant_expressions_dynamic.phpt | 5 | ||||
| -rw-r--r-- | Zend/zend_ast.c | 39 | ||||
| -rw-r--r-- | Zend/zend_compile.c | 39 | ||||
| -rw-r--r-- | Zend/zend_compile.h | 2 | ||||
| -rw-r--r-- | Zend/zend_execute.c | 6 | ||||
| -rw-r--r-- | Zend/zend_execute.h | 1 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 4 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 4 | ||||
| -rw-r--r-- | ext/intl/tests/timezone_IDforWindowsID_basic.phpt | 2 | ||||
| -rw-r--r-- | ext/intl/tests/timezone_windowsID_basic.phpt | 2 |
15 files changed, 186 insertions, 16 deletions
diff --git a/Zend/tests/bug41117_1.phpt b/Zend/tests/bug41117_1.phpt index f555b637ad..a612f07fed 100644 --- a/Zend/tests/bug41117_1.phpt +++ b/Zend/tests/bug41117_1.phpt @@ -10,5 +10,4 @@ class foo { $obj = new foo("Hello world"); ?> --EXPECTF-- -Fatal error: Cannot re-assign $this in %sbug41117_1.php on line 3 - +Fatal error: Cannot use $this as parameter in %s on line %d diff --git a/Zend/tests/bug71737.phpt b/Zend/tests/bug71737.phpt new file mode 100644 index 0000000000..b44de8e78e --- /dev/null +++ b/Zend/tests/bug71737.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #71737: Memory leak in closure with parameter named $this +--FILE-- +<?php + +class Test { + public function method() { + return function($this) {}; + } +} + +(new Test)->method()(new stdClass); + +?> +--EXPECTF-- +Fatal error: Cannot use $this as parameter in %s on line %d diff --git a/Zend/tests/bug72057.phpt b/Zend/tests/bug72057.phpt new file mode 100644 index 0000000000..e1a129bbc2 --- /dev/null +++ b/Zend/tests/bug72057.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #72057 (PHP hangs when user error handler throws exception after Notice from type coercion) +--FILE-- +<?php + +set_error_handler( + function() { + throw new Exception("My custom error"); + } +); + +(function (int $i) { bar(); })("7as"); + +--EXPECTF-- + +Fatal error: Uncaught Exception: My custom error in %s:%d +Stack trace: +#0 %s(%d): {closure}(8, 'A non well form...', '%s', %d, Array) +#1 %s(%d): {closure}('7as') +#2 {main} + thrown in %s on line %d diff --git a/Zend/tests/constant_expressions_coalesce.phpt b/Zend/tests/constant_expressions_coalesce.phpt new file mode 100644 index 0000000000..425aba69c4 --- /dev/null +++ b/Zend/tests/constant_expressions_coalesce.phpt @@ -0,0 +1,47 @@ +--TEST-- +Constant expressions with null coalescing operator ?? +--FILE-- +<?php + +const A = [1 => [[]]]; + +const T_1 = null ?? A[1]['undefined']['index'] ?? 1; +const T_2 = null ?? A['undefined']['index'] ?? 2; +const T_3 = null ?? A[1][0][2] ?? 3; +const T_4 = A[1][0][2] ?? 4; +const T_5 = null ?? __LINE__; +const T_6 = __LINE__ ?? "bar"; + +var_dump(T_1); +var_dump(T_2); +var_dump(T_3); +var_dump(T_4); +var_dump(T_5); +var_dump(T_6); + +var_dump((function(){ static $var = null ?? A[1]['undefined']['index'] ?? 1; return $var; })()); +var_dump((function(){ static $var = null ?? A['undefined']['index'] ?? 2; return $var; })()); +var_dump((function(){ static $var = null ?? A[1][0][2] ?? 3; return $var; })()); +var_dump((function(){ static $var = A[1][0][2] ?? 4; return $var; })()); + +var_dump((new class { public $var = null ?? A[1]['undefined']['index'] ?? 1; })->var); +var_dump((new class { public $var = null ?? A['undefined']['index'] ?? 2; })->var); +var_dump((new class { public $var = null ?? A[1][0][2] ?? 3; })->var); +var_dump((new class { public $var = A[1][0][2] ?? 4; })->var); + +?> +--EXPECTF-- +int(1) +int(2) +int(3) +int(4) +int(%d) +int(%d) +int(1) +int(2) +int(3) +int(4) +int(1) +int(2) +int(3) +int(4) diff --git a/Zend/tests/constant_expressions_coalesce_empty_dim.phpt b/Zend/tests/constant_expressions_coalesce_empty_dim.phpt new file mode 100644 index 0000000000..56ee43b789 --- /dev/null +++ b/Zend/tests/constant_expressions_coalesce_empty_dim.phpt @@ -0,0 +1,11 @@ +--TEST-- +Constant expressions with empty dimension fetch on coalesce +--FILE-- +<?php + +const A = [][] ?? 1; + +?> +--EXPECTF-- +Fatal error: Cannot use [] for reading in %s.php on line %d + diff --git a/Zend/tests/constant_expressions_dynamic.phpt b/Zend/tests/constant_expressions_dynamic.phpt index b0ba3a5b19..686dcc1d11 100644 --- a/Zend/tests/constant_expressions_dynamic.phpt +++ b/Zend/tests/constant_expressions_dynamic.phpt @@ -35,10 +35,12 @@ const T_19 = [ false => false, true => true, ]; +eval("const T_20x = 'a';"); +const T_20 = null ?: (T_20x . 'bc'); var_dump( T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9, T_10, - T_11, T_12, T_13, T_14, T_15, T_16, T_17, T_18, T_19 + T_11, T_12, T_13, T_14, T_15, T_16, T_17, T_18, T_19, T_20 ); ?> @@ -77,3 +79,4 @@ array(6) { [1]=> bool(true) } +string(3) "abc" diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index cfcd636269..4d3678f0b6 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -337,6 +337,30 @@ ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *sc zval_dtor(&op1); } break; + case ZEND_AST_COALESCE: + if (ast->child[0]->kind == ZEND_AST_DIM) { + ast->child[0]->attr = ZEND_DIM_IS; + } + + if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) { + ret = FAILURE; + break; + } + if (Z_TYPE(op1) > IS_NULL) { + *result = op1; + } else { + if (ast->child[1]->kind == ZEND_AST_DIM) { + ast->child[1]->attr = ZEND_DIM_IS; + } + + if (UNEXPECTED(zend_ast_evaluate(result, ast->child[1], scope) != SUCCESS)) { + zval_dtor(&op1); + ret = FAILURE; + break; + } + zval_dtor(&op1); + } + break; case ZEND_AST_UNARY_PLUS: if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[0], scope) != SUCCESS)) { ret = FAILURE; @@ -385,6 +409,14 @@ ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *sc } break; case ZEND_AST_DIM: + if (ast->child[1] == NULL) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading"); + } + + if (ast->attr == ZEND_DIM_IS && ast->child[0]->kind == ZEND_AST_DIM) { + ast->child[0]->attr = ZEND_DIM_IS; + } + if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) { ret = FAILURE; } else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) { @@ -393,7 +425,12 @@ ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *sc } else { zval tmp; - zend_fetch_dimension_by_zval(&tmp, &op1, &op2); + if (ast->attr == ZEND_DIM_IS) { + zend_fetch_dimension_by_zval_is(&tmp, &op1, &op2, IS_CONST); + } else { + zend_fetch_dimension_by_zval(&tmp, &op1, &op2); + } + if (UNEXPECTED(Z_ISREF(tmp))) { ZVAL_DUP(result, Z_REFVAL(tmp)); } else { diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index fe9139b609..af2d2e95cb 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4903,8 +4903,9 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter $%s", ZSTR_VAL(name)); } else if (zend_string_equals_literal(name, "this")) { - if (op_array->scope && (op_array->fn_flags & ZEND_ACC_STATIC) == 0) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); + if ((op_array->scope || (op_array->fn_flags & ZEND_ACC_CLOSURE)) + && (op_array->fn_flags & ZEND_ACC_STATIC) == 0) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as parameter"); } op_array->this_var = var_node.u.op.var; } @@ -7313,7 +7314,7 @@ zend_bool zend_is_allowed_in_const_expr(zend_ast_kind kind) /* {{{ */ || kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM || kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM || kind == ZEND_AST_CONST || kind == ZEND_AST_CLASS_CONST - || kind == ZEND_AST_MAGIC_CONST; + || kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_COALESCE; } /* }}} */ @@ -7447,14 +7448,16 @@ void zend_const_expr_to_zval(zval *result, zend_ast *ast) /* {{{ */ zend_compile_const_expr(&ast); if (ast->kind == ZEND_AST_ZVAL) { ZVAL_COPY_VALUE(result, zend_ast_get_zval(ast)); - - /* Kill this branch of the original AST, as it was already destroyed. - * It would be nice to find a better solution to this problem in the - * future. */ - orig_ast->kind = 0; } else { ZVAL_NEW_AST(result, zend_ast_copy(ast)); + /* destroy the ast here, it might have been replaced */ + zend_ast_destroy(ast); } + + /* Kill this branch of the original AST, as it was already destroyed. + * It would be nice to find a better solution to this problem in the + * future. */ + orig_ast->kind = 0; } /* }}} */ @@ -7865,6 +7868,26 @@ void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ return; } break; + case ZEND_AST_COALESCE: + zend_eval_const_expr(&ast->child[0]); + + if (ast->child[0]->kind != ZEND_AST_ZVAL) { + /* ensure everything was compile-time evaluated at least once */ + zend_eval_const_expr(&ast->child[1]); + return; + } + + if (Z_TYPE_P(zend_ast_get_zval(ast->child[0])) == IS_NULL) { + zend_eval_const_expr(&ast->child[1]); + *ast_ptr = ast->child[1]; + ast->child[1] = NULL; + zend_ast_destroy(ast); + } else { + *ast_ptr = ast->child[0]; + ast->child[0] = NULL; + zend_ast_destroy(ast); + } + return; case ZEND_AST_CONDITIONAL: { zend_ast **child, *child_ast; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 8fe291f443..20a622f4d8 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -896,6 +896,8 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name); #define ZEND_SEND_BY_REF 1 #define ZEND_SEND_PREFER_REF 2 +#define ZEND_DIM_IS 1 + static zend_always_inline int zend_check_arg_send_type(const zend_function *zf, uint32_t arg_num, uint32_t mask) { arg_num--; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index be4b039d89..68fc5e7f5d 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1938,6 +1938,12 @@ 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); } +ZEND_API void zend_fetch_dimension_by_zval_is(zval *result, zval *container, zval *dim, int dim_type) +{ + zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 1); +} + + static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type) { if (container_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 738895e73c..b2163c7d25 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -294,6 +294,7 @@ ZEND_API zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, con void zend_verify_abstract_class(zend_class_entry *ce); ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval *dim); +ZEND_API void zend_fetch_dimension_by_zval_is(zval *result, zval *container, zval *dim, int dim_type); ZEND_API zval* zend_get_compiled_variable_value(const zend_execute_data *execute_data_ptr, uint32_t var); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 49d6b20516..99494cff2a 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4670,7 +4670,7 @@ ZEND_VM_HANDLER(63, ZEND_RECV, NUM, ANY) zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var); SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)))) { + if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) { HANDLE_EXCEPTION(); } } @@ -4707,7 +4707,7 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, NUM, CONST) zval *default_value = EX_CONSTANT(opline->op2); SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(Z_CACHE_SLOT_P(default_value))))) { + if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(Z_CACHE_SLOT_P(default_value))) || EG(exception))) { HANDLE_EXCEPTION(); } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 99e2333644..4aa47ba299 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1498,7 +1498,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_ zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var); SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)))) { + if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) { HANDLE_EXCEPTION(); } } @@ -2308,7 +2308,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(Z zval *default_value = EX_CONSTANT(opline->op2); SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(Z_CACHE_SLOT_P(default_value))))) { + if (UNEXPECTED(!zend_verify_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(Z_CACHE_SLOT_P(default_value))) || EG(exception))) { HANDLE_EXCEPTION(); } } diff --git a/ext/intl/tests/timezone_IDforWindowsID_basic.phpt b/ext/intl/tests/timezone_IDforWindowsID_basic.phpt index 2fab10fdd7..4127d8e31c 100644 --- a/ext/intl/tests/timezone_IDforWindowsID_basic.phpt +++ b/ext/intl/tests/timezone_IDforWindowsID_basic.phpt @@ -4,6 +4,8 @@ IntlTimeZone::getIDForWindowsID basic test <?php if (!extension_loaded('intl')) die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '52') < 0) + die('skip for ICU >= 52'); --FILE-- <?php diff --git a/ext/intl/tests/timezone_windowsID_basic.phpt b/ext/intl/tests/timezone_windowsID_basic.phpt index 8a9fcfe95f..dd48f016e2 100644 --- a/ext/intl/tests/timezone_windowsID_basic.phpt +++ b/ext/intl/tests/timezone_windowsID_basic.phpt @@ -4,6 +4,8 @@ IntlTimeZone::getWindowsID basic test <?php if (!extension_loaded('intl')) die('skip intl extension not enabled'); +if (version_compare(INTL_ICU_VERSION, '52') < 0) + die('skip for ICU >= 52'); --FILE-- <?php |
