From e11faad233156f912d71a3027ffce75b74f86e3b Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 30 Sep 2021 14:53:47 +0200 Subject: [PATCH] Create reference wrappers in SEND_UNPACK if necessary Even if we can't actually pass by reference, we still need to create the REFERENCE wrapper to satisfy the calling convention. The particular test case would crash with JIT, because the existence of the reference was assumed. Fixes oss-fuzz #39440. --- .../unpack_iterator_by_ref_type_check.phpt | 18 ++++++++++++++++++ Zend/zend_vm_def.h | 19 ++++++++++++++----- Zend/zend_vm_execute.h | 19 ++++++++++++++----- 3 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 Zend/tests/unpack_iterator_by_ref_type_check.phpt diff --git a/Zend/tests/unpack_iterator_by_ref_type_check.phpt b/Zend/tests/unpack_iterator_by_ref_type_check.phpt new file mode 100644 index 00000000000..2fef31056bd --- /dev/null +++ b/Zend/tests/unpack_iterator_by_ref_type_check.phpt @@ -0,0 +1,18 @@ +--TEST-- +Unpack iterator by reference with type check +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +Warning: Cannot pass by-reference argument 1 of test() by unpacking a Traversable, passing by-value instead in %s on line %d +test(): Argument #1 ($a) must be of type T, null given, called in %s on line %d diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f324d801c01..d28628c044a 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5126,6 +5126,9 @@ ZEND_VM_C_LABEL(send_again): break; } + ZVAL_DEREF(arg); + Z_TRY_ADDREF_P(arg); + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" @@ -5134,9 +5137,11 @@ ZEND_VM_C_LABEL(send_again): EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name) ); + ZVAL_NEW_REF(top, arg); + } else { + ZVAL_COPY_VALUE(top, arg); } - ZVAL_COPY_DEREF(top, arg); zend_string_release(name); } else { if (have_named_params) { @@ -5145,6 +5150,11 @@ ZEND_VM_C_LABEL(send_again): break; } + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1); + top = ZEND_CALL_ARG(EX(call), arg_num); + ZVAL_DEREF(arg); + Z_TRY_ADDREF_P(arg); + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" @@ -5153,12 +5163,11 @@ ZEND_VM_C_LABEL(send_again): EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name) ); + ZVAL_NEW_REF(top, arg); + } else { + ZVAL_COPY_VALUE(top, arg); } - - zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1); - top = ZEND_CALL_ARG(EX(call), arg_num); - ZVAL_COPY_DEREF(top, arg); ZEND_CALL_NUM_ARGS(EX(call))++; } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a4a268d81e8..329fa827dd4 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2248,6 +2248,9 @@ send_again: break; } + ZVAL_DEREF(arg); + Z_TRY_ADDREF_P(arg); + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" @@ -2256,9 +2259,11 @@ send_again: EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name) ); + ZVAL_NEW_REF(top, arg); + } else { + ZVAL_COPY_VALUE(top, arg); } - ZVAL_COPY_DEREF(top, arg); zend_string_release(name); } else { if (have_named_params) { @@ -2267,6 +2272,11 @@ send_again: break; } + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1); + top = ZEND_CALL_ARG(EX(call), arg_num); + ZVAL_DEREF(arg); + Z_TRY_ADDREF_P(arg); + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" @@ -2275,12 +2285,11 @@ send_again: EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name) ); + ZVAL_NEW_REF(top, arg); + } else { + ZVAL_COPY_VALUE(top, arg); } - - zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1); - top = ZEND_CALL_ARG(EX(call), arg_num); - ZVAL_COPY_DEREF(top, arg); ZEND_CALL_NUM_ARGS(EX(call))++; }