]> granicus.if.org Git - php/commitdiff
fix bug #61782 - __clone/__destruct do not match other methods when checking access...
authorStanislav Malyshev <stas@php.net>
Sun, 13 May 2012 05:12:48 +0000 (22:12 -0700)
committerStanislav Malyshev <stas@php.net>
Sun, 13 May 2012 21:40:44 +0000 (14:40 -0700)
NEWS
Zend/tests/bug61782.phpt [new file with mode: 0644]
Zend/zend_object_handlers.c
Zend/zend_object_handlers.h
Zend/zend_objects.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index a4486c8cf55d43fee545f6b540062fb02d457830..01beab5bdd00e89d5e572f4a62a3bc5f7925724a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,8 @@ PHP                                                                        NEWS
     member of a null object). (Laruence)
   . Fixed bug #61978 (Object recursion not detected for classes that implement
     JsonSerializable). (Felipe)
+  . Fixed bug #61782 (__clone/__destruct do not match other methods when checking
+    access controls). (Stas)
   . Fixed bug #61730 (Segfault from array_walk modifying an array passed by
     reference). (Laruence)
   . Fixed bug #61922 (ZTS build doesn't accept zend.script_encoding config).
diff --git a/Zend/tests/bug61782.phpt b/Zend/tests/bug61782.phpt
new file mode 100644 (file)
index 0000000..95bf4e6
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+Bug #61782 (__clone/__destruct do not match other methods when checking access controls)
+--FILE--
+<?php
+ abstract class BaseClass {
+        abstract protected function __clone();
+    }
+
+    class MommasBoy extends BaseClass {
+        protected function __clone() {
+            echo __METHOD__, "\n";
+        }
+    }
+
+    class LatchkeyKid extends BaseClass {
+        public function __construct() {
+            echo 'In ', __CLASS__, ":\n";
+            $kid = new MommasBoy();
+            $kid = clone $kid;
+        }
+        public function __clone() {}
+    }
+
+    $obj = new LatchkeyKid();
+echo "DONE\n";
+--EXPECT--
+In LatchkeyKid:
+MommasBoy::__clone
+DONE
index ba6221ef70665ebb5da6f9370b3bc4f0c2152f1f..60095f7062b1c16edf8db02e12c03166ea2d9b2b 100644 (file)
@@ -66,11 +66,11 @@ ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */
                             zend_hash_get_current_data_ex(&ce->properties_info, (void**)&prop_info, &pos) == SUCCESS;
                             zend_hash_move_forward_ex(&ce->properties_info, &pos)) {
                                if (/*prop_info->ce == ce &&*/
-                                   (prop_info->flags & ZEND_ACC_STATIC) == 0 && 
+                                   (prop_info->flags & ZEND_ACC_STATIC) == 0 &&
                                    prop_info->offset >= 0 &&
                                    zobj->properties_table[prop_info->offset]) {
                                        zend_hash_quick_add(zobj->properties, prop_info->name, prop_info->name_length+1, prop_info->h, (void**)&zobj->properties_table[prop_info->offset], sizeof(zval*), (void**)&zobj->properties_table[prop_info->offset]);
-                               }                               
+                               }
                        }
                        while (ce->parent && ce->parent->default_properties_count) {
                                ce = ce->parent;
@@ -78,12 +78,12 @@ ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */
                                     zend_hash_get_current_data_ex(&ce->properties_info, (void**)&prop_info, &pos) == SUCCESS;
                                     zend_hash_move_forward_ex(&ce->properties_info, &pos)) {
                                        if (prop_info->ce == ce &&
-                                           (prop_info->flags & ZEND_ACC_STATIC) == 0 && 
-                                           (prop_info->flags & ZEND_ACC_PRIVATE) != 0 && 
+                                           (prop_info->flags & ZEND_ACC_STATIC) == 0 &&
+                                           (prop_info->flags & ZEND_ACC_PRIVATE) != 0 &&
                                            prop_info->offset >= 0 &&
                                                zobj->properties_table[prop_info->offset]) {
                                                zend_hash_quick_add(zobj->properties, prop_info->name, prop_info->name_length+1, prop_info->h, (void**)&zobj->properties_table[prop_info->offset], sizeof(zval*), (void**)&zobj->properties_table[prop_info->offset]);
-                                       }                               
+                                       }
                                }
                        }
                }
@@ -783,7 +783,7 @@ static void zend_std_unset_property(zval *object, zval *member, const zend_liter
        property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__unset != NULL), key TSRMLS_CC);
 
        if (EXPECTED(property_info != NULL) &&
-           EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && 
+           EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&
            !zobj->properties &&
            property_info->offset >= 0 &&
            EXPECTED(zobj->properties_table[property_info->offset] != NULL)) {
@@ -815,8 +815,8 @@ static void zend_std_unset_property(zval *object, zval *member, const zend_liter
                                }
                        }
                }
-       } else if (EXPECTED(property_info != NULL) && 
-                  EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && 
+       } else if (EXPECTED(property_info != NULL) &&
+                  EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&
                   property_info->offset >= 0) {
                zobj->properties_table[property_info->offset] = NULL;
        }
@@ -960,12 +960,6 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
 }
 /* }}} */
 
-static inline zend_class_entry * zend_get_function_root_class(zend_function *fbc) /* {{{ */
-{
-       return fbc->common.prototype ? fbc->common.prototype->common.scope : fbc->common.scope;
-}
-/* }}} */
-
 static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, const char *method_name, int method_len) /* {{{ */
 {
        zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
@@ -1143,7 +1137,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, const c
                zend_str_tolower_copy(lc_function_name, function_name_strval, function_name_strlen);
                hash_value = zend_hash_func(lc_function_name, function_name_strlen+1);
        }
-       
+
        if (function_name_strlen == ce->name_length && ce->constructor) {
                lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
                /* Only change the method to the constructor if the constructor isn't called __construct
@@ -1178,7 +1172,7 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, const c
        if (UNEXPECTED(!(fbc->common.fn_flags & ZEND_ACC_STATIC))) {
                zend_error_noreturn(E_ERROR, "Cannot call non static method %s::%s() without object", ZEND_FN_SCOPE_NAME(fbc), fbc->common.function_name);
        }
-#endif 
+#endif
        if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
                /* No further checks necessary, most common case */
        } else if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
@@ -1220,7 +1214,7 @@ ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, const char *p
 {
        zend_property_info *property_info;
        ulong hash_value;
-       
+
        if (UNEXPECTED(!key) ||
            (property_info = CACHED_POLYMORPHIC_PTR(key->cache_slot, ce)) == NULL) {
                if (EXPECTED(key != NULL)) {
index 32c0a674b318cd154f75f5846b9607b84a921901..d0d7a7b847a00aa0ae60d968e2210ccaf2a58301 100644 (file)
@@ -146,6 +146,9 @@ struct _zend_object_handlers {
 
 extern ZEND_API zend_object_handlers std_object_handlers;
 
+#define zend_get_function_root_class(fbc) \
+       ((fbc)->common.prototype ? (fbc)->common.prototype->common.scope : (fbc)->common.scope)
+
 BEGIN_EXTERN_C()
 ZEND_API union _zend_function *zend_std_get_static_method(zend_class_entry *ce, const char *function_name_strval, int function_name_strlen, const struct _zend_literal *key TSRMLS_DC);
 ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, const char *property_name, int property_name_len, zend_bool silent, const struct _zend_literal *key TSRMLS_DC);
index 7fadcf740b4e9208da6facb44c2d472dc75071ad..f7470fa578d114d2fe653f3d8f9791957982a5a8 100644 (file)
@@ -28,7 +28,7 @@
 
 ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce TSRMLS_DC)
 {
-       object->ce = ce;        
+       object->ce = ce;
        object->properties = NULL;
        object->properties_table = NULL;
        object->guards = NULL;
@@ -38,7 +38,7 @@ ZEND_API void zend_object_std_dtor(zend_object *object TSRMLS_DC)
 {
        if (object->guards) {
                zend_hash_destroy(object->guards);
-               FREE_HASHTABLE(object->guards);         
+               FREE_HASHTABLE(object->guards);
        }
        if (object->properties) {
                zend_hash_destroy(object->properties);
@@ -74,23 +74,23 @@ ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handl
                                if (object->ce != EG(scope)) {
                                        zend_class_entry *ce = object->ce;
 
-                                       zend_error(EG(in_execution) ? E_ERROR : E_WARNING, 
-                                               "Call to private %s::__destruct() from context '%s'%s", 
-                                               ce->name, 
-                                               EG(scope) ? EG(scope)->name : "", 
+                                       zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
+                                               "Call to private %s::__destruct() from context '%s'%s",
+                                               ce->name,
+                                               EG(scope) ? EG(scope)->name : "",
                                                EG(in_execution) ? "" : " during shutdown ignored");
                                        return;
                                }
                        } else {
                                /* Ensure that if we're calling a protected function, we're allowed to do so.
                                 */
-                               if (!zend_check_protected(destructor->common.scope, EG(scope))) {
+                               if (!zend_check_protected(zend_get_function_root_class(destructor), EG(scope))) {
                                        zend_class_entry *ce = object->ce;
 
-                                       zend_error(EG(in_execution) ? E_ERROR : E_WARNING, 
-                                               "Call to protected %s::__destruct() from context '%s'%s", 
-                                               ce->name, 
-                                               EG(scope) ? EG(scope)->name : "", 
+                                       zend_error(EG(in_execution) ? E_ERROR : E_WARNING,
+                                               "Call to protected %s::__destruct() from context '%s'%s",
+                                               ce->name,
+                                               EG(scope) ? EG(scope)->name : "",
                                                EG(in_execution) ? "" : " during shutdown ignored");
                                        return;
                                }
@@ -139,7 +139,7 @@ ZEND_API void zend_objects_free_object_storage(zend_object *object TSRMLS_DC)
 }
 
 ZEND_API zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type TSRMLS_DC)
-{      
+{
        zend_object_value retval;
 
        *object = emalloc(sizeof(zend_object));
@@ -222,7 +222,7 @@ ZEND_API zend_object_value zend_objects_clone_obj(zval *zobject TSRMLS_DC)
        zend_object *new_object;
        zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
 
-       /* assume that create isn't overwritten, so when clone depends on the 
+       /* assume that create isn't overwritten, so when clone depends on the
         * overwritten one then it must itself be overwritten */
        old_object = zend_objects_get_address(zobject TSRMLS_CC);
        new_obj_val = zend_objects_new(&new_object, old_object->ce TSRMLS_CC);
index 8cceb19d83affc3aeee221fecb4026dfc189dff3..5a3ae4954541d6b79661a91658c8664d487181e1 100644 (file)
@@ -2442,7 +2442,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
                                if (UNEXPECTED(EX(fbc) == NULL)) {
                                        zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
                                }
-                               
+
                                if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
                                        EX(object) = NULL;
                                } else {
@@ -2974,7 +2974,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV)
                catch_ce = CACHED_PTR(opline->op1.literal->cache_slot);
        } else {
                catch_ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC);
-               
+
                CACHE_PTR(opline->op1.literal->cache_slot, catch_ce);
        }
        ce = Z_OBJCE_P(EG(exception));
@@ -3426,7 +3426,7 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY)
                } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) {
                        /* Ensure that if we're calling a protected function, we're allowed to do so.
                         */
-                       if (UNEXPECTED(!zend_check_protected(clone->common.scope, EG(scope)))) {
+                       if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), EG(scope)))) {
                                zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : "");
                        }
                }
index 68ba74b44005d2aaf1e1b456cbdd10da65c2a899..1fb6e76cea42b66f381fa6384a4a57665d446727 100644 (file)
@@ -2436,7 +2436,7 @@ static int ZEND_FASTCALL  ZEND_CLONE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
                } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) {
                        /* Ensure that if we're calling a protected function, we're allowed to do so.
                         */
-                       if (UNEXPECTED(!zend_check_protected(clone->common.scope, EG(scope)))) {
+                       if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), EG(scope)))) {
                                zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : "");
                        }
                }
@@ -6850,7 +6850,7 @@ static int ZEND_FASTCALL  ZEND_CLONE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) {
                        /* Ensure that if we're calling a protected function, we're allowed to do so.
                         */
-                       if (UNEXPECTED(!zend_check_protected(clone->common.scope, EG(scope)))) {
+                       if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), EG(scope)))) {
                                zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : "");
                        }
                }
@@ -11278,7 +11278,7 @@ static int ZEND_FASTCALL  ZEND_CLONE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) {
                        /* Ensure that if we're calling a protected function, we're allowed to do so.
                         */
-                       if (UNEXPECTED(!zend_check_protected(clone->common.scope, EG(scope)))) {
+                       if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), EG(scope)))) {
                                zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : "");
                        }
                }
@@ -21475,7 +21475,7 @@ static int ZEND_FASTCALL  ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARG
                } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) {
                        /* Ensure that if we're calling a protected function, we're allowed to do so.
                         */
-                       if (UNEXPECTED(!zend_check_protected(clone->common.scope, EG(scope)))) {
+                       if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), EG(scope)))) {
                                zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : "");
                        }
                }
@@ -27222,7 +27222,7 @@ static int ZEND_FASTCALL  ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) {
                        /* Ensure that if we're calling a protected function, we're allowed to do so.
                         */
-                       if (UNEXPECTED(!zend_check_protected(clone->common.scope, EG(scope)))) {
+                       if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), EG(scope)))) {
                                zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : "");
                        }
                }