diff options
author | Dmitry Stogov <dmitry@zend.com> | 2016-09-26 14:14:57 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2016-09-26 14:14:57 +0300 |
commit | d2791184228ff86878acda46567a3bc2a94f2a36 (patch) | |
tree | ac181b827714dcbbcc4b56a141157f4caf6fd702 | |
parent | 4e7b5ca45953cb22213bbd9ed5b95b4b1898bab0 (diff) | |
download | php-git-d2791184228ff86878acda46567a3bc2a94f2a36.tar.gz |
Fixed bug #73156 (segfault on undefined function)
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | Zend/tests/bug73156.phpt | 50 | ||||
-rw-r--r-- | Zend/zend_builtin_functions.c | 30 |
3 files changed, 78 insertions, 3 deletions
@@ -11,6 +11,7 @@ PHP NEWS password_verify). (Anatol) . Fixed bug #73058 (crypt broken when salt is 'too' long). (Anatol) . Fixed bug #69579 (Invalid free in extension trait). (John Boehr) + . Fixed bug #73156 (segfault on undefined function). (Dmitry) . Fixed bug #73163 (PHP hangs if error handler throws while accessing undef const in default value). (Nikita) diff --git a/Zend/tests/bug73156.phpt b/Zend/tests/bug73156.phpt new file mode 100644 index 0000000000..b5092514a0 --- /dev/null +++ b/Zend/tests/bug73156.phpt @@ -0,0 +1,50 @@ +--TEST-- +iBug #73156 (segfault on undefined function) +--FILE-- +<?php +class A { + public function __call($name, $args) { + eval('$args = array(); var_dump(debug_backtrace());'); + } +} + +$a = new A(); + +$a->test("test"); +?> +--EXPECTF-- +array(2) { + [0]=> + array(3) { + ["file"]=> + string(%d) "%sbug73156.php" + ["line"]=> + int(4) + ["function"]=> + string(4) "eval" + } + [1]=> + array(7) { + ["file"]=> + string(%d) "%sbug73156.php" + ["line"]=> + int(10) + ["function"]=> + string(6) "__call" + ["class"]=> + string(1) "A" + ["object"]=> + object(A)#%d (0) { + } + ["type"]=> + string(2) "->" + ["args"]=> + array(2) { + [0]=> + string(4) "test" + [1]=> + array(0) { + } + } + } +} diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index c3160d0a6f..9aa6725af4 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -2211,9 +2211,33 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / zend_hash_real_init(Z_ARRVAL_P(arg_array), 1); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(arg_array)) { if (call->func->type == ZEND_USER_FUNCTION) { - uint32_t first_extra_arg = call->func->op_array.num_args; + uint32_t first_extra_arg = MIN(num_args, call->func->op_array.num_args); - if (ZEND_CALL_NUM_ARGS(call) > first_extra_arg) { + if (UNEXPECTED(call->symbol_table)) { + /* In case of attached symbol_table, values on stack may be invalid + * and we have to access them through symbol_table + * See: https://bugs.php.net/bug.php?id=73156 + */ + zend_string *arg_name; + zval *arg; + + while (i < first_extra_arg) { + arg_name = call->func->op_array.vars[i]; + arg = zend_hash_find_ind(call->symbol_table, arg_name); + if (arg) { + if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + n++; + ZEND_HASH_FILL_ADD(arg); + } else { + zval tmp; + ZVAL_UNDEF(&tmp); + ZEND_HASH_FILL_ADD(&tmp); + } + i++; + } + } else { while (i < first_extra_arg) { if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) { if (Z_OPT_REFCOUNTED_P(p)) { @@ -2225,8 +2249,8 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / p++; i++; } - p = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T); } + p = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T); } while (i < num_args) { |