]> granicus.if.org Git - php/commitdiff
Fix incorrect linkage of access-levels, when using private methods
authorZeev Suraski <zeev@php.net>
Thu, 2 Jan 2003 13:58:08 +0000 (13:58 +0000)
committerZeev Suraski <zeev@php.net>
Thu, 2 Jan 2003 13:58:08 +0000 (13:58 +0000)
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c

index 5a66f28f5fe83a490d64530ea4e63e667dfd7401..9b6c08f52f1d3a41dca172a2b96fe62e699f3217 100644 (file)
@@ -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;
index 7331128c0551e9f74b7c064a39c741de1dca1543..5a2bb4962e829cce471ebe23b281ee69a02ccc92 100644 (file)
@@ -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 {
index 2642f790e8ddb3f748809bcceac5e439d21cdda3..e5f10e5ffe1111d5500257fecbf5188661bfaacd 100644 (file)
@@ -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.
                         */