Skip to content

Reduce memory usage when unserializing packed arrays of size 1 #7691

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions ext/standard/var_unserializer.re
Original file line number Diff line number Diff line change
Expand Up @@ -769,14 +769,22 @@ static inline int object_common(UNSERIALIZE_PARAMETER, zend_long elements, bool
return 0;
}

array_init_size(&ary, elements);
/* Avoid reallocation due to packed -> mixed conversion. */
zend_hash_real_init_mixed(Z_ARRVAL(ary));
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);
return 0;
if (elements > 0) {
/* Avoid reallocation due to packed -> mixed conversion.
* Note that an array must have at least 2 elements in order for the packed -> mixed conversion to change zval locations.
*/
array_init_size(&ary, elements);
if (elements > 1) {
zend_hash_real_init_mixed(Z_ARRVAL(ary));
}
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);
return 0;
}
} else {
ZVAL_EMPTY_ARRAY(&ary);
}

/* Delay __unserialize() call until end of serialization. We use two slots here to
Expand Down Expand Up @@ -1078,8 +1086,12 @@ use_double:
if (elements) {
array_init_size(rval, elements);
/* we can't convert from packed to hash during unserialization, because
reference to some zvals might be kept in var_hash (to support references) */
zend_hash_real_init_mixed(Z_ARRVAL_P(rval));
* references to some zvals might be kept in var_hash (to support references).
* This will only change zval addresses if there are at least 2 values
* (the value being referenced, and the value being added afterwards) */
if (elements > 1) {
zend_hash_real_init_mixed(Z_ARRVAL_P(rval));
}
} else {
ZVAL_EMPTY_ARRAY(rval);
return finish_nested_data(UNSERIALIZE_PASSTHRU);
Expand Down