static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key);
-static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)
+static zend_always_inline int process_nested_array_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements)
{
if (var_hash) {
if ((*var_hash)->max_depth > 0 && (*var_hash)->cur_depth >= (*var_hash)->max_depth) {
while (elements-- > 0) {
zval key, *data, d, *old_data;
zend_ulong idx;
- zend_property_info *info = NULL;
ZVAL_UNDEF(&key);
data = NULL;
ZVAL_UNDEF(&d);
- if (!obj) {
- if (Z_TYPE(key) == IS_LONG) {
- idx = Z_LVAL(key);
+ if (Z_TYPE(key) == IS_LONG) {
+ idx = Z_LVAL(key);
numeric_key:
- if (UNEXPECTED((old_data = zend_hash_index_find(ht, idx)) != NULL)) {
- //??? update hash
- var_push_dtor(var_hash, old_data);
- data = zend_hash_index_update(ht, idx, &d);
- } else {
- data = zend_hash_index_add_new(ht, idx, &d);
- }
- } else if (Z_TYPE(key) == IS_STRING) {
- if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) {
- goto numeric_key;
- }
- if (UNEXPECTED((old_data = zend_hash_find(ht, Z_STR(key))) != NULL)) {
- //??? update hash
- var_push_dtor(var_hash, old_data);
- data = zend_hash_update(ht, Z_STR(key), &d);
- } else {
- data = zend_hash_add_new(ht, Z_STR(key), &d);
- }
+ if (UNEXPECTED((old_data = zend_hash_index_find(ht, idx)) != NULL)) {
+ //??? update hash
+ var_push_dtor(var_hash, old_data);
+ data = zend_hash_index_update(ht, idx, &d);
} else {
- zval_ptr_dtor(&key);
- goto failure;
+ data = zend_hash_index_add_new(ht, idx, &d);
+ }
+ } else if (Z_TYPE(key) == IS_STRING) {
+ if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) {
+ goto numeric_key;
+ }
+ if (UNEXPECTED((old_data = zend_hash_find(ht, Z_STR(key))) != NULL)) {
+ //??? update hash
+ var_push_dtor(var_hash, old_data);
+ data = zend_hash_update(ht, Z_STR(key), &d);
+ } else {
+ data = zend_hash_add_new(ht, Z_STR(key), &d);
+ }
+ } else {
+ zval_ptr_dtor(&key);
+ goto failure;
+ }
+
+ if (!php_var_unserialize_internal(data, p, max, var_hash, 0)) {
+ zval_ptr_dtor(&key);
+ goto failure;
+ }
+
+ if (BG(unserialize).level > 1) {
+ var_push_dtor(var_hash, data);
+ }
+ zval_ptr_dtor_str(&key);
+
+ if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
+ (*p)--;
+ goto failure;
+ }
+ }
+
+ if (var_hash) {
+ (*var_hash)->cur_depth--;
+ }
+ return 1;
+
+failure:
+ if (var_hash) {
+ (*var_hash)->cur_depth--;
+ }
+ return 0;
+}
+
+static int is_property_visibility_changed(zend_class_entry *ce, zval *key)
+{
+ if (zend_hash_num_elements(&ce->properties_info) > 0) {
+ zend_property_info *existing_propinfo;
+ const char *unmangled_class = NULL;
+ const char *unmangled_prop;
+ size_t unmangled_prop_len;
+
+ if (UNEXPECTED(zend_unmangle_property_name_ex(Z_STR_P(key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) {
+ zval_ptr_dtor_str(key);
+ return -1;
+ }
+
+ if (unmangled_class == NULL) {
+ existing_propinfo = zend_hash_find_ptr(&ce->properties_info, Z_STR_P(key));
+ if (existing_propinfo != NULL) {
+ zval_ptr_dtor_str(key);
+ ZVAL_STR_COPY(key, existing_propinfo->name);
+ return 1;
}
} else {
- if (EXPECTED(Z_TYPE(key) == IS_STRING)) {
+ if (!strcmp(unmangled_class, "*")
+ || !strcasecmp(unmangled_class, ZSTR_VAL(ce->name))) {
+ zend_string *unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0);
+
+ existing_propinfo = zend_hash_find_ptr(&ce->properties_info, unmangled);
+ if (existing_propinfo != NULL) {
+ zend_string_release_ex(unmangled, 0);
+ zval_ptr_dtor_str(key);
+ ZVAL_STR_COPY(key, existing_propinfo->name);
+ return 1;
+ } else {
+ zval_ptr_dtor_str(key);
+ ZVAL_STR(key, unmangled);
+ return 0;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+static zend_always_inline int process_nested_object_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)
+{
+ if (var_hash) {
+ if ((*var_hash)->max_depth > 0 && (*var_hash)->cur_depth >= (*var_hash)->max_depth) {
+ php_error_docref(NULL, E_WARNING,
+ "Maximum depth of " ZEND_LONG_FMT " exceeded. "
+ "The depth limit can be changed using the max_depth unserialize() option "
+ "or the unserialize_max_depth ini setting",
+ (*var_hash)->max_depth);
+ return 0;
+ }
+ (*var_hash)->cur_depth++;
+ }
+
+ while (elements-- > 0) {
+ zval key, *data, d, *old_data;
+ zend_property_info *info = NULL;
+
+ ZVAL_UNDEF(&key);
+
+ if (!php_var_unserialize_internal(&key, p, max, NULL, 1)) {
+ zval_ptr_dtor(&key);
+ goto failure;
+ }
+
+ data = NULL;
+ ZVAL_UNDEF(&d);
+
+ if (EXPECTED(Z_TYPE(key) == IS_STRING)) {
string_key:
- if (obj && zend_hash_num_elements(&obj->ce->properties_info) > 0) {
- zend_property_info *existing_propinfo;
- zend_string *new_key;
- const char *unmangled_class = NULL;
- const char *unmangled_prop;
- size_t unmangled_prop_len;
- zend_string *unmangled;
-
- if (UNEXPECTED(zend_unmangle_property_name_ex(Z_STR(key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) {
- zval_ptr_dtor(&key);
- goto failure;
- }
+ if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) {
+ if (Z_TYPE_P(old_data) == IS_INDIRECT) {
+declared_property:
+ /* This is a property with a declaration */
+ old_data = Z_INDIRECT_P(old_data);
+ info = zend_get_typed_property_info_for_slot(obj, old_data);
+ if (info) {
+ if (Z_ISREF_P(old_data)) {
+ /* If the value is overwritten, remove old type source from ref. */
+ ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(old_data), info);
+ }
- unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0);
-
- existing_propinfo = zend_hash_find_ptr(&obj->ce->properties_info, unmangled);
- if ((unmangled_class == NULL || !strcmp(unmangled_class, "*") || !strcasecmp(unmangled_class, ZSTR_VAL(obj->ce->name)))
- && (existing_propinfo != NULL)
- && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) {
- if (existing_propinfo->flags & ZEND_ACC_PROTECTED) {
- new_key = zend_mangle_property_name(
- "*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), 0);
- zend_string_release_ex(unmangled, 0);
- } else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) {
- if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) {
- new_key = zend_mangle_property_name(
- unmangled_class, strlen(unmangled_class),
- ZSTR_VAL(unmangled), ZSTR_LEN(unmangled),
- 0);
- } else {
- new_key = zend_mangle_property_name(
- ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name),
- ZSTR_VAL(unmangled), ZSTR_LEN(unmangled),
- 0);
- }
- zend_string_release_ex(unmangled, 0);
- } else {
- ZEND_ASSERT(existing_propinfo->flags & ZEND_ACC_PUBLIC);
- new_key = unmangled;
+ if ((*var_hash)->ref_props) {
+ /* Remove old entry from ref_props table, if it exists. */
+ zend_hash_index_del(
+ (*var_hash)->ref_props, (zend_uintptr_t) old_data);
}
- zval_ptr_dtor_str(&key);
- ZVAL_STR(&key, new_key);
+ }
+ var_push_dtor(var_hash, old_data);
+ Z_TRY_DELREF_P(old_data);
+ ZVAL_NULL(old_data);
+ data = old_data;
+ } else {
+ int ret = is_property_visibility_changed(obj->ce, &key);
+
+ if (EXPECTED(!ret)) {
+ var_push_dtor(var_hash, old_data);
+ data = zend_hash_update(ht, Z_STR(key), &d);
+ } else if (ret < 0) {
+ goto failure;
} else {
- zend_string_release_ex(unmangled, 0);
+ goto second_try;
}
}
+ } else {
+ int ret = is_property_visibility_changed(obj->ce, &key);
- if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) {
- if (Z_TYPE_P(old_data) == IS_INDIRECT) {
- /* This is a property with a declaration */
- old_data = Z_INDIRECT_P(old_data);
- info = zend_get_typed_property_info_for_slot(obj, old_data);
- if (info) {
- if (Z_ISREF_P(old_data)) {
- /* If the value is overwritten, remove old type source from ref. */
- ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(old_data), info);
- }
-
- if ((*var_hash)->ref_props) {
- /* Remove old entry from ref_props table, if it exists. */
- zend_hash_index_del(
- (*var_hash)->ref_props, (zend_uintptr_t) old_data);
- }
+ if (EXPECTED(!ret)) {
+ data = zend_hash_add_new(ht, Z_STR(key), &d);
+ } else if (ret < 0) {
+ goto failure;
+ } else {
+second_try:
+ if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) {
+ if (Z_TYPE_P(old_data) == IS_INDIRECT) {
+ goto declared_property;
+ } else {
+ var_push_dtor(var_hash, old_data);
+ data = zend_hash_update(ht, Z_STR(key), &d);
}
- var_push_dtor(var_hash, old_data);
- Z_TRY_DELREF_P(old_data);
- ZVAL_COPY_VALUE(old_data, &d);
- data = old_data;
} else {
- var_push_dtor(var_hash, old_data);
- data = zend_hash_update_ind(ht, Z_STR(key), &d);
+ data = zend_hash_add_new(ht, Z_STR(key), &d);
}
- } else {
- data = zend_hash_add_new(ht, Z_STR(key), &d);
}
- } else if (Z_TYPE(key) == IS_LONG) {
- /* object properties should include no integers */
- convert_to_string(&key);
- goto string_key;
- } else {
- zval_ptr_dtor(&key);
- goto failure;
}
+ zval_ptr_dtor_str(&key);
+ } else if (Z_TYPE(key) == IS_LONG) {
+ /* object properties should include no integers */
+ convert_to_string(&key);
+ goto string_key;
+ } else {
+ zval_ptr_dtor(&key);
+ goto failure;
}
if (!php_var_unserialize_internal(data, p, max, var_hash, 0)) {
* The data is still stored in the property. */
ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info);
}
- zval_ptr_dtor(&key);
goto failure;
}
if (!zend_verify_prop_assignable_by_ref(info, data, /* strict */ 1)) {
zval_ptr_dtor(data);
ZVAL_UNDEF(data);
- zval_ptr_dtor_nogc(&key);
goto failure;
}
if (BG(unserialize).level > 1) {
var_push_dtor(var_hash, data);
}
- zval_ptr_dtor_str(&key);
if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
(*p)--;
array_init_size(&ary, elements);
/* Avoid reallocation due to packed -> mixed conversion. */
zend_hash_real_init_mixed(Z_ARRVAL(ary));
- if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL(ary), elements, NULL)) {
+ if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL(ary), elements)) {
ZVAL_DEREF(rval);
GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
zval_ptr_dtor(&ary);
}
zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, HT_FLAGS(ht) & HASH_FLAG_PACKED);
- if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P(rval))) {
+ if (!process_nested_object_data(UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P(rval))) {
if (has_wakeup) {
ZVAL_DEREF(rval);
GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
* prohibit "r:" references to non-objects, as we only generate them for objects. */
HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(rval));
- if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, NULL)) {
+ if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements)) {
return 0;
}