diff --git a/Zend/tests/arg_unpack/gh25313.phpt b/Zend/tests/arg_unpack/gh25313.phpt new file mode 100644 index 000000000000..072a4f2aa71c --- /dev/null +++ b/Zend/tests/arg_unpack/gh25313.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-25313 (Assertion !EG(exception) in ZEND_FE_FREE when unpacking a generator into a by-ref parameter throws) +--CREDITS-- +YuanchengJiang +--FILE-- +getMessage(), "\n"; +} + +try { + test(...gen(['a' => 1, 'b' => 2]), ...gen(['c' => 3, 'ref' => 4])); +} catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Exception: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead +Exception: Cannot pass by-reference argument 4 of test() by unpacking a Traversable, passing by-value instead diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f9432cb65856..4d5301ad0233 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5356,6 +5356,7 @@ ZEND_VM_C_LABEL(send_again): Z_TRY_ADDREF_P(arg); if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + ZVAL_NEW_REF(top, arg); zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" " by unpacking a Traversable, passing by-value instead", arg_num, @@ -5363,7 +5364,10 @@ ZEND_VM_C_LABEL(send_again): EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name) ); - ZVAL_NEW_REF(top, arg); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_string_release(name); + break; + } } else { ZVAL_COPY_VALUE(top, arg); } @@ -5380,8 +5384,10 @@ ZEND_VM_C_LABEL(send_again): top = ZEND_CALL_ARG(EX(call), arg_num); ZVAL_DEREF(arg); Z_TRY_ADDREF_P(arg); + ZEND_CALL_NUM_ARGS(EX(call))++; if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + ZVAL_NEW_REF(top, arg); zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" " by unpacking a Traversable, passing by-value instead", arg_num, @@ -5389,12 +5395,12 @@ ZEND_VM_C_LABEL(send_again): EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name) ); - ZVAL_NEW_REF(top, arg); + if (UNEXPECTED(EG(exception) != NULL)) { + break; + } } else { ZVAL_COPY_VALUE(top, arg); } - - ZEND_CALL_NUM_ARGS(EX(call))++; } funcs->move_forward(iter); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3137c55eac0d..812402c79312 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2440,6 +2440,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_ Z_TRY_ADDREF_P(arg); if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + ZVAL_NEW_REF(top, arg); zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" " by unpacking a Traversable, passing by-value instead", arg_num, @@ -2447,7 +2448,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_ EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name) ); - ZVAL_NEW_REF(top, arg); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_string_release(name); + break; + } } else { ZVAL_COPY_VALUE(top, arg); } @@ -2464,8 +2468,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_ top = ZEND_CALL_ARG(EX(call), arg_num); ZVAL_DEREF(arg); Z_TRY_ADDREF_P(arg); + ZEND_CALL_NUM_ARGS(EX(call))++; if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + ZVAL_NEW_REF(top, arg); zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" " by unpacking a Traversable, passing by-value instead", arg_num, @@ -2473,12 +2479,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_ EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name) ); - ZVAL_NEW_REF(top, arg); + if (UNEXPECTED(EG(exception) != NULL)) { + break; + } } else { ZVAL_COPY_VALUE(top, arg); } - - ZEND_CALL_NUM_ARGS(EX(call))++; } funcs->move_forward(iter);