summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/fr47160.phpt150
-rw-r--r--Zend/zend_vm_def.h61
-rw-r--r--Zend/zend_vm_execute.h244
3 files changed, 455 insertions, 0 deletions
diff --git a/Zend/tests/fr47160.phpt b/Zend/tests/fr47160.phpt
new file mode 100644
index 0000000000..809e1f1603
--- /dev/null
+++ b/Zend/tests/fr47160.phpt
@@ -0,0 +1,150 @@
+--TEST--
+Calling method from array
+--FILE--
+<?php
+
+class Hello {
+ public function world($x) {
+ echo "Hello, $x\n"; return $this;
+ }
+}
+
+class Hello2 {
+ static public function world($x) {
+ echo "Hello, $x\n";
+ }
+}
+
+class Magic {
+ public function __call($f, $a) {
+ printf("%s called (%s)!\n", __METHOD__, $f);
+ }
+}
+
+class Magic2 {
+ public static function __callStatic($f, $a) {
+ printf("%s called (%s)!\n", __METHOD__, $f);
+ }
+}
+
+class Magic3 {
+ public static function __callStatic($f, $a) {
+ printf("%s called (%s)!\n", __METHOD__, $f);
+ }
+ public function __call($f, $a) {
+ printf("%s called (%s)!\n", __METHOD__, $f);
+ }
+}
+
+$f = array('Hello','world');
+var_dump($f('you'));
+var_dump(call_user_func($f, 'you'));
+
+printf("-----\n");
+
+$h= new Hello;
+$f = array($h,'world');
+var_dump($f('again'));
+var_dump(call_user_func($f, 'again'));
+
+printf("-----\n");
+
+function bar() {
+ return array(new Hello,'world');
+}
+$f = bar();
+var_dump($f('there'));
+var_dump(call_user_func($f, 'there'));
+
+printf("-----\n");
+
+$x = function ($c,$v) { return array($c, $v); };
+
+$c = new Hello;
+$m = 'world';
+$f = $x($c, $m);
+var_dump($f('devs'));
+var_dump(call_user_func($f, 'devs'));
+
+printf("-----\n");
+
+$f = array(new Magic, 'foo');
+$f();
+call_user_func($f);
+
+printf("-----\n");
+
+$f = array('Magic2', 'foo');
+$f();
+call_user_func($f);
+
+
+printf("-----\n");
+
+$f = array('Magic3', 'foo');
+$f();
+call_user_func($f);
+
+printf("-----\n");
+
+$f = array(new Magic3, 'foo');
+$f();
+call_user_func($f);
+
+printf("-----\n");
+
+$f = array(new Hello2, 'world');
+var_dump($f('you'));
+var_dump(call_user_func($f, 'you'));
+
+?>
+--EXPECTF--
+Strict Standards: Non-static method Hello::world() should not be called statically in %s on line %d
+Hello, you
+
+Notice: Undefined variable: this in %s on line %d
+NULL
+
+Strict Standards: call_user_func() expects parameter 1 to be a valid callback, non-static method Hello::world() should not be called statically in %s on line %d
+Hello, you
+
+Notice: Undefined variable: this in %s on line %d
+NULL
+-----
+Hello, again
+object(Hello)#1 (0) {
+}
+Hello, again
+object(Hello)#1 (0) {
+}
+-----
+Hello, there
+object(Hello)#2 (0) {
+}
+Hello, there
+object(Hello)#2 (0) {
+}
+-----
+Hello, devs
+object(Hello)#4 (0) {
+}
+Hello, devs
+object(Hello)#4 (0) {
+}
+-----
+Magic::__call called (foo)!
+Magic::__call called (foo)!
+-----
+Magic2::__callStatic called (foo)!
+Magic2::__callStatic called (foo)!
+-----
+Magic3::__callStatic called (foo)!
+Magic3::__callStatic called (foo)!
+-----
+Magic3::__call called (foo)!
+Magic3::__call called (foo)!
+-----
+Hello, you
+NULL
+Hello, you
+NULL
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index c25b7a7a74..77d208ce53 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2382,6 +2382,67 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
+ } else if (OP2_TYPE != IS_CONST &&
+ EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
+ zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
+ zend_class_entry *ce;
+ zval **method = NULL;
+ zval **obj = NULL;
+
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj);
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method);
+
+ if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) {
+ zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object");
+ }
+
+ if (Z_TYPE_PP(method) != IS_STRING) {
+ zend_error_noreturn(E_ERROR, "Second array member is not a valid method");
+ }
+
+ if (Z_TYPE_PP(obj) == IS_STRING) {
+ ce = zend_fetch_class_by_name(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), NULL, 0 TSRMLS_CC);
+ if (UNEXPECTED(ce == NULL)) {
+ zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_PP(obj));
+ }
+ EX(called_scope) = ce;
+ EX(object) = NULL;
+
+ if (ce->get_static_method) {
+ EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
+ } else {
+ EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ }
+ } else {
+ EX(object) = *obj;
+ ce = EX(called_scope) = Z_OBJCE_PP(obj);
+
+ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
+ }
+
+ if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
+ EX(object) = NULL;
+ } else {
+ if (!PZVAL_IS_REF(EX(object))) {
+ Z_ADDREF_P(EX(object)); /* For $this pointer */
+ } else {
+ zval *this_ptr;
+ ALLOC_ZVAL(this_ptr);
+ INIT_PZVAL_COPY(this_ptr, EX(object));
+ zval_copy_ctor(this_ptr);
+ EX(object) = this_ptr;
+ }
+ }
+ }
+
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
+ }
+ FREE_OP2();
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
} else {
zend_error_noreturn(E_ERROR, "Function name must be a string");
}
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 63db4987d6..fd726eb880 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1246,6 +1246,67 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
+ } else if (IS_CONST != IS_CONST &&
+ EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
+ zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
+ zend_class_entry *ce;
+ zval **method = NULL;
+ zval **obj = NULL;
+
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj);
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method);
+
+ if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) {
+ zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object");
+ }
+
+ if (Z_TYPE_PP(method) != IS_STRING) {
+ zend_error_noreturn(E_ERROR, "Second array member is not a valid method");
+ }
+
+ if (Z_TYPE_PP(obj) == IS_STRING) {
+ ce = zend_fetch_class_by_name(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), NULL, 0 TSRMLS_CC);
+ if (UNEXPECTED(ce == NULL)) {
+ zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_PP(obj));
+ }
+ EX(called_scope) = ce;
+ EX(object) = NULL;
+
+ if (ce->get_static_method) {
+ EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
+ } else {
+ EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ }
+ } else {
+ EX(object) = *obj;
+ ce = EX(called_scope) = Z_OBJCE_PP(obj);
+
+ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
+ }
+
+ if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
+ EX(object) = NULL;
+ } else {
+ if (!PZVAL_IS_REF(EX(object))) {
+ Z_ADDREF_P(EX(object)); /* For $this pointer */
+ } else {
+ zval *this_ptr;
+ ALLOC_ZVAL(this_ptr);
+ INIT_PZVAL_COPY(this_ptr, EX(object));
+ zval_copy_ctor(this_ptr);
+ EX(object) = this_ptr;
+ }
+ }
+ }
+
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
+ }
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
} else {
zend_error_noreturn(E_ERROR, "Function name must be a string");
}
@@ -1486,6 +1547,67 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
+ } else if (IS_TMP_VAR != IS_CONST &&
+ EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
+ zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
+ zend_class_entry *ce;
+ zval **method = NULL;
+ zval **obj = NULL;
+
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj);
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method);
+
+ if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) {
+ zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object");
+ }
+
+ if (Z_TYPE_PP(method) != IS_STRING) {
+ zend_error_noreturn(E_ERROR, "Second array member is not a valid method");
+ }
+
+ if (Z_TYPE_PP(obj) == IS_STRING) {
+ ce = zend_fetch_class_by_name(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), NULL, 0 TSRMLS_CC);
+ if (UNEXPECTED(ce == NULL)) {
+ zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_PP(obj));
+ }
+ EX(called_scope) = ce;
+ EX(object) = NULL;
+
+ if (ce->get_static_method) {
+ EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
+ } else {
+ EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ }
+ } else {
+ EX(object) = *obj;
+ ce = EX(called_scope) = Z_OBJCE_PP(obj);
+
+ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
+ }
+
+ if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
+ EX(object) = NULL;
+ } else {
+ if (!PZVAL_IS_REF(EX(object))) {
+ Z_ADDREF_P(EX(object)); /* For $this pointer */
+ } else {
+ zval *this_ptr;
+ ALLOC_ZVAL(this_ptr);
+ INIT_PZVAL_COPY(this_ptr, EX(object));
+ zval_copy_ctor(this_ptr);
+ EX(object) = this_ptr;
+ }
+ }
+ }
+
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
+ }
+ zval_dtor(free_op2.var);
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
} else {
zend_error_noreturn(E_ERROR, "Function name must be a string");
}
@@ -1588,6 +1710,67 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
+ } else if (IS_VAR != IS_CONST &&
+ EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
+ zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
+ zend_class_entry *ce;
+ zval **method = NULL;
+ zval **obj = NULL;
+
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj);
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method);
+
+ if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) {
+ zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object");
+ }
+
+ if (Z_TYPE_PP(method) != IS_STRING) {
+ zend_error_noreturn(E_ERROR, "Second array member is not a valid method");
+ }
+
+ if (Z_TYPE_PP(obj) == IS_STRING) {
+ ce = zend_fetch_class_by_name(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), NULL, 0 TSRMLS_CC);
+ if (UNEXPECTED(ce == NULL)) {
+ zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_PP(obj));
+ }
+ EX(called_scope) = ce;
+ EX(object) = NULL;
+
+ if (ce->get_static_method) {
+ EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
+ } else {
+ EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ }
+ } else {
+ EX(object) = *obj;
+ ce = EX(called_scope) = Z_OBJCE_PP(obj);
+
+ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
+ }
+
+ if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
+ EX(object) = NULL;
+ } else {
+ if (!PZVAL_IS_REF(EX(object))) {
+ Z_ADDREF_P(EX(object)); /* For $this pointer */
+ } else {
+ zval *this_ptr;
+ ALLOC_ZVAL(this_ptr);
+ INIT_PZVAL_COPY(this_ptr, EX(object));
+ zval_copy_ctor(this_ptr);
+ EX(object) = this_ptr;
+ }
+ }
+ }
+
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
+ }
+ if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
} else {
zend_error_noreturn(E_ERROR, "Function name must be a string");
}
@@ -1723,6 +1906,67 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
+ } else if (IS_CV != IS_CONST &&
+ EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
+ zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) {
+ zend_class_entry *ce;
+ zval **method = NULL;
+ zval **obj = NULL;
+
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj);
+ zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method);
+
+ if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) {
+ zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object");
+ }
+
+ if (Z_TYPE_PP(method) != IS_STRING) {
+ zend_error_noreturn(E_ERROR, "Second array member is not a valid method");
+ }
+
+ if (Z_TYPE_PP(obj) == IS_STRING) {
+ ce = zend_fetch_class_by_name(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), NULL, 0 TSRMLS_CC);
+ if (UNEXPECTED(ce == NULL)) {
+ zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_PP(obj));
+ }
+ EX(called_scope) = ce;
+ EX(object) = NULL;
+
+ if (ce->get_static_method) {
+ EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
+ } else {
+ EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ }
+ } else {
+ EX(object) = *obj;
+ ce = EX(called_scope) = Z_OBJCE_PP(obj);
+
+ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
+ }
+
+ if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
+ EX(object) = NULL;
+ } else {
+ if (!PZVAL_IS_REF(EX(object))) {
+ Z_ADDREF_P(EX(object)); /* For $this pointer */
+ } else {
+ zval *this_ptr;
+ ALLOC_ZVAL(this_ptr);
+ INIT_PZVAL_COPY(this_ptr, EX(object));
+ zval_copy_ctor(this_ptr);
+ EX(object) = this_ptr;
+ }
+ }
+ }
+
+ if (UNEXPECTED(EX(fbc) == NULL)) {
+ zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
+ }
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
} else {
zend_error_noreturn(E_ERROR, "Function name must be a string");
}