Permalink
Browse files

Fix incorrect linkage of access-levels, when using private methods

  • Loading branch information...
1 parent da9eb59 commit 77208ec4d6ca4f662aa18a8af1483a189d7df096 @zsuraski zsuraski committed Jan 2, 2003
Showing with 38 additions and 15 deletions.
  1. +11 −4 Zend/zend_compile.c
  2. +5 −3 Zend/zend_compile.h
  3. +22 −8 Zend/zend_execute.c
View
@@ -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;
View
@@ -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 {
View
@@ -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.
*/

0 comments on commit 77208ec

Please sign in to comment.