summaryrefslogtreecommitdiff
path: root/Zend/zend_API.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r--Zend/zend_API.c256
1 files changed, 132 insertions, 124 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 358feff3c9..c9eaf1f96c 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -2305,21 +2305,69 @@ ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_
}
/* }}} */
-static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, zend_class_entry *ce_org, zval *callable, zend_class_entry **ce_ptr, zend_function **fptr_ptr, char **error TSRMLS_DC) /* {{{ */
+static int zend_is_callable_check_class(char *name, int name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
{
+ int ret = 0;
+ zend_class_entry **pce;
+ char *lcname = zend_str_tolower_dup(name, name_len);
+
+ if (name_len == sizeof("self") - 1 &&
+ !memcmp(lcname, "self", sizeof("self") - 1)) {
+ if (!EG(scope)) {
+ if (error) *error = estrdup("cannot access self:: when no class scope is active");
+ } else {
+ fcc->called_scope = EG(called_scope);
+ fcc->calling_scope = EG(scope);
+ ret = 1;
+ }
+ } else if (name_len == sizeof("parent") - 1 &&
+ !memcmp(lcname, "parent", sizeof("parent") - 1)) {
+ if (!EG(scope)) {
+ if (error) *error = estrdup("cannot access parent:: when no class scope is active");
+ } else if (!EG(scope)->parent) {
+ if (error) *error = estrdup("cannot access parent:: when current class scope has no parent");
+ } else {
+ fcc->called_scope = EG(called_scope);
+ fcc->calling_scope = EG(scope)->parent;
+ ret = 1;
+ }
+ } else if (name_len == sizeof("static") - 1 &&
+ !memcmp(lcname, "static", sizeof("static") - 1)) {
+ if (!EG(called_scope)) {
+ if (error) *error = estrdup("cannot access static:: when no class scope is active");
+ } else {
+ fcc->called_scope = EG(called_scope);
+ fcc->calling_scope = EG(called_scope);
+ ret = 1;
+ }
+ } else if (zend_lookup_class_ex(name, name_len, 1, &pce TSRMLS_CC) == SUCCESS) {
+ fcc->called_scope = fcc->calling_scope = *pce;
+ ret = 1;
+ } else {
+ if (error) zend_spprintf(error, 0, "class '%.*s' not found", name_len, name);
+ }
+ efree(lcname);
+ return ret;
+}
+/* }}} */
+
+
+static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
+{
+ zend_class_entry *ce_org = fcc->calling_scope;
int retval;
char *lmname, *colon;
int clen, mlen;
- zend_function *fptr;
zend_class_entry *last_scope;
HashTable *ftable;
+ int call_via_handler = 0;
if (error) {
*error = NULL;
}
- *ce_ptr = NULL;
- *fptr_ptr = NULL;
+ fcc->calling_scope = NULL;
+ fcc->function_handler = NULL;
if (!ce_org) {
/* Skip leading :: */
@@ -2334,8 +2382,7 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
}
/* Check if function with given name exists.
* This may be a compound name that includes namespace name */
- if (zend_hash_find(EG(function_table), lmname, mlen+1, (void**)&fptr) == SUCCESS) {
- *fptr_ptr = fptr;
+ if (zend_hash_find(EG(function_table), lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS) {
efree(lmname);
return 1;
}
@@ -2363,15 +2410,16 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
if (ce_org) {
EG(scope) = ce_org;
}
- *ce_ptr = zend_fetch_class(Z_STRVAL_P(callable), clen, ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_SILENT TSRMLS_CC);
- EG(scope) = last_scope;
- if (!*ce_ptr) {
- if (error) zend_spprintf(error, 0, "class '%.*Z' not found", clen, callable);
+
+ if (!zend_is_callable_check_class(Z_STRVAL_P(callable), clen, fcc, error TSRMLS_CC)) {
+ EG(scope) = last_scope;
return 0;
}
- ftable = &(*ce_ptr)->function_table;
- if (ce_org && !instanceof_function(ce_org, *ce_ptr TSRMLS_CC)) {
- if (error) zend_spprintf(error, 0, "class '%s' is not a subclass of '%s'", ce_org->name, (*ce_ptr)->name);
+ EG(scope) = last_scope;
+
+ ftable = &fcc->calling_scope->function_table;
+ if (ce_org && !instanceof_function(ce_org, fcc->calling_scope TSRMLS_CC)) {
+ if (error) zend_spprintf(error, 0, "class '%s' is not a subclass of '%s'", ce_org->name, fcc->calling_scope->name);
return 0;
}
lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen);
@@ -2380,49 +2428,51 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
mlen = Z_STRLEN_P(callable);
lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), Z_STRLEN_P(callable));
ftable = &ce_org->function_table;
- *ce_ptr = ce_org;
+ fcc->calling_scope = ce_org;
} else {
/* We already checked for plain function before. */
if (error) zend_spprintf(error, 0, "function '%s' not found or invalid function name", Z_STRVAL_P(callable));
return 0;
}
- retval = zend_hash_find(ftable, lmname, mlen+1, (void**)&fptr) == SUCCESS ? 1 : 0;
+ retval = zend_hash_find(ftable, lmname, mlen+1, (void**)&fcc->function_handler) == SUCCESS ? 1 : 0;
if (!retval) {
- if (*zobj_ptr_ptr && *ce_ptr && (*ce_ptr)->__call != 0) {
- retval = (*ce_ptr)->__call != NULL;
- *fptr_ptr = (*ce_ptr)->__call;
+ if (fcc->object_pp && fcc->calling_scope && fcc->calling_scope->__call != 0) {
+ retval = 1;
+ call_via_handler = 1;
+ fcc->function_handler = fcc->calling_scope->__call;
} else {
- if (!*zobj_ptr_ptr && *ce_ptr && ((*ce_ptr)->__callstatic || (*ce_ptr)->__call)) {
- if ((*ce_ptr)->__call &&
+ if (!fcc->object_pp && fcc->calling_scope && (fcc->calling_scope->__callstatic || fcc->calling_scope->__call)) {
+ if (fcc->calling_scope->__call &&
EG(This) &&
Z_OBJ_HT_P(EG(This))->get_class_entry &&
- instanceof_function(Z_OBJCE_P(EG(This)), *ce_ptr TSRMLS_CC)) {
+ instanceof_function(Z_OBJCE_P(EG(This)), fcc->calling_scope TSRMLS_CC)) {
retval = 1;
- *fptr_ptr = (*ce_ptr)->__call;
- *zobj_ptr_ptr = &EG(This);
- } else if ((*ce_ptr)->__callstatic) {
+ call_via_handler = 1;
+ fcc->function_handler = fcc->calling_scope->__call;
+ fcc->object_pp = &EG(This);
+ } else if (fcc->calling_scope->__callstatic) {
retval = 1;
- *fptr_ptr = (*ce_ptr)->__callstatic;
+ call_via_handler = 1;
+ fcc->function_handler = fcc->calling_scope->__callstatic;
}
}
if (retval == 0) {
- if (*ce_ptr) {
- if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", (*ce_ptr)->name, lmname);
+ if (fcc->calling_scope) {
+ if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", fcc->calling_scope->name, lmname);
} else {
if (error) zend_spprintf(error, 0, "function '%s' does not exist", lmname);
}
}
}
} else {
- *fptr_ptr = fptr;
- if (*ce_ptr) {
- if (!*zobj_ptr_ptr && !(fptr->common.fn_flags & ZEND_ACC_STATIC)) {
+ if (fcc->calling_scope) {
+ if (!fcc->object_pp && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
int severity;
char *verb;
- if (fptr->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+ if (fcc->function_handler->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
severity = E_STRICT;
verb = "should not";
} else {
@@ -2433,39 +2483,39 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) {
retval = 0;
}
- if (EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), *ce_ptr TSRMLS_CC)) {
- *zobj_ptr_ptr = &EG(This);
+ if (EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), fcc->calling_scope TSRMLS_CC)) {
+ fcc->object_pp = &EG(This);
if (error) {
- zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", (*ce_ptr)->name, fptr->common.function_name, verb, Z_OBJCE_P(EG(This))->name);
+ zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", fcc->calling_scope->name, fcc->function_handler->common.function_name, verb, Z_OBJCE_P(EG(This))->name);
} else if (retval) {
- zend_error(severity, "Non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", (*ce_ptr)->name, fptr->common.function_name, verb, Z_OBJCE_P(EG(This))->name);
+ zend_error(severity, "Non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", fcc->calling_scope->name, fcc->function_handler->common.function_name, verb, Z_OBJCE_P(EG(This))->name);
}
} else {
if (error) {
- zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically", (*ce_ptr)->name, fptr->common.function_name, verb);
+ zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically", fcc->calling_scope->name, fcc->function_handler->common.function_name, verb);
} else if (retval) {
- zend_error(severity, "Non-static method %s::%s() %s be called statically", (*ce_ptr)->name, fptr->common.function_name, verb);
+ zend_error(severity, "Non-static method %s::%s() %s be called statically", fcc->calling_scope->name, fcc->function_handler->common.function_name, verb);
}
}
}
if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
- if (fptr->op_array.fn_flags & ZEND_ACC_PRIVATE) {
- if (!zend_check_private(fptr, *zobj_ptr_ptr ? Z_OBJCE_PP(*zobj_ptr_ptr) : EG(scope), lmname, mlen TSRMLS_CC)) {
+ if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) {
+ if (!zend_check_private(fcc->function_handler, fcc->object_pp ? Z_OBJCE_PP(fcc->object_pp) : EG(scope), lmname, mlen TSRMLS_CC)) {
if (error) {
if (*error) {
efree(*error);
}
- zend_spprintf(error, 0, "cannot access private method %s::%s()", (*ce_ptr)->name, fptr->common.function_name);
+ zend_spprintf(error, 0, "cannot access private method %s::%s()", fcc->calling_scope->name, fcc->function_handler->common.function_name);
}
retval = 0;
}
- } else if ((fptr->common.fn_flags & ZEND_ACC_PROTECTED)) {
- if (!zend_check_protected(fptr->common.scope, EG(scope))) {
+ } else if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PROTECTED)) {
+ if (!zend_check_protected(fcc->function_handler->common.scope, EG(scope))) {
if (error) {
if (*error) {
efree(*error);
}
- zend_spprintf(error, 0, "cannot access protected method %s::%s()", (*ce_ptr)->name, fptr->common.function_name);
+ zend_spprintf(error, 0, "cannot access protected method %s::%s()", fcc->calling_scope->name, fcc->function_handler->common.function_name);
}
retval = 0;
}
@@ -2473,18 +2523,21 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze
}
}
}
+ if (fcc->object_pp) {
+ fcc->called_scope = Z_OBJCE_PP(fcc->object_pp);
+ }
efree(lmname);
+ if (retval && !call_via_handler) {
+ fcc->initialized = 1;
+ }
return retval;
}
/* }}} */
-ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr, char **error TSRMLS_DC) /* {{{ */
+ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_fcall_info_cache *fcc, char **error TSRMLS_DC) /* {{{ */
{
- char *lcname;
int callable_name_len_local;
- zend_class_entry *ce_local, **pce;
- zend_function *fptr_local;
- zval **zobj_ptr_local;
+ zend_fcall_info_cache fcc_local;
if (callable_name) {
*callable_name = NULL;
@@ -2492,21 +2545,19 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
if (callable_name_len == NULL) {
callable_name_len = &callable_name_len_local;
}
- if (ce_ptr == NULL) {
- ce_ptr = &ce_local;
- }
- if (fptr_ptr == NULL) {
- fptr_ptr = &fptr_local;
- }
- if (zobj_ptr_ptr == NULL) {
- zobj_ptr_ptr = &zobj_ptr_local;
+ if (fcc == NULL) {
+ fcc = &fcc_local;
}
if (error) {
*error = NULL;
}
- *ce_ptr = NULL;
- *fptr_ptr = NULL;
- *zobj_ptr_ptr = NULL;
+
+ fcc->initialized = 0;
+ fcc->calling_scope = NULL;
+ fcc->called_scope = NULL;
+ fcc->function_handler = NULL;
+ fcc->calling_scope = NULL;
+ fcc->object_pp = NULL;
switch (Z_TYPE_P(callable)) {
case IS_STRING:
@@ -2518,11 +2569,10 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
return 1;
}
- return zend_is_callable_check_func(check_flags, zobj_ptr_ptr, NULL, callable, ce_ptr, fptr_ptr, error TSRMLS_CC);
+ return zend_is_callable_check_func(check_flags, callable, fcc, error TSRMLS_CC);
case IS_ARRAY:
{
- zend_class_entry *ce = NULL;
zval **method = NULL;
zval **obj = NULL;
@@ -2552,51 +2602,34 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
return 1;
}
- lcname = zend_str_tolower_dup(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj));
-
- if (EG(active_op_array) &&
- Z_STRLEN_PP(obj) == sizeof("self") - 1 &&
- !memcmp(lcname, "self", sizeof("self") - 1)) {
- ce = EG(active_op_array)->scope;
- } else if (EG(active_op_array) && EG(active_op_array)->scope &&
- Z_STRLEN_PP(obj) == sizeof("parent") - 1 &&
- !memcmp(lcname, "parent", sizeof("parent") - 1)) {
- ce = EG(active_op_array)->scope->parent;
- } else if (Z_STRLEN_PP(obj) == sizeof("static") - 1 &&
- !memcmp(lcname, "static", sizeof("static") - 1)) {
- ce = EG(called_scope);
- } else if (zend_lookup_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), &pce TSRMLS_CC) == SUCCESS) {
- ce = *pce;
+ if (!zend_is_callable_check_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), fcc, error TSRMLS_CC)) {
+ return 0;
}
- efree(lcname);
+
} else {
- ce = Z_OBJCE_PP(obj); /* TBFixed: what if it's overloaded? */
+ fcc->calling_scope = Z_OBJCE_PP(obj); /* TBFixed: what if it's overloaded? */
- *zobj_ptr_ptr = obj;
+ fcc->object_pp = obj;
if (callable_name) {
char *ptr;
- *callable_name_len = ce->name_length + Z_STRLEN_PP(method) + sizeof("::") - 1;
+ *callable_name_len = fcc->calling_scope->name_length + Z_STRLEN_PP(method) + sizeof("::") - 1;
ptr = *callable_name = emalloc(*callable_name_len + 1);
- memcpy(ptr, ce->name, ce->name_length);
- ptr += ce->name_length;
+ memcpy(ptr, fcc->calling_scope->name, fcc->calling_scope->name_length);
+ ptr += fcc->calling_scope->name_length;
memcpy(ptr, "::", sizeof("::") - 1);
ptr += sizeof("::") - 1;
memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1);
}
if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
- *ce_ptr = ce;
+ fcc->called_scope = fcc->calling_scope;
return 1;
}
}
- if (ce) {
- return zend_is_callable_check_func(check_flags, zobj_ptr_ptr, ce, *method, ce_ptr, fptr_ptr, error TSRMLS_CC);
- } else {
- if (error) zend_spprintf(error, 0, "first array member is not a valid %s", Z_TYPE_PP(obj) == IS_STRING ? "class name" : "object");
- }
+ return zend_is_callable_check_func(check_flags, *method, fcc, error TSRMLS_CC);
} else {
if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
if (!obj || (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT)) {
@@ -2612,12 +2645,12 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
*callable_name_len = sizeof("Array") - 1;
}
}
- *ce_ptr = ce;
}
return 0;
case IS_OBJECT:
- if (zend_get_closure(callable, ce_ptr, fptr_ptr, NULL, zobj_ptr_ptr TSRMLS_CC) == SUCCESS) {
+ if (zend_get_closure(callable, &fcc->calling_scope, &fcc->function_handler, NULL, &fcc->object_pp TSRMLS_CC) == SUCCESS) {
+ fcc->called_scope = fcc->calling_scope;
if (callable_name) {
zend_class_entry *ce = Z_OBJCE_P(callable); /* TBFixed: what if it's overloaded? */
@@ -2650,22 +2683,20 @@ ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **cal
{
TSRMLS_FETCH();
- return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL, NULL, NULL TSRMLS_CC);
+ return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL TSRMLS_CC);
}
/* }}} */
ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRMLS_DC) /* {{{ */
{
- zend_class_entry *ce;
- zend_function *fptr;
- zval **zobj_ptr;
+ zend_fcall_info_cache fcc;
- if (zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, NULL, &ce, &fptr, &zobj_ptr, NULL TSRMLS_CC)) {
- if (Z_TYPE_P(callable) == IS_STRING && ce) {
+ if (zend_is_callable_ex(callable, IS_CALLABLE_STRICT, callable_name, NULL, &fcc, NULL TSRMLS_CC)) {
+ if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) {
zval_dtor(callable);
array_init(callable);
- add_next_index_string(callable, ce->name, 1);
- add_next_index_string(callable, fptr->common.function_name, 1);
+ add_next_index_string(callable, fcc.calling_scope->name, 1);
+ add_next_index_string(callable, fcc.function_handler->common.function_name, 1);
}
return 1;
}
@@ -2675,18 +2706,13 @@ ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRML
ZEND_API int zend_fcall_info_init(zval *callable, uint check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, char **callable_name, char **error TSRMLS_DC) /* {{{ */
{
- int len;
- zend_class_entry *ce;
- zend_function *func;
- zval **obj;
-
- if (!zend_is_callable_ex(callable, check_flags, callable_name, NULL, &ce, &func, &obj, error TSRMLS_CC)) {
+ if (!zend_is_callable_ex(callable, check_flags, callable_name, NULL, fcc, error TSRMLS_CC)) {
return FAILURE;
}
fci->size = sizeof(*fci);
- fci->function_table = ce ? &ce->function_table : EG(function_table);
- fci->object_pp = obj;
+ fci->function_table = fcc->calling_scope ? &fcc->calling_scope->function_table : EG(function_table);
+ fci->object_pp = fcc->object_pp;
fci->function_name = callable;
fci->retval_ptr_ptr = NULL;
fci->param_count = 0;
@@ -2694,24 +2720,6 @@ ZEND_API int zend_fcall_info_init(zval *callable, uint check_flags, zend_fcall_i
fci->no_separation = 1;
fci->symbol_table = NULL;
- if (ce) {
- len = strlen(func->common.function_name);
- if ((len == sizeof(ZEND_CALL_FUNC_NAME) - 1 && !zend_binary_strcasecmp(func->common.function_name, len, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME) - 1)) ||
- (len == sizeof(ZEND_CALLSTATIC_FUNC_NAME) - 1 && !zend_binary_strcasecmp(func->common.function_name, len, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME) - 1))
- ) {
- fcc->initialized = 0;
- fcc->function_handler = NULL;
- fcc->calling_scope = NULL;
- fcc->object_pp = NULL;
- return SUCCESS;
- }
- }
-
- fcc->initialized = 1;
- fcc->function_handler = func;
- fcc->calling_scope = ce;
- fcc->object_pp = obj;
-
return SUCCESS;
}
/* }}} */