]> granicus.if.org Git - php/commitdiff
Fix get_class_vars() fast-path/slow-path discrepancies
authorNikita Popov <nikic@php.net>
Tue, 22 Nov 2016 19:49:12 +0000 (20:49 +0100)
committerNikita Popov <nikic@php.net>
Tue, 22 Nov 2016 19:49:12 +0000 (20:49 +0100)
Normalize to the fast-path behavior. In particular, make sure that
the the property visibility check is correct for property names that
are formatted like mangled private properties (but are not). This is
done by only calling zend_check_property_access() for INDIRECT
properties.

Zend/zend_builtin_functions.c
ext/standard/tests/class_object/get_object_vars_variation_004.phpt [new file with mode: 0644]
ext/standard/tests/class_object/get_object_vars_variation_005.phpt [new file with mode: 0644]

index 51716a096ef581c21e94c88ab8035505e00050f0..1faf57cf3170cb7082c4456e5e1fd50e47b4d797 100644 (file)
@@ -1231,6 +1231,7 @@ ZEND_FUNCTION(get_object_vars)
        HashTable *properties;
        zend_string *key;
        zend_object *zobj;
+       zend_ulong num_key;
 
        ZEND_PARSE_PARAMETERS_START(1, 1)
                Z_PARAM_OBJECT(obj)
@@ -1257,33 +1258,44 @@ ZEND_FUNCTION(get_object_vars)
        } else {
                array_init_size(return_value, zend_hash_num_elements(properties));
 
-               ZEND_HASH_FOREACH_STR_KEY_VAL_IND(properties, key, value) {
-                       if (key) {
-                               if (zend_check_property_access(zobj, key) == SUCCESS) {
-                                       if (Z_ISREF_P(value) && Z_REFCOUNT_P(value) == 1) {
-                                               value = Z_REFVAL_P(value);
-                                       }
-                                       if (Z_REFCOUNTED_P(value)) {
-                                               Z_ADDREF_P(value);
-                                       }
-                                       if (ZSTR_VAL(key)[0] == 0) {
-                                               const char *prop_name, *class_name;
-                                               size_t prop_len;
-                                               zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_len);
-                                               /* We assume here that a mangled property name is never
-                                                * numeric. This is probably a safe assumption, but
-                                                * theoretically someone might write an extension with
-                                                * private, numeric properties. Well, too bad.
-                                                */
-                                               zend_hash_str_add_new(Z_ARRVAL_P(return_value), prop_name, prop_len, value);
-                                       } else {
-                                               zend_ulong num_key;
-                                               if (ZEND_HANDLE_NUMERIC(key, num_key)) {
-                                                       zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, value);
-                                               } else {
-                                                       zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
-                                               }
-                                       }
+               ZEND_HASH_FOREACH_KEY_VAL(properties, num_key, key, value) {
+                       zend_bool unmangle = 0;
+                       if (Z_TYPE_P(value) == IS_INDIRECT) {
+                               value = Z_INDIRECT_P(value);
+                               if (UNEXPECTED(Z_ISUNDEF_P(value))) {
+                                       continue;
+                               }
+
+                               ZEND_ASSERT(key);
+                               if (zend_check_property_access(zobj, key) == FAILURE) {
+                                       continue;
+                               }
+                               unmangle = 1;
+                       }
+
+                       if (Z_ISREF_P(value) && Z_REFCOUNT_P(value) == 1) {
+                               value = Z_REFVAL_P(value);
+                       }
+                       Z_TRY_ADDREF_P(value);
+
+                       if (UNEXPECTED(!key)) {
+                               /* This case is only possible due to loopholes, e.g. ArrayObject */
+                               zend_hash_index_add(Z_ARRVAL_P(return_value), num_key, value);
+                       } else if (unmangle && ZSTR_VAL(key)[0] == 0) {
+                               const char *prop_name, *class_name;
+                               size_t prop_len;
+                               zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_len);
+                               /* We assume here that a mangled property name is never
+                                * numeric. This is probably a safe assumption, but
+                                * theoretically someone might write an extension with
+                                * private, numeric properties. Well, too bad.
+                                */
+                               zend_hash_str_add_new(Z_ARRVAL_P(return_value), prop_name, prop_len, value);
+                       } else {
+                               if (ZEND_HANDLE_NUMERIC(key, num_key)) {
+                                       zend_hash_index_add(Z_ARRVAL_P(return_value), num_key, value);
+                               } else {
+                                       zend_hash_add_new(Z_ARRVAL_P(return_value), key, value);
                                }
                        }
                } ZEND_HASH_FOREACH_END();
diff --git a/ext/standard/tests/class_object/get_object_vars_variation_004.phpt b/ext/standard/tests/class_object/get_object_vars_variation_004.phpt
new file mode 100644 (file)
index 0000000..0d86bf9
Binary files /dev/null and b/ext/standard/tests/class_object/get_object_vars_variation_004.phpt differ
diff --git a/ext/standard/tests/class_object/get_object_vars_variation_005.phpt b/ext/standard/tests/class_object/get_object_vars_variation_005.phpt
new file mode 100644 (file)
index 0000000..d33ef48
Binary files /dev/null and b/ext/standard/tests/class_object/get_object_vars_variation_005.phpt differ