Permalink
Browse files

- Simplify and synch is_callable_ex() with actual execution code

  . Allow array($this, 'parent::method') for function 'pointers'
  . Spit out E_STRICT in case of erroneous use of function 'pointers'
  • Loading branch information...
1 parent 418223e commit 0cd997d79c1601e72047f8faea8614aaeaebc053 Marcus Boerger committed Dec 16, 2005
Showing with 134 additions and 66 deletions.
  1. +90 −58 Zend/zend_API.c
  2. +2 −0 Zend/zend_API.h
  3. +42 −8 Zend/zend_execute_API.c
View
148 Zend/zend_API.c
@@ -1974,15 +1974,94 @@ ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_
return 1;
}
-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 TSRMLS_DC)
+static int zend_is_callable_check_func(int check_flags, zval **zobj_ptr, zend_class_entry *ce_org, zval *callable, zend_class_entry **ce_ptr, zend_function **fptr_ptr TSRMLS_DC)
{
+ int retval;
char *lcname, *lmname, *colon;
+ int clen, mlen;
+ zend_function *fptr;
+ zend_class_entry **pce;
+ HashTable *ftable;
+
+ *ce_ptr = NULL;
+ *fptr_ptr = NULL;
+
+ if ((colon = strstr(Z_STRVAL_P(callable), "::")) != NULL) {
+ clen = colon - Z_STRVAL_P(callable);
+ mlen = Z_STRLEN_P(callable) - clen - 2;
+ if (zend_lookup_class(Z_STRVAL_P(callable), clen, &pce TSRMLS_CC) == SUCCESS) {
+ *ce_ptr = *pce;
+ } else {
+ lcname = zend_str_tolower_dup(Z_STRVAL_P(callable), clen);
+ /* caution: lcname is not '\0' terminated */
+ if (clen == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self") - 1) == 0) {
+ *ce_ptr = EG(scope);
+ } else if (clen == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent") - 1) == 0 && EG(active_op_array)->scope) {
+ *ce_ptr = EG(scope) ? EG(scope)->parent : NULL;
+ }
+ efree(lcname);
+ }
+ if (!*ce_ptr) {
+ return 0;
+ }
+ ftable = &(*ce_ptr)->function_table;
+ if (ce_org && !instanceof_function(ce_org, *ce_ptr TSRMLS_CC)) {
+ return 0;
+ }
+ lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen);
+ } else {
+ mlen = Z_STRLEN_P(callable);
+ lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen);
+ if (ce_org) {
+ ftable = &ce_org->function_table;
+ *ce_ptr = ce_org;
+ } else {
+ ftable = EG(function_table);
+ }
+ }
+
+ retval = zend_hash_find(ftable, lmname, mlen+1, (void**)&fptr) == SUCCESS ? 1 : 0;
+
+ if (!retval) {
+ if (zobj_ptr && *ce_ptr && (*ce_ptr)->__call != 0) {
+ retval = (*ce_ptr)->__call != NULL;
+ *fptr_ptr = (*ce_ptr)->__call;
+ }
+ } else {
+ *fptr_ptr = fptr;
+ if (*ce_ptr) {
+ if (!zobj_ptr && !(fptr->common.fn_flags & ZEND_ACC_STATIC)) {
+ if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) {
+ retval = 0;
+ } else {
+ zend_error(E_STRICT, "Non-static method %s::%s() cannot be called statically", (*ce_ptr)->name, fptr->common.function_name);
+ }
+ }
+ 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 ? Z_OBJCE_PP(zobj_ptr) : EG(scope), lmname, mlen TSRMLS_CC)) {
+ retval = 0;
+ }
+ } else if ((fptr->common.fn_flags & ZEND_ACC_PROTECTED)) {
+ if (!zend_check_protected(fptr->common.scope, EG(scope))) {
+ retval = 0;
+ }
+ }
+ }
+ }
+ }
+ efree(lmname);
+ 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 TSRMLS_DC)
+{
+ char *lcname;
zend_bool retval = 0;
- int callable_name_len_local, clen, mlen;
+ int callable_name_len_local;
zend_class_entry *ce_local, **pce;
zend_function *fptr_local;
zval **zobj_ptr_local;
- HashTable *ftable;
if (callable_name_len == NULL) {
callable_name_len = &callable_name_len_local;
@@ -2010,33 +2089,7 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
return 1;
}
- if ((colon = strstr(Z_STRVAL_P(callable), "::")) != NULL) {
- clen = colon - Z_STRVAL_P(callable);
- mlen = Z_STRLEN_P(callable) - clen - 2;
- lcname = estrndup(Z_STRVAL_P(callable), clen);
- lcname[clen] = '\0';
- lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen);
- if (zend_lookup_class(lcname, clen, &pce TSRMLS_CC) == FAILURE) {
- efree(lcname);
- efree(lmname);
- return 0;
- }
- efree(lcname);
- *ce_ptr = *pce;
- ftable = &(*ce_ptr)->function_table;
- } else {
- mlen = Z_STRLEN_P(callable);
- lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen);
- ftable = EG(function_table);
- }
-
- if (zend_hash_find(ftable, lmname, mlen+1, (void**)fptr_ptr) == SUCCESS) {
- retval = 1;
- }
- if (*ce_ptr && *fptr_ptr && !((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC)) {
- retval = 0;
- }
- efree(lmname);
+ retval = zend_is_callable_check_func(check_flags|IS_CALLABLE_CHECK_IS_STATIC, NULL, NULL, callable, ce_ptr, fptr_ptr TSRMLS_CC);
break;
case IS_ARRAY:
@@ -2065,7 +2118,6 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
}
if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
- *ce_ptr = ce;
return 1;
}
@@ -2080,6 +2132,12 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
}
efree(lcname);
}
+ if (EG(This)) {
+ if (instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
+ *zobj_ptr_ptr = &EG(This);
+ zend_error(E_STRICT, "Non-static method %s::%s() canot be called statically, assuming $this from compatible context %s", ce->name, Z_STRVAL_PP(method), Z_OBJCE_P(EG(This))->name);
+ }
+ }
} else {
ce = Z_OBJCE_PP(obj); /* TBFixed: what if it's overloaded? */
@@ -2104,38 +2162,12 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
}
if (ce) {
- zend_function *fbc;
-
- lcname = zend_str_tolower_dup(Z_STRVAL_PP(method), Z_STRLEN_PP(method));
- if (zend_hash_find(&ce->function_table, lcname, Z_STRLEN_PP(method)+1, (void **)&fbc) == SUCCESS) {
- retval = 1;
- if ((check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
- if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
- if (!zend_check_private(fbc, (Z_TYPE_PP(obj) == IS_STRING)?EG(scope):(*obj)->value.obj.handlers->get_class_entry(*obj TSRMLS_CC), lcname, Z_STRLEN_PP(method) TSRMLS_CC)) {
- retval = 0;
- }
- } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
- if (!zend_check_protected(fbc->common.scope, EG(scope))) {
- retval = 0;
- }
- }
- }
- *fptr_ptr = fbc;
- }
- /* check for __call too */
- if (retval == 0 && *zobj_ptr_ptr && ce->__call != 0) {
- retval = 1;
- *fptr_ptr = ce->__call;
- }
- efree(lcname);
+ retval = zend_is_callable_check_func(check_flags, *zobj_ptr_ptr, ce, *method, ce_ptr, fptr_ptr TSRMLS_CC);
}
} else if (callable_name) {
*callable_name = estrndup("Array", sizeof("Array")-1);
*callable_name_len = sizeof("Array") - 1;
}
- if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0 && !*zobj_ptr_ptr && (!*fptr_ptr || !((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC))) {
- retval = 0;
- }
*ce_ptr = ce;
}
break;
View
2 Zend/zend_API.h
@@ -204,6 +204,8 @@ ZEND_API void zend_wrong_param_count(TSRMLS_D);
#define IS_CALLABLE_CHECK_NO_ACCESS (1<<1)
#define IS_CALLABLE_CHECK_IS_STATIC (1<<2)
+#define IS_CALLABLE_STRICT (IS_CALLABLE_CHECK_IS_STATIC)
+
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 TSRMLS_DC);
ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name);
ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRMLS_DC);
View
50 Zend/zend_execute_API.c
@@ -587,6 +587,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
zval *method_name;
zval *params_array;
int call_via_handler = 0;
+ char *fname, *colon;
+ int fname_len;
if (EG(exception)) {
return FAILURE; /* we would result in an instable executor otherwise */
@@ -706,30 +708,62 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
return FAILURE;
}
+ fname = Z_STRVAL_P(fci->function_name);
+ fname_len = Z_STRLEN_P(fci->function_name);
+ if (calling_scope && (colon = strstr(fname, "::")) != NULL) {
+ int clen = colon - fname;
+ int mlen = fname_len - clen - 2;
+ zend_class_entry **pce, *ce_child;
+ if (zend_lookup_class(fname, clen, &pce TSRMLS_CC) == SUCCESS) {
+ ce_child = *pce;
+ } else {
+ char *lcname = zend_str_tolower_dup(fname, clen);
+ /* caution: lcname is not '\0' terminated */
+ if (clen == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self") - 1) == 0) {
+ ce_child = EG(active_op_array) ? EG(active_op_array)->scope : NULL;
+ } else if (clen == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent") - 1) == 0 && EG(active_op_array)->scope) {
+ ce_child = EG(active_op_array) && EG(active_op_array)->scope ? EG(scope)->parent : NULL;
+ }
+ efree(lcname);
+ }
+ if (!ce_child) {
+ zend_error(E_ERROR, "Cannot call method %s() or method does not exist", fname);
+ return FAILURE;
+ }
+ if (!instanceof_function(calling_scope, ce_child TSRMLS_CC)) {
+ zend_error(E_ERROR, "Cannot call method %s() of class %s which is not a derived from %s", fname, ce_child->name, calling_scope->name);
+ return 0;
+ }
+ fci->function_table = &ce_child->function_table;
+ calling_scope = ce_child;
+ fname = fname + clen + 2;
+ fname_len = mlen;
+ }
+
if (fci->object_pp) {
if (Z_OBJ_HT_PP(fci->object_pp)->get_method == NULL) {
zend_error(E_ERROR, "Object does not support method calls");
}
EX(function_state).function =
- Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name) TSRMLS_CC);
+ Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, fname, fname_len TSRMLS_CC);
if (EX(function_state).function && calling_scope != EX(function_state).function->common.scope) {
- char *function_name_lc = zend_str_tolower_dup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name));
- if (zend_hash_find(&calling_scope->function_table, function_name_lc, fci->function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
+ char *function_name_lc = zend_str_tolower_dup(fname, fname_len);
+ if (zend_hash_find(&calling_scope->function_table, function_name_lc, fname_len+1, (void **) &EX(function_state).function)==FAILURE) {
efree(function_name_lc);
- zend_error(E_ERROR, "Cannot call method %s::%s() or method does not exist", calling_scope->name, Z_STRVAL_P(fci->function_name));
+ zend_error(E_ERROR, "Cannot call method %s::%s() or method does not exist", calling_scope->name, fname);
}
efree(function_name_lc);
}
} else if (calling_scope) {
- char *function_name_lc = zend_str_tolower_dup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name));
+ char *function_name_lc = zend_str_tolower_dup(fname, fname_len);
EX(function_state).function =
- zend_std_get_static_method(calling_scope, function_name_lc, Z_STRLEN_P(fci->function_name) TSRMLS_CC);
+ zend_std_get_static_method(calling_scope, function_name_lc, fname_len TSRMLS_CC);
efree(function_name_lc);
} else {
- char *function_name_lc = zend_str_tolower_dup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name));
+ char *function_name_lc = zend_str_tolower_dup(fname, fname_len);
- if (zend_hash_find(fci->function_table, function_name_lc, fci->function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
+ if (zend_hash_find(fci->function_table, function_name_lc, fname_len+1, (void **) &EX(function_state).function)==FAILURE) {
EX(function_state).function = NULL;
}
efree(function_name_lc);

0 comments on commit 0cd997d

Please sign in to comment.