Skip to content

Commit

Permalink
Fix SEND_USER with ref arg
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nikic committed Sep 17, 2021
1 parent d46b102 commit 01453a0
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 19 deletions.
17 changes: 17 additions & 0 deletions Zend/tests/call_user_func_by_ref.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
call_user_func() with ref arg and type check
--FILE--
<?php

function test(Type &$ref) {
}
try {
call_user_func('test', 0);
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECTF--
Warning: test(): Argument #1 ($ref) must be passed by reference, value given in %s on line %d
test(): Argument #1 ($ref) must be of type Type, int given, called in %s on line %d
2 changes: 0 additions & 2 deletions Zend/tests/closure_invoke_ref_warning.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,3 @@ call_user_func([$test, '__invoke'], null);
?>
--EXPECTF--
Warning: Closure::__invoke(): Argument #1 ($arg) must be passed by reference, value given in %s on line %d

Warning: {closure}(): Argument #1 ($arg) must be passed by reference, value given in %s on line %d
9 changes: 6 additions & 3 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -5326,13 +5326,16 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, CONST|TMP|VAR|CV, NUM)

SAVE_OPLINE();

arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
Z_TRY_ADDREF_P(arg);
ZVAL_NEW_REF(param, arg);
} else {
ZVAL_COPY(param, arg);
}

arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
ZVAL_COPY(param, arg);
FREE_OP1();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
Expand Down
38 changes: 24 additions & 14 deletions Zend/zend_vm_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -4477,14 +4477,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CONST_HANDLER(Z

SAVE_OPLINE();

arg = RT_CONSTANT(opline, opline->op1);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
Z_TRY_ADDREF_P(arg);
ZVAL_NEW_REF(param, arg);
} else {
ZVAL_COPY(param, arg);
}

arg = RT_CONSTANT(opline, opline->op1);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
ZVAL_COPY(param, arg);

ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

Expand Down Expand Up @@ -18738,13 +18740,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_TMP_HANDLER(ZEN

SAVE_OPLINE();

arg = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
Z_TRY_ADDREF_P(arg);
ZVAL_NEW_REF(param, arg);
} else {
ZVAL_COPY(param, arg);
}

arg = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
ZVAL_COPY(param, arg);
zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
Expand Down Expand Up @@ -21311,13 +21316,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN

SAVE_OPLINE();

arg = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
Z_TRY_ADDREF_P(arg);
ZVAL_NEW_REF(param, arg);
} else {
ZVAL_COPY(param, arg);
}

arg = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
ZVAL_COPY(param, arg);
zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
Expand Down Expand Up @@ -37618,14 +37626,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND

SAVE_OPLINE();

arg = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
Z_TRY_ADDREF_P(arg);
ZVAL_NEW_REF(param, arg);
} else {
ZVAL_COPY(param, arg);
}

arg = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC);
param = ZEND_CALL_VAR(EX(call), opline->result.var);
ZVAL_COPY(param, arg);

ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

Expand Down

0 comments on commit 01453a0

Please sign in to comment.