Skip to content

Commit 93b8592

Browse files
committed
Merge branch 'PHP-7.1'
* PHP-7.1: call_user_func(_array): Don't abort on reference warning
2 parents f2dd856 + 906456c commit 93b8592

File tree

12 files changed

+81
-97
lines changed

12 files changed

+81
-97
lines changed

Zend/tests/call_user_func_008.phpt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
call_user_func() behavior with references
3+
--FILE--
4+
<?php
5+
6+
function test(&$ref1, &$ref2) {
7+
$ref1 += 42;
8+
$ref2 -= 42;
9+
return true;
10+
}
11+
12+
$i = $j = 0;
13+
var_dump(call_user_func('test', $i, $j));
14+
var_dump($i, $j);
15+
16+
var_dump(call_user_func_array('test', [$i, $j]));
17+
var_dump($i, $j);
18+
19+
$x =& $i; $y =& $j;
20+
var_dump(call_user_func('test', $i, $j));
21+
var_dump($i, $j);
22+
23+
var_dump(call_user_func_array('test', [$i, $j]));
24+
var_dump($i, $j);
25+
26+
?>
27+
--EXPECTF--
28+
Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d
29+
30+
Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d
31+
bool(true)
32+
int(0)
33+
int(0)
34+
35+
Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d
36+
37+
Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d
38+
bool(true)
39+
int(0)
40+
int(0)
41+
42+
Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d
43+
44+
Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d
45+
bool(true)
46+
int(0)
47+
int(0)
48+
49+
Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d
50+
51+
Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d
52+
bool(true)
53+
int(0)
54+
int(0)

Zend/zend_execute_API.c

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -788,41 +788,29 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
788788

789789
if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
790790
if (UNEXPECTED(!Z_ISREF_P(arg))) {
791-
if (fci->no_separation &&
792-
!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
793-
if (i) {
794-
/* hack to clean up the stack */
795-
ZEND_CALL_NUM_ARGS(call) = i;
796-
zend_vm_stack_free_args(call);
797-
}
798-
zend_vm_stack_free_call_frame(call);
799-
800-
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
801-
i+1,
791+
if (!fci->no_separation) {
792+
/* Separation is enabled -- create a ref */
793+
ZVAL_NEW_REF(arg, arg);
794+
} else if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
795+
/* By-value send is not allowed -- emit a warning,
796+
* but still perform the call with a by-value send. */
797+
zend_error(E_WARNING,
798+
"Parameter %d to %s%s%s() expected to be a reference, value given", i+1,
802799
func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
803800
func->common.scope ? "::" : "",
804801
ZSTR_VAL(func->common.function_name));
805-
if (EG(current_execute_data) == &dummy_execute_data) {
806-
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
807-
}
808-
return FAILURE;
809802
}
810-
811-
ZVAL_NEW_REF(arg, arg);
812803
}
813-
Z_ADDREF_P(arg);
814804
} else {
815805
if (Z_ISREF_P(arg) &&
816806
!(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
817807
/* don't separate references for __call */
818808
arg = Z_REFVAL_P(arg);
819809
}
820-
if (Z_OPT_REFCOUNTED_P(arg)) {
821-
Z_ADDREF_P(arg);
822-
}
823810
}
811+
824812
param = ZEND_CALL_ARG(call, i+1);
825-
ZVAL_COPY_VALUE(param, arg);
813+
ZVAL_COPY(param, arg);
826814
}
827815

828816
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {

Zend/zend_vm_def.h

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4626,23 +4626,15 @@ ZEND_VM_C_LABEL(send_array):
46264626
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
46274627
if (UNEXPECTED(!Z_ISREF_P(arg))) {
46284628
if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
4629-
4630-
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
4629+
/* By-value send is not allowed -- emit a warning,
4630+
* but still perform the call. */
4631+
zend_error(E_WARNING,
4632+
"Parameter %d to %s%s%s() expected to be a reference, value given",
46314633
arg_num,
46324634
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
46334635
EX(call)->func->common.scope ? "::" : "",
46344636
ZSTR_VAL(EX(call)->func->common.function_name));
46354637

4636-
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
4637-
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
4638-
}
4639-
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
4640-
OBJ_RELEASE(Z_OBJ(EX(call)->This));
4641-
}
4642-
EX(call)->func = (zend_function*)&zend_pass_function;
4643-
Z_OBJ(EX(call)->This) = NULL;
4644-
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
4645-
break;
46464638
}
46474639
}
46484640
} else {
@@ -4673,25 +4665,12 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, NUM)
46734665
param = ZEND_CALL_VAR(EX(call), opline->result.var);
46744666

46754667
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
4668+
ZVAL_DEREF(arg);
46764669
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
46774670
opline->op2.num,
46784671
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
46794672
EX(call)->func->common.scope ? "::" : "",
46804673
ZSTR_VAL(EX(call)->func->common.function_name));
4681-
4682-
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
4683-
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
4684-
}
4685-
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
4686-
OBJ_RELEASE(Z_OBJ(EX(call)->This));
4687-
}
4688-
ZVAL_UNDEF(param);
4689-
EX(call)->func = (zend_function*)&zend_pass_function;
4690-
Z_OBJ(EX(call)->This) = NULL;
4691-
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
4692-
4693-
FREE_OP1();
4694-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
46954674
} else {
46964675
if (Z_ISREF_P(arg) &&
46974676
!(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {

Zend/zend_vm_execute.h

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,23 +1423,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_O
14231423
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
14241424
if (UNEXPECTED(!Z_ISREF_P(arg))) {
14251425
if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
1426-
1427-
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
1426+
/* By-value send is not allowed -- emit a warning,
1427+
* but still perform the call. */
1428+
zend_error(E_WARNING,
1429+
"Parameter %d to %s%s%s() expected to be a reference, value given",
14281430
arg_num,
14291431
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
14301432
EX(call)->func->common.scope ? "::" : "",
14311433
ZSTR_VAL(EX(call)->func->common.function_name));
14321434

1433-
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
1434-
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
1435-
}
1436-
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
1437-
OBJ_RELEASE(Z_OBJ(EX(call)->This));
1438-
}
1439-
EX(call)->func = (zend_function*)&zend_pass_function;
1440-
Z_OBJ(EX(call)->This) = NULL;
1441-
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
1442-
break;
14431435
}
14441436
}
14451437
} else {
@@ -15890,25 +15882,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN
1589015882
param = ZEND_CALL_VAR(EX(call), opline->result.var);
1589115883

1589215884
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
15885+
ZVAL_DEREF(arg);
1589315886
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
1589415887
opline->op2.num,
1589515888
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
1589615889
EX(call)->func->common.scope ? "::" : "",
1589715890
ZSTR_VAL(EX(call)->func->common.function_name));
15898-
15899-
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
15900-
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
15901-
}
15902-
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
15903-
OBJ_RELEASE(Z_OBJ(EX(call)->This));
15904-
}
15905-
ZVAL_UNDEF(param);
15906-
EX(call)->func = (zend_function*)&zend_pass_function;
15907-
Z_OBJ(EX(call)->This) = NULL;
15908-
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
15909-
15910-
zval_ptr_dtor_nogc(free_op1);
15911-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
1591215891
} else {
1591315892
if (Z_ISREF_P(arg) &&
1591415893
!(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
@@ -34904,24 +34883,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND
3490434883
param = ZEND_CALL_VAR(EX(call), opline->result.var);
3490534884

3490634885
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
34886+
ZVAL_DEREF(arg);
3490734887
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
3490834888
opline->op2.num,
3490934889
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
3491034890
EX(call)->func->common.scope ? "::" : "",
3491134891
ZSTR_VAL(EX(call)->func->common.function_name));
34912-
34913-
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
34914-
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
34915-
}
34916-
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
34917-
OBJ_RELEASE(Z_OBJ(EX(call)->This));
34918-
}
34919-
ZVAL_UNDEF(param);
34920-
EX(call)->func = (zend_function*)&zend_pass_function;
34921-
Z_OBJ(EX(call)->This) = NULL;
34922-
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
34923-
34924-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
3492534892
} else {
3492634893
if (Z_ISREF_P(arg) &&
3492734894
!(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
Binary file not shown.

ext/phar/tests/cache_list/files/frontcontroller17.phar.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ echo "hi";
66
';
77
$a->setStub('<?php
88
try {
9-
Phar::webPhar("test.phar", "/index.php", null, array(), "sort");
9+
Phar::webPhar("test.phar", "/index.php", null, array(), function() { throw new Exception; });
1010
} catch (Exception $e) {
1111
die($e->getMessage() . "\n");
1212
}

ext/phar/tests/cache_list/frontcontroller32.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ Content-type: text/html; charset=UTF-8
1313
--FILE_EXTERNAL--
1414
files/frontcontroller17.phar
1515
--EXPECTF--
16-
%ahar error: failed to call rewrite callback
16+
%ahar error: rewrite callback must return a string or false
29 Bytes
Binary file not shown.

ext/phar/tests/files/frontcontroller17.phar.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ echo "hi";
66
';
77
$a->setStub('<?php
88
try {
9-
Phar::webPhar("test.phar", "/index.php", null, array(), "sort");
9+
Phar::webPhar("test.phar", "/index.php", null, array(), function() { throw new Exception; });
1010
} catch (Exception $e) {
1111
die($e->getMessage() . "\n");
1212
}

ext/phar/tests/frontcontroller32.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ Content-type: text/html; charset=UTF-8
1212
--FILE_EXTERNAL--
1313
files/frontcontroller17.phar
1414
--EXPECTF--
15-
%ahar error: failed to call rewrite callback
15+
%ahar error: rewrite callback must return a string or false

ext/reflection/tests/bug42976.phpt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,8 @@ echo "Done\n";
2727
string(9) "x.changed"
2828

2929
Warning: Parameter 1 to C::__construct() expected to be a reference, value given in %sbug42976.php on line 15
30-
31-
Warning: ReflectionClass::newInstance(): Invocation of C's constructor failed in %sbug42976.php on line 15
3230
string(10) "x.original"
3331

3432
Warning: Parameter 1 to C::__construct() expected to be a reference, value given in %sbug42976.php on line 18
35-
36-
Warning: ReflectionClass::newInstanceArgs(): Invocation of C's constructor failed in %sbug42976.php on line 18
3733
string(10) "x.original"
3834
Done

ext/standard/tests/general_functions/bug41970.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ echo "Done\n";
1414
?>
1515
--EXPECTF--
1616
Warning: Parameter 1 to sort() expected to be a reference, value given in %sbug41970.php on line 5
17-
NULL
17+
bool(true)
1818

1919
Warning: strlen() expects parameter 1 to be string, array given in %sbug41970.php on line 6
2020
NULL
2121

2222
Warning: Parameter 1 to sort() expected to be a reference, value given in %sbug41970.php on line 7
23-
NULL
23+
bool(true)
2424

2525
Warning: strlen() expects parameter 1 to be string, array given in %sbug41970.php on line 8
2626
NULL

0 commit comments

Comments
 (0)