Skip to content

Commit 57a4a2c

Browse files
committed
Fixed bug #80096
We shouldn't assume that call->prev_execute_data is NULL here. The value needs to be preserved for call chains.
1 parent 48368a6 commit 57a4a2c

File tree

3 files changed

+32
-15
lines changed

3 files changed

+32
-15
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ PHP NEWS
77
https://wiki.php.net/rfc/shorter_attribute_syntax_change
88
. Fixed bug #80045 (memleak after two set_exception_handler calls with
99
__call). (Nikita)
10+
. Fixed bug #80096 (Segmentation fault with named arguments in nested call).
11+
(Nikita)
1012

1113
- Date:
1214
. Fixed bug #80057 (DateTimeImmutable::createFromFormat() does not populate

Zend/tests/bug80096.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Bug #80096: Segmentation fault with named arguments in nested call
3+
--FILE--
4+
<?php
5+
6+
function println($arg) {
7+
echo $arg, "\n";
8+
}
9+
10+
println(htmlentities("The < character is encoded as &lt;", double_encode: false));
11+
12+
?>
13+
--EXPECT--
14+
The &lt; character is encoded as &lt;

Zend/zend_execute.c

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4430,17 +4430,18 @@ zval * ZEND_FASTCALL zend_handle_named_arg(
44304430
return arg;
44314431
}
44324432

4433-
static void start_fake_frame(zend_execute_data *call, const zend_op *opline) {
4434-
zend_execute_data *prev_execute_data = EG(current_execute_data);
4435-
call->prev_execute_data = prev_execute_data;
4433+
static zend_execute_data *start_fake_frame(zend_execute_data *call, const zend_op *opline) {
4434+
zend_execute_data *old_prev_execute_data = call->prev_execute_data;
4435+
call->prev_execute_data = EG(current_execute_data);
44364436
call->opline = opline;
44374437
EG(current_execute_data) = call;
4438+
return old_prev_execute_data;
44384439
}
44394440

4440-
static void end_fake_frame(zend_execute_data *call) {
4441+
static void end_fake_frame(zend_execute_data *call, zend_execute_data *old_prev_execute_data) {
44414442
zend_execute_data *prev_execute_data = call->prev_execute_data;
44424443
EG(current_execute_data) = prev_execute_data;
4443-
call->prev_execute_data = NULL;
4444+
call->prev_execute_data = old_prev_execute_data;
44444445
if (UNEXPECTED(EG(exception)) && ZEND_USER_CODE(prev_execute_data->func->common.type)) {
44454446
zend_rethrow_exception(prev_execute_data);
44464447
}
@@ -4473,9 +4474,9 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal
44734474
* value is not accessible through back traces. */
44744475
zval tmp;
44754476
ZVAL_COPY(&tmp, default_value);
4476-
start_fake_frame(call, opline);
4477+
zend_execute_data *old = start_fake_frame(call, opline);
44774478
zend_result ret = zval_update_constant_ex(&tmp, fbc->op_array.scope);
4478-
end_fake_frame(call);
4479+
end_fake_frame(call, old);
44794480
if (UNEXPECTED(ret == FAILURE)) {
44804481
zval_ptr_dtor_nogc(&tmp);
44814482
return FAILURE;
@@ -4490,9 +4491,9 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal
44904491
}
44914492
} else {
44924493
ZEND_ASSERT(opline->opcode == ZEND_RECV);
4493-
start_fake_frame(call, opline);
4494+
zend_execute_data *old = start_fake_frame(call, opline);
44944495
zend_argument_error(zend_ce_argument_count_error, i + 1, "not passed");
4495-
end_fake_frame(call);
4496+
end_fake_frame(call, old);
44964497
return FAILURE;
44974498
}
44984499
}
@@ -4513,25 +4514,25 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal
45134514

45144515
zend_internal_arg_info *arg_info = &fbc->internal_function.arg_info[i];
45154516
if (i < fbc->common.required_num_args) {
4516-
start_fake_frame(call, NULL);
4517+
zend_execute_data *old = start_fake_frame(call, NULL);
45174518
zend_argument_error(zend_ce_argument_count_error, i + 1, "not passed");
4518-
end_fake_frame(call);
4519+
end_fake_frame(call, old);
45194520
return FAILURE;
45204521
}
45214522

45224523
zval default_value;
45234524
if (zend_get_default_from_internal_arg_info(&default_value, arg_info) == FAILURE) {
4524-
start_fake_frame(call, NULL);
4525+
zend_execute_data *old = start_fake_frame(call, NULL);
45254526
zend_argument_error(zend_ce_argument_count_error, i + 1,
45264527
"must be passed explicitly, because the default value is not known");
4527-
end_fake_frame(call);
4528+
end_fake_frame(call, old);
45284529
return FAILURE;
45294530
}
45304531

45314532
if (Z_TYPE(default_value) == IS_CONSTANT_AST) {
4532-
start_fake_frame(call, NULL);
4533+
zend_execute_data *old = start_fake_frame(call, NULL);
45334534
zend_result ret = zval_update_constant_ex(&default_value, fbc->common.scope);
4534-
end_fake_frame(call);
4535+
end_fake_frame(call, old);
45354536
if (ret == FAILURE) {
45364537
return FAILURE;
45374538
}

0 commit comments

Comments
 (0)