]> granicus.if.org Git - php/commitdiff
Make call_user_func() on reference args consistent
authorNikita Popov <nikic@php.net>
Tue, 28 Jun 2016 18:43:38 +0000 (20:43 +0200)
committerNikita Popov <nikic@php.net>
Tue, 28 Jun 2016 18:43:38 +0000 (20:43 +0200)
Previously reference arguments were allowed if call_user_func()
was compiled to SEND_USER and not otherwise. Make it consistent
by always forbidding them.

Zend/tests/call_user_func_006.phpt [new file with mode: 0644]
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/call_user_func_006.phpt b/Zend/tests/call_user_func_006.phpt
new file mode 100644 (file)
index 0000000..16a59bc
--- /dev/null
@@ -0,0 +1,28 @@
+--TEST--
+call_user_func() should error on reference arguments
+--FILE--
+<?php
+
+namespace Foo;
+
+function bar(&$ref) {
+    $ref = 24;
+}
+
+$x = 42;
+$ref =& $x;
+\call_user_func('Foo\bar', $x);
+var_dump($x);
+
+$y = 42;
+$ref =& $y;
+call_user_func('Foo\bar', $y);
+var_dump($y);
+
+?>
+--EXPECTF--
+Warning: Parameter 1 to Foo\bar() expected to be a reference, value given in %s on line %d
+int(42)
+
+Warning: Parameter 1 to Foo\bar() expected to be a reference, value given in %s on line %d
+int(42)
index ce7c6faea246d88fa5572a7c7de34a892d45e255..83e74bc8ac127e05b82a4244270086dc543843bd 100644 (file)
@@ -4654,32 +4654,27 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, ANY)
        arg = GET_OP1_ZVAL_PTR(BP_VAR_R);
        param = ZEND_CALL_VAR(EX(call), opline->result.var);
 
-       if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
-               if (UNEXPECTED(!Z_ISREF_P(arg))) {
-                       if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+       if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
+               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));
 
-                               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_OBJ(EX(call)->This)) {
-                                       OBJ_RELEASE(Z_OBJ(EX(call)->This));
-                               }
-                               ZVAL_UNDEF(param);
-                               EX(call)->func = (zend_function*)&zend_pass_function;
-                               EX(call)->called_scope = NULL;
-                               Z_OBJ(EX(call)->This) = NULL;
-                               ZEND_SET_CALL_INFO(EX(call), ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
-
-                               FREE_OP1();
-                               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
-                       }
+               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
+                       OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                }
+               if (Z_OBJ(EX(call)->This)) {
+                       OBJ_RELEASE(Z_OBJ(EX(call)->This));
+               }
+               ZVAL_UNDEF(param);
+               EX(call)->func = (zend_function*)&zend_pass_function;
+               EX(call)->called_scope = NULL;
+               Z_OBJ(EX(call)->This) = NULL;
+               ZEND_SET_CALL_INFO(EX(call), 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)) {
index aba8081585b1f7b41d088c08924f671088dbe014..174c6de1c1445e6f8cb8cecc69cb99f1a89dd705 100644 (file)
@@ -15358,32 +15358,27 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN
        arg = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
        param = ZEND_CALL_VAR(EX(call), opline->result.var);
 
-       if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
-               if (UNEXPECTED(!Z_ISREF_P(arg))) {
-                       if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
+       if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
+               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));
 
-                               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_OBJ(EX(call)->This)) {
-                                       OBJ_RELEASE(Z_OBJ(EX(call)->This));
-                               }
-                               ZVAL_UNDEF(param);
-                               EX(call)->func = (zend_function*)&zend_pass_function;
-                               EX(call)->called_scope = NULL;
-                               Z_OBJ(EX(call)->This) = NULL;
-                               ZEND_SET_CALL_INFO(EX(call), ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
-
-                               zval_ptr_dtor_nogc(free_op1);
-                               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
-                       }
+               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
+                       OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                }
+               if (Z_OBJ(EX(call)->This)) {
+                       OBJ_RELEASE(Z_OBJ(EX(call)->This));
+               }
+               ZVAL_UNDEF(param);
+               EX(call)->func = (zend_function*)&zend_pass_function;
+               EX(call)->called_scope = NULL;
+               Z_OBJ(EX(call)->This) = NULL;
+               ZEND_SET_CALL_INFO(EX(call), 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)) {
@@ -28980,31 +28975,26 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND
        arg = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
        param = ZEND_CALL_VAR(EX(call), opline->result.var);
 
-       if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
-               if (UNEXPECTED(!Z_ISREF_P(arg))) {
-                       if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) {
-
-                               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_OBJ(EX(call)->This)) {
-                                       OBJ_RELEASE(Z_OBJ(EX(call)->This));
-                               }
-                               ZVAL_UNDEF(param);
-                               EX(call)->func = (zend_function*)&zend_pass_function;
-                               EX(call)->called_scope = NULL;
-                               Z_OBJ(EX(call)->This) = NULL;
-                               ZEND_SET_CALL_INFO(EX(call), ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
+       if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
+               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));
 
-                               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
-                       }
+               if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
+                       OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
                }
+               if (Z_OBJ(EX(call)->This)) {
+                       OBJ_RELEASE(Z_OBJ(EX(call)->This));
+               }
+               ZVAL_UNDEF(param);
+               EX(call)->func = (zend_function*)&zend_pass_function;
+               EX(call)->called_scope = NULL;
+               Z_OBJ(EX(call)->This) = NULL;
+               ZEND_SET_CALL_INFO(EX(call), 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)) {