summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2016-09-26 14:14:57 +0300
committerDmitry Stogov <dmitry@zend.com>2016-09-26 14:14:57 +0300
commitd2791184228ff86878acda46567a3bc2a94f2a36 (patch)
treeac181b827714dcbbcc4b56a141157f4caf6fd702
parent4e7b5ca45953cb22213bbd9ed5b95b4b1898bab0 (diff)
downloadphp-git-d2791184228ff86878acda46567a3bc2a94f2a36.tar.gz
Fixed bug #73156 (segfault on undefined function)
-rw-r--r--NEWS1
-rw-r--r--Zend/tests/bug73156.phpt50
-rw-r--r--Zend/zend_builtin_functions.c30
3 files changed, 78 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index 674a6cb05c..c692a67bff 100644
--- a/NEWS
+++ b/NEWS
@@ -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) {