From: Nikita Popov Date: Sat, 6 Aug 2016 13:24:23 +0000 (+0200) Subject: call_user_func(_array): Don't abort on reference warning X-Git-Tag: php-7.1.0RC1~75 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=906456c4106ac74da0688b2481e91e27de3b176b;p=php call_user_func(_array): Don't abort on reference warning Change zend_call_function() to not abort the call if a non-reference is passed to a reference argument. The usual warning will still be thrown, but the call will proceed as usual. --- diff --git a/Zend/tests/call_user_func_008.phpt b/Zend/tests/call_user_func_008.phpt new file mode 100644 index 0000000000..3e727e7f43 --- /dev/null +++ b/Zend/tests/call_user_func_008.phpt @@ -0,0 +1,54 @@ +--TEST-- +call_user_func() behavior with references +--FILE-- + +--EXPECTF-- +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) + +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) + +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) + +Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d + +Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d +bool(true) +int(0) +int(0) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 3432064eaf..dc411af835 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -788,41 +788,29 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (fci->no_separation && - !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { - if (i) { - /* hack to clean up the stack */ - ZEND_CALL_NUM_ARGS(call) = i; - zend_vm_stack_free_args(call); - } - zend_vm_stack_free_call_frame(call); - - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", - i+1, + if (!fci->no_separation) { + /* Separation is enabled -- create a ref */ + ZVAL_NEW_REF(arg, arg); + } else 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. */ + zend_error(E_WARNING, + "Parameter %d to %s%s%s() expected to be a reference, value given", i+1, func->common.scope ? ZSTR_VAL(func->common.scope->name) : "", func->common.scope ? "::" : "", ZSTR_VAL(func->common.function_name)); - if (EG(current_execute_data) == &dummy_execute_data) { - EG(current_execute_data) = dummy_execute_data.prev_execute_data; - } - return FAILURE; } - - ZVAL_NEW_REF(arg, arg); } - Z_ADDREF_P(arg); } else { if (Z_ISREF_P(arg) && !(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { /* don't separate references for __call */ arg = Z_REFVAL_P(arg); } - if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } } + param = ZEND_CALL_ARG(call, i+1); - ZVAL_COPY_VALUE(param, arg); + ZVAL_COPY(param, arg); } if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1a52041ab3..c64eebb781 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4626,23 +4626,15 @@ ZEND_VM_C_LABEL(send_array): 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)) { - - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + /* By-value send is not allowed -- emit a warning, + * but still perform the call. */ + zend_error(E_WARNING, + "Parameter %d to %s%s%s() expected to be a reference, value given", arg_num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - break; } } } else { @@ -4673,25 +4665,12 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, NUM) param = ZEND_CALL_VAR(EX(call), opline->result.var); if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + ZVAL_DEREF(arg); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", opline->op2.num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - ZVAL_UNDEF(param); - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - - FREE_OP1(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { if (Z_ISREF_P(arg) && !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3d0bcf8a19..46c87e72aa 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1423,23 +1423,15 @@ send_array: 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)) { - - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + /* By-value send is not allowed -- emit a warning, + * but still perform the call. */ + zend_error(E_WARNING, + "Parameter %d to %s%s%s() expected to be a reference, value given", arg_num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - break; } } } else { @@ -15904,25 +15896,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN param = ZEND_CALL_VAR(EX(call), opline->result.var); if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + ZVAL_DEREF(arg); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", opline->op2.num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - ZVAL_UNDEF(param); - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - - zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { if (Z_ISREF_P(arg) && !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { @@ -34925,24 +34904,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND param = ZEND_CALL_VAR(EX(call), opline->result.var); if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + ZVAL_DEREF(arg); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", opline->op2.num, EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", EX(call)->func->common.scope ? "::" : "", ZSTR_VAL(EX(call)->func->common.function_name)); - - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_TYPE(EX(call)->This) == IS_OBJECT) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - ZVAL_UNDEF(param); - EX(call)->func = (zend_function*)&zend_pass_function; - Z_OBJ(EX(call)->This) = NULL; - ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { if (Z_ISREF_P(arg) && !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { diff --git a/ext/phar/tests/cache_list/files/frontcontroller17.phar b/ext/phar/tests/cache_list/files/frontcontroller17.phar index b83d41fd5b..d9b8330e63 100644 Binary files a/ext/phar/tests/cache_list/files/frontcontroller17.phar and b/ext/phar/tests/cache_list/files/frontcontroller17.phar differ diff --git a/ext/phar/tests/cache_list/files/frontcontroller17.phar.inc b/ext/phar/tests/cache_list/files/frontcontroller17.phar.inc index 85b8729f31..715479552a 100644 --- a/ext/phar/tests/cache_list/files/frontcontroller17.phar.inc +++ b/ext/phar/tests/cache_list/files/frontcontroller17.phar.inc @@ -6,7 +6,7 @@ echo "hi"; '; $a->setStub('getMessage() . "\n"); } diff --git a/ext/phar/tests/cache_list/frontcontroller32.phpt b/ext/phar/tests/cache_list/frontcontroller32.phpt index 59116907a5..cb9abb8c19 100644 --- a/ext/phar/tests/cache_list/frontcontroller32.phpt +++ b/ext/phar/tests/cache_list/frontcontroller32.phpt @@ -13,4 +13,4 @@ Content-type: text/html; charset=UTF-8 --FILE_EXTERNAL-- files/frontcontroller17.phar --EXPECTF-- -%ahar error: failed to call rewrite callback \ No newline at end of file +%ahar error: rewrite callback must return a string or false diff --git a/ext/phar/tests/files/frontcontroller17.phar b/ext/phar/tests/files/frontcontroller17.phar index b83d41fd5b..4dab78a9ec 100644 Binary files a/ext/phar/tests/files/frontcontroller17.phar and b/ext/phar/tests/files/frontcontroller17.phar differ diff --git a/ext/phar/tests/files/frontcontroller17.phar.inc b/ext/phar/tests/files/frontcontroller17.phar.inc index 85b8729f31..715479552a 100644 --- a/ext/phar/tests/files/frontcontroller17.phar.inc +++ b/ext/phar/tests/files/frontcontroller17.phar.inc @@ -6,7 +6,7 @@ echo "hi"; '; $a->setStub('getMessage() . "\n"); } diff --git a/ext/phar/tests/frontcontroller32.phpt b/ext/phar/tests/frontcontroller32.phpt index 58f6fffa00..032d0f571d 100644 --- a/ext/phar/tests/frontcontroller32.phpt +++ b/ext/phar/tests/frontcontroller32.phpt @@ -12,4 +12,4 @@ Content-type: text/html; charset=UTF-8 --FILE_EXTERNAL-- files/frontcontroller17.phar --EXPECTF-- -%ahar error: failed to call rewrite callback \ No newline at end of file +%ahar error: rewrite callback must return a string or false diff --git a/ext/reflection/tests/bug42976.phpt b/ext/reflection/tests/bug42976.phpt index 2e4ade2847..21aff8d4cc 100644 --- a/ext/reflection/tests/bug42976.phpt +++ b/ext/reflection/tests/bug42976.phpt @@ -27,12 +27,8 @@ echo "Done\n"; string(9) "x.changed" Warning: Parameter 1 to C::__construct() expected to be a reference, value given in %sbug42976.php on line 15 - -Warning: ReflectionClass::newInstance(): Invocation of C's constructor failed in %sbug42976.php on line 15 string(10) "x.original" Warning: Parameter 1 to C::__construct() expected to be a reference, value given in %sbug42976.php on line 18 - -Warning: ReflectionClass::newInstanceArgs(): Invocation of C's constructor failed in %sbug42976.php on line 18 string(10) "x.original" Done diff --git a/ext/standard/tests/general_functions/bug41970.phpt b/ext/standard/tests/general_functions/bug41970.phpt index 4bce3ac7f7..6f05137afc 100644 --- a/ext/standard/tests/general_functions/bug41970.phpt +++ b/ext/standard/tests/general_functions/bug41970.phpt @@ -14,13 +14,13 @@ echo "Done\n"; ?> --EXPECTF-- Warning: Parameter 1 to sort() expected to be a reference, value given in %sbug41970.php on line 5 -NULL +bool(true) Warning: strlen() expects parameter 1 to be string, array given in %sbug41970.php on line 6 NULL Warning: Parameter 1 to sort() expected to be a reference, value given in %sbug41970.php on line 7 -NULL +bool(true) Warning: strlen() expects parameter 1 to be string, array given in %sbug41970.php on line 8 NULL