Skip to content

Commit 01453a0

Browse files
committed
Fix SEND_USER with ref arg
Even though the input is not a reference (or not treated as such), we still need to create a reference to satisfy the function signature. Various code relies on reference arguments actually being references. In this particular case, it would result in a JIT crash. The zend_call_function() implementation already handled this correctly.
1 parent d46b102 commit 01453a0

File tree

4 files changed

+47
-19
lines changed

4 files changed

+47
-19
lines changed

Zend/tests/call_user_func_by_ref.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
call_user_func() with ref arg and type check
3+
--FILE--
4+
<?php
5+
6+
function test(Type &$ref) {
7+
}
8+
try {
9+
call_user_func('test', 0);
10+
} catch (TypeError $e) {
11+
echo $e->getMessage(), "\n";
12+
}
13+
14+
?>
15+
--EXPECTF--
16+
Warning: test(): Argument #1 ($ref) must be passed by reference, value given in %s on line %d
17+
test(): Argument #1 ($ref) must be of type Type, int given, called in %s on line %d

Zend/tests/closure_invoke_ref_warning.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,3 @@ call_user_func([$test, '__invoke'], null);
99
?>
1010
--EXPECTF--
1111
Warning: Closure::__invoke(): Argument #1 ($arg) must be passed by reference, value given in %s on line %d
12-
13-
Warning: {closure}(): Argument #1 ($arg) must be passed by reference, value given in %s on line %d

Zend/zend_vm_def.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5326,13 +5326,16 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, CONST|TMP|VAR|CV, NUM)
53265326

53275327
SAVE_OPLINE();
53285328

5329+
arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
5330+
param = ZEND_CALL_VAR(EX(call), opline->result.var);
53295331
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
53305332
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
5333+
Z_TRY_ADDREF_P(arg);
5334+
ZVAL_NEW_REF(param, arg);
5335+
} else {
5336+
ZVAL_COPY(param, arg);
53315337
}
53325338

5333-
arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
5334-
param = ZEND_CALL_VAR(EX(call), opline->result.var);
5335-
ZVAL_COPY(param, arg);
53365339
FREE_OP1();
53375340
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
53385341
}

Zend/zend_vm_execute.h

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4477,14 +4477,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CONST_HANDLER(Z
44774477

44784478
SAVE_OPLINE();
44794479

4480+
arg = RT_CONSTANT(opline, opline->op1);
4481+
param = ZEND_CALL_VAR(EX(call), opline->result.var);
44804482
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
44814483
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
4484+
Z_TRY_ADDREF_P(arg);
4485+
ZVAL_NEW_REF(param, arg);
4486+
} else {
4487+
ZVAL_COPY(param, arg);
44824488
}
44834489

4484-
arg = RT_CONSTANT(opline, opline->op1);
4485-
param = ZEND_CALL_VAR(EX(call), opline->result.var);
4486-
ZVAL_COPY(param, arg);
4487-
44884490
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
44894491
}
44904492

@@ -18738,13 +18740,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_TMP_HANDLER(ZEN
1873818740

1873918741
SAVE_OPLINE();
1874018742

18743+
arg = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC);
18744+
param = ZEND_CALL_VAR(EX(call), opline->result.var);
1874118745
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
1874218746
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
18747+
Z_TRY_ADDREF_P(arg);
18748+
ZVAL_NEW_REF(param, arg);
18749+
} else {
18750+
ZVAL_COPY(param, arg);
1874318751
}
1874418752

18745-
arg = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC);
18746-
param = ZEND_CALL_VAR(EX(call), opline->result.var);
18747-
ZVAL_COPY(param, arg);
1874818753
zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
1874918754
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
1875018755
}
@@ -21311,13 +21316,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN
2131121316

2131221317
SAVE_OPLINE();
2131321318

21319+
arg = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC);
21320+
param = ZEND_CALL_VAR(EX(call), opline->result.var);
2131421321
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
2131521322
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
21323+
Z_TRY_ADDREF_P(arg);
21324+
ZVAL_NEW_REF(param, arg);
21325+
} else {
21326+
ZVAL_COPY(param, arg);
2131621327
}
2131721328

21318-
arg = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC);
21319-
param = ZEND_CALL_VAR(EX(call), opline->result.var);
21320-
ZVAL_COPY(param, arg);
2132121329
zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
2132221330
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
2132321331
}
@@ -37618,14 +37626,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND
3761837626

3761937627
SAVE_OPLINE();
3762037628

37629+
arg = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC);
37630+
param = ZEND_CALL_VAR(EX(call), opline->result.var);
3762137631
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
3762237632
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
37633+
Z_TRY_ADDREF_P(arg);
37634+
ZVAL_NEW_REF(param, arg);
37635+
} else {
37636+
ZVAL_COPY(param, arg);
3762337637
}
3762437638

37625-
arg = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC);
37626-
param = ZEND_CALL_VAR(EX(call), opline->result.var);
37627-
ZVAL_COPY(param, arg);
37628-
3762937639
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
3763037640
}
3763137641

0 commit comments

Comments
 (0)