Skip to content

Commit 061c708

Browse files
committed
Correctly report failure in zend_handle_undef_args()
And do the check before increfing the closure object, otherwise we'd have to release it as well. Fixes oss-fuzz #25313.
1 parent e81becc commit 061c708

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

Zend/tests/named_params/call_user_func.phpt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ $test_variadic = function(...$args) {
1212
$test_ref = function(&$ref) {
1313
$ref++;
1414
};
15+
$test_required = function($a, $b) {
16+
echo "a = $a, b = $b\n";
17+
};
1518

1619
class Test {
1720
public function __construct($a = 'a', $b = 'b', $c = 'c') {
@@ -31,6 +34,11 @@ call_user_func($test, c: 'C');
3134
call_user_func($test_variadic, 'A', c: 'C');
3235
call_user_func($test_ref, ref: null);
3336
var_dump(call_user_func('call_user_func', $test, c: 'D'));
37+
try {
38+
call_user_func($test_required, b: 'B');
39+
} catch (ArgumentCountError $e) {
40+
echo $e->getMessage(), "\n";
41+
}
3442
try {
3543
var_dump(call_user_func('array_slice', [1, 2, 3, 4, 5], length: 2));
3644
} catch (ArgumentCountError $e) {
@@ -74,6 +82,7 @@ array(2) {
7482
Warning: {closure}(): Argument #1 ($ref) must be passed by reference, value given in %s on line %d
7583
a = a, b = b, c = D
7684
NULL
85+
{closure}(): Argument #1 ($a) not passed
7786
array_slice(): Argument #2 ($offset) not passed
7887
array(2) {
7988
[3]=>

Zend/zend_execute.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4491,6 +4491,7 @@ ZEND_API zend_result ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *cal
44914491
start_fake_frame(call, opline);
44924492
zend_argument_error(zend_ce_argument_count_error, i + 1, "not passed");
44934493
end_fake_frame(call);
4494+
return FAILURE;
44944495
}
44954496
}
44964497

Zend/zend_execute_API.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -839,17 +839,6 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
839839
} ZEND_HASH_FOREACH_END();
840840
}
841841

842-
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
843-
uint32_t call_info;
844-
845-
GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
846-
call_info = ZEND_CALL_CLOSURE;
847-
if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
848-
call_info |= ZEND_CALL_FAKE_CLOSURE;
849-
}
850-
ZEND_ADD_CALL_FLAG(call, call_info);
851-
}
852-
853842
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_MAY_HAVE_UNDEF)) {
854843
if (zend_handle_undef_args(call) == FAILURE) {
855844
zend_vm_stack_free_args(call);
@@ -861,6 +850,17 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
861850
}
862851
}
863852

853+
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
854+
uint32_t call_info;
855+
856+
GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
857+
call_info = ZEND_CALL_CLOSURE;
858+
if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
859+
call_info |= ZEND_CALL_FAKE_CLOSURE;
860+
}
861+
ZEND_ADD_CALL_FLAG(call, call_info);
862+
}
863+
864864
orig_fake_scope = EG(fake_scope);
865865
EG(fake_scope) = NULL;
866866
if (func->type == ZEND_USER_FUNCTION) {

0 commit comments

Comments
 (0)