From: Zeev Suraski Date: Thu, 2 Jan 2003 13:58:08 +0000 (+0000) Subject: Fix incorrect linkage of access-levels, when using private methods X-Git-Tag: PHP_5_0_dev_before_13561_fix~530 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=77208ec4d6ca4f662aa18a8af1483a189d7df096;p=php Fix incorrect linkage of access-levels, when using private methods --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 5a66f28f5f..9b6c08f52f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1592,10 +1592,17 @@ static zend_bool do_inherit_method_check(zend_function *child, zend_function *pa zend_error(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child)); } - /* Prevent derived classes from restricting access that was available in parent classes - */ - if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) { - zend_error(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(child), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); + if (parent_flags & ZEND_ACC_CHANGED) { + child->common.fn_flags |= ZEND_ACC_CHANGED; + } else { + /* Prevent derived classes from restricting access that was available in parent classes + */ + if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) { + zend_error(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(child), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker"); + } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK)) + && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) { + child->common.fn_flags |= ZEND_ACC_CHANGED; + } } return 0; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 7331128c05..5a2bb4962e 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -92,11 +92,13 @@ typedef struct _zend_brk_cont_element { #define ZEND_ACC_ABSTRACT 0x02 /* The order of those must be kept - public < protected < private */ -#define ZEND_ACC_PUBLIC 0x10 -#define ZEND_ACC_PROTECTED 0x20 -#define ZEND_ACC_PRIVATE 0x40 +#define ZEND_ACC_PUBLIC 0x10 +#define ZEND_ACC_PROTECTED 0x20 +#define ZEND_ACC_PRIVATE 0x40 #define ZEND_ACC_PPP_MASK (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE) +#define ZEND_ACC_CHANGED 0x80 + char *zend_visibility_string(zend_uint fn_flags); struct _zend_op_array { diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 2642f790e8..e5f10e5ffe 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2228,19 +2228,23 @@ inline int zend_check_private(zend_execute_data *execute_data, zend_class_entry return 0; } - /* We may call a private function in one of two cases: - * 1. The scope of the function is the same as the class entry of our object - * 2. The class of our object is different, but a private function exists - * in one of the ancestor that corresponds to our object's ce. + /* We may call a private function if: + * 1. The class of our object is the same as the scope, and the private + * function (EX(fbc)) has the same scope. + * 2. One of our parent classes are the same as the scope, and it contains + * a private function with the same name that has the same scope. */ - if (EX(fbc)->common.scope == ce) { + if (EX(fbc)->common.scope == ce + && EG(scope) == ce) { /* rule #1 checks out ok, allow the function call */ return 1; } - orig_fbc = EX(fbc); /* Check rule #2 */ + orig_fbc = EX(fbc); + + ce = ce->parent; while (ce) { if (ce == EG(scope)) { if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &EX(fbc))==SUCCESS @@ -2296,7 +2300,7 @@ int zend_init_ctor_call_handler(ZEND_OPCODE_HANDLER_ARGS) EX(fbc) = EX(fbc_constructor); if (EX(fbc)->type == ZEND_USER_FUNCTION) { /* HACK!! */ if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) { - /* No further checks necessary, most common case */ + /* No further checks necessary */ } else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) { /* Ensure that if we're calling a private function, we're allowed to do so. */ @@ -2347,7 +2351,17 @@ int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS) } if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) { - /* No further checks necessary, most common case */ + /* Ensure that we haven't overridden a private function and end up calling + * the overriding public function... + */ + if (EX(fbc)->op_array.fn_flags & ZEND_ACC_CHANGED) { + zend_function *priv_fbc; + + if (zend_hash_find(&EG(scope)->function_table, function_name_strval, function_name_strlen+1, (void **) &priv_fbc)==SUCCESS + && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE) { + EX(fbc) = priv_fbc; + } + } } else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) { /* Ensure that if we're calling a private function, we're allowed to do so. */