diff options
| author | Nikita Popov <nikita.ppv@gmail.com> | 2020-09-14 15:49:49 +0200 |
|---|---|---|
| committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-09-14 15:49:49 +0200 |
| commit | 57a4a2c5a8ddd7e2f1214d5b05c270992e19451e (patch) | |
| tree | 536d9dc88c30f6cc67fb5362463b9c1460a11902 | |
| parent | 48368a6bf31300bcd5a1cbc03b89314be7bf6df8 (diff) | |
| download | php-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-- | NEWS | 2 | ||||
| -rw-r--r-- | Zend/tests/bug80096.phpt | 14 | ||||
| -rw-r--r-- | Zend/zend_execute.c | 31 |
3 files changed, 32 insertions, 15 deletions
@@ -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 <", double_encode: false)); + +?> +--EXPECT-- +The < character is encoded as < 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; } |
