summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-09-14 15:49:49 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-09-14 15:49:49 +0200
commit57a4a2c5a8ddd7e2f1214d5b05c270992e19451e (patch)
tree536d9dc88c30f6cc67fb5362463b9c1460a11902
parent48368a6bf31300bcd5a1cbc03b89314be7bf6df8 (diff)
downloadphp-git-57a4a2c5a8ddd7e2f1214d5b05c270992e19451e.tar.gz
Fixed bug #80096
We shouldn't assume that call->prev_execute_data is NULL here. The value needs to be preserved for call chains.
-rw-r--r--NEWS2
-rw-r--r--Zend/tests/bug80096.phpt14
-rw-r--r--Zend/zend_execute.c31
3 files changed, 32 insertions, 15 deletions
diff --git a/NEWS b/NEWS
index 434a132d78..87f9550353 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ PHP NEWS
https://wiki.php.net/rfc/shorter_attribute_syntax_change
. Fixed bug #80045 (memleak after two set_exception_handler calls with
__call). (Nikita)
+ . Fixed bug #80096 (Segmentation fault with named arguments in nested call).
+ (Nikita)
- Date:
. Fixed bug #80057 (DateTimeImmutable::createFromFormat() does not populate
diff --git a/Zend/tests/bug80096.phpt b/Zend/tests/bug80096.phpt
new file mode 100644
index 0000000000..d1d2d0249b
--- /dev/null
+++ b/Zend/tests/bug80096.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug #80096: Segmentation fault with named arguments in nested call
+--FILE--
+<?php
+
+function println($arg) {
+ echo $arg, "\n";
+}
+
+println(htmlentities("The < character is encoded as &lt;", double_encode: false));
+
+?>
+--EXPECT--
+The &lt; character is encoded as &lt;
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 55466a1e07..3cf2af2ae8 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -4430,17 +4430,18 @@ zval * ZEND_FASTCALL zend_handle_named_arg(
return arg;
}
-static void start_fake_frame(zend_execute_data *call, const zend_op *opline) {
- zend_execute_data *prev_execute_data = EG(current_execute_data);
- call->prev_execute_data = prev_execute_data;
+static zend_execute_data *start_fake_frame(zend_execute_data *call, const zend_op *opline) {
+ zend_execute_data *old_prev_execute_data = call->prev_execute_data;
+ call->prev_execute_data = EG(current_execute_data);
call->opline = opline;
EG(current_execute_data) = call;
+ return old_prev_execute_data;
}
-static void end_fake_frame(zend_execute_data *call) {
+static void end_fake_frame(zend_execute_data *call, zend_execute_data *old_prev_execute_data) {
zend_execute_data *prev_execute_data = call->prev_execute_data;
EG(current_execute_data) = prev_execute_data;
- call->prev_execute_data = NULL;
+ call->prev_execute_data = old_prev_execute_data;
if (UNEXPECTED(EG(exception)) && ZEND_USER_CODE(prev_execute_data->func->common.type)) {
zend_rethrow_exception(prev_execute_data);
}
@@ -4473,9 +4474,9 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal
* value is not accessible through back traces. */
zval tmp;
ZVAL_COPY(&tmp, default_value);
- start_fake_frame(call, opline);
+ zend_execute_data *old = start_fake_frame(call, opline);
zend_result ret = zval_update_constant_ex(&tmp, fbc->op_array.scope);
- end_fake_frame(call);
+ end_fake_frame(call, old);
if (UNEXPECTED(ret == FAILURE)) {
zval_ptr_dtor_nogc(&tmp);
return FAILURE;
@@ -4490,9 +4491,9 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal
}
} else {
ZEND_ASSERT(opline->opcode == ZEND_RECV);
- start_fake_frame(call, opline);
+ zend_execute_data *old = start_fake_frame(call, opline);
zend_argument_error(zend_ce_argument_count_error, i + 1, "not passed");
- end_fake_frame(call);
+ end_fake_frame(call, old);
return FAILURE;
}
}
@@ -4513,25 +4514,25 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal
zend_internal_arg_info *arg_info = &fbc->internal_function.arg_info[i];
if (i < fbc->common.required_num_args) {
- start_fake_frame(call, NULL);
+ zend_execute_data *old = start_fake_frame(call, NULL);
zend_argument_error(zend_ce_argument_count_error, i + 1, "not passed");
- end_fake_frame(call);
+ end_fake_frame(call, old);
return FAILURE;
}
zval default_value;
if (zend_get_default_from_internal_arg_info(&default_value, arg_info) == FAILURE) {
- start_fake_frame(call, NULL);
+ zend_execute_data *old = start_fake_frame(call, NULL);
zend_argument_error(zend_ce_argument_count_error, i + 1,
"must be passed explicitly, because the default value is not known");
- end_fake_frame(call);
+ end_fake_frame(call, old);
return FAILURE;
}
if (Z_TYPE(default_value) == IS_CONSTANT_AST) {
- start_fake_frame(call, NULL);
+ zend_execute_data *old = start_fake_frame(call, NULL);
zend_result ret = zval_update_constant_ex(&default_value, fbc->common.scope);
- end_fake_frame(call);
+ end_fake_frame(call, old);
if (ret == FAILURE) {
return FAILURE;
}