diff options
-rw-r--r-- | Zend/tests/bug79979.phpt | 17 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 20 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 16 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 16 |
4 files changed, 61 insertions, 8 deletions
diff --git a/Zend/tests/bug79979.phpt b/Zend/tests/bug79979.phpt new file mode 100644 index 0000000000..c41d3889e9 --- /dev/null +++ b/Zend/tests/bug79979.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #79979 (passing value to by-ref param via CUF(A) crashes) +--FILE-- +<?php +call_user_func_array("str_replace", ["a", "b", "c", 0]); + +$cufa = "call_user_func_array"; +$cufa("str_replace", ["a", "b", "c", 0]); + +call_user_func_array($cufa, ["str_replace", ["a", "b", "c", 0]]); +?> +--EXPECTF-- +Warning: str_replace(): Argument #4 ($replace_count) must be passed by reference, value given in %s on line %d + +Warning: str_replace(): Argument #4 ($replace_count) must be passed by reference, value given in %s on line %d + +Warning: str_replace(): Argument #4 ($replace_count) must be passed by reference, value given in %s on line %d diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index b3d6319560..ece3679822 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -734,6 +734,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / for (i=0; i<fci->param_count; i++) { zval *param = ZEND_CALL_ARG(call, i+1); zval *arg = &fci->params[i]; + zend_bool must_wrap = 0; if (UNEXPECTED(Z_ISUNDEF_P(arg))) { /* Allow forwarding undef slots. This is only used by Closure::__invoke(). */ ZVAL_UNDEF(param); @@ -745,8 +746,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / if (UNEXPECTED(!Z_ISREF_P(arg))) { if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { /* By-value send is not allowed -- emit a warning, - * but still perform the call with a by-value send. */ + * and perform the call with the value wrapped in a reference. */ zend_param_must_be_ref(func, i + 1); + must_wrap = 1; if (UNEXPECTED(EG(exception))) { ZEND_CALL_NUM_ARGS(call) = i; cleanup_args: @@ -767,7 +769,11 @@ cleanup_args: } } - ZVAL_COPY(param, arg); + if (EXPECTED(!must_wrap)) { + ZVAL_COPY(param, arg); + } else { + ZVAL_NEW_REF(param, arg); + } } if (fci->named_params) { @@ -775,6 +781,7 @@ cleanup_args: zval *arg; uint32_t arg_num = ZEND_CALL_NUM_ARGS(call) + 1; zend_bool have_named_params = 0; + zend_bool must_wrap = 0; ZEND_HASH_FOREACH_STR_KEY_VAL(fci->named_params, name, arg) { zval *target; if (name) { @@ -799,8 +806,9 @@ cleanup_args: if (UNEXPECTED(!Z_ISREF_P(arg))) { if (!ARG_MAY_BE_SENT_BY_REF(func, arg_num)) { /* By-value send is not allowed -- emit a warning, - * but still perform the call with a by-value send. */ + * and perform the call with the value wrapped in a reference. */ zend_param_must_be_ref(func, arg_num); + must_wrap = 1; if (UNEXPECTED(EG(exception))) { goto cleanup_args; } @@ -814,7 +822,11 @@ cleanup_args: } } - ZVAL_COPY(target, arg); + if (EXPECTED(!must_wrap)) { + ZVAL_COPY(target, arg); + } else { + ZVAL_NEW_REF(target, arg); + } if (!name) { ZEND_CALL_NUM_ARGS(call)++; arg_num++; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b92928e3b0..805f8f0a3e 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5203,6 +5203,7 @@ ZEND_VM_C_LABEL(send_array): arg_num = 1; param = ZEND_CALL_ARG(EX(call), 1); ZEND_HASH_FOREACH_VAL(ht, arg) { + zend_bool must_wrap = 0; if (skip > 0) { skip--; continue; @@ -5214,6 +5215,7 @@ ZEND_VM_C_LABEL(send_array): /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); + must_wrap = 1; } } } else { @@ -5223,7 +5225,11 @@ ZEND_VM_C_LABEL(send_array): arg = Z_REFVAL_P(arg); } } - ZVAL_COPY(param, arg); + if (EXPECTED(!must_wrap)) { + ZVAL_COPY(param, arg); + } else { + ZVAL_NEW_REF(param, arg); + } ZEND_CALL_NUM_ARGS(EX(call))++; arg_num++; param++; @@ -5253,12 +5259,14 @@ ZEND_VM_C_LABEL(send_array): HANDLE_EXCEPTION(); } + zend_bool must_wrap = 0; if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); + must_wrap = 1; } } } else { @@ -5269,7 +5277,11 @@ ZEND_VM_C_LABEL(send_array): } } - ZVAL_COPY(param, arg); + if (EXPECTED(!must_wrap)) { + ZVAL_COPY(param, arg); + } else { + ZVAL_NEW_REF(param, arg); + } if (!name) { ZEND_CALL_NUM_ARGS(EX(call))++; arg_num++; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 7a50d99d29..d87edfc570 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2098,6 +2098,7 @@ send_array: arg_num = 1; param = ZEND_CALL_ARG(EX(call), 1); ZEND_HASH_FOREACH_VAL(ht, arg) { + zend_bool must_wrap = 0; if (skip > 0) { skip--; continue; @@ -2109,6 +2110,7 @@ send_array: /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); + must_wrap = 1; } } } else { @@ -2118,7 +2120,11 @@ send_array: arg = Z_REFVAL_P(arg); } } - ZVAL_COPY(param, arg); + if (EXPECTED(!must_wrap)) { + ZVAL_COPY(param, arg); + } else { + ZVAL_NEW_REF(param, arg); + } ZEND_CALL_NUM_ARGS(EX(call))++; arg_num++; param++; @@ -2148,12 +2154,14 @@ send_array: HANDLE_EXCEPTION(); } + zend_bool must_wrap = 0; if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); + must_wrap = 1; } } } else { @@ -2164,7 +2172,11 @@ send_array: } } - ZVAL_COPY(param, arg); + if (EXPECTED(!must_wrap)) { + ZVAL_COPY(param, arg); + } else { + ZVAL_NEW_REF(param, arg); + } if (!name) { ZEND_CALL_NUM_ARGS(EX(call))++; arg_num++; |