Fix get_class_vars() fast-path/slow-path discrepancies

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.
This commit is contained in:
Nikita Popov 2016-11-22 20:49:12 +01:00
parent c31396f85e
commit dd9ad0940a
3 changed files with 39 additions and 27 deletions

View 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();