Skip to content

Commit fba4391

Browse files
committed
Fix bug #81163 __sleep allowed to return non-array
1 parent a30fab5 commit fba4391

File tree

2 files changed

+40
-16
lines changed

2 files changed

+40
-16
lines changed
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Test __sleep returns non-array
3+
--FILE--
4+
<?php
5+
class foo
6+
{
7+
private $private = 'private';
8+
}
9+
10+
class bar extends foo
11+
{
12+
public function __sleep()
13+
{
14+
return (new bar());
15+
}
16+
}
17+
18+
serialize(new bar());
19+
?>
20+
--EXPECTF--
21+
Warning: serialize(): bar::__sleep() should return an array only containing the names of instance-variables to serialize in %s on line %d

ext/standard/var.c

+19-16
Original file line numberDiff line numberDiff line change
@@ -764,15 +764,16 @@ static inline bool php_var_serialize_class_name(smart_str *buf, zval *struc) /*
764764
}
765765
/* }}} */
766766

767-
static zend_result php_var_serialize_call_sleep(zend_object *obj, zend_function *fn, zval *retval) /* {{{ */
767+
static HashTable* php_var_serialize_call_sleep(zend_object *obj, zend_function *fn) /* {{{ */
768768
{
769769
zend_result res;
770770
zend_fcall_info fci;
771771
zend_fcall_info_cache fci_cache;
772+
zval retval;
772773

773774
fci.size = sizeof(fci);
774775
fci.object = obj;
775-
fci.retval = retval;
776+
fci.retval = &retval;
776777
fci.param_count = 0;
777778
fci.params = NULL;
778779
fci.named_params = NULL;
@@ -786,18 +787,18 @@ static zend_result php_var_serialize_call_sleep(zend_object *obj, zend_function
786787
res = zend_call_function(&fci, &fci_cache);
787788
BG(serialize_lock)--;
788789

789-
if (res == FAILURE || Z_ISUNDEF_P(retval)) {
790-
zval_ptr_dtor(retval);
791-
return FAILURE;
790+
if (res == FAILURE || Z_ISUNDEF(retval)) {
791+
zval_ptr_dtor(&retval);
792+
return NULL;
792793
}
793794

794-
if (!HASH_OF(retval)) {
795-
zval_ptr_dtor(retval);
795+
if (Z_TYPE(retval) != IS_ARRAY) {
796+
zval_ptr_dtor(&retval);
796797
php_error_docref(NULL, E_WARNING, "%s::__sleep() should return an array only containing the names of instance-variables to serialize", ZSTR_VAL(obj->ce->name));
797-
return FAILURE;
798+
return NULL;
798799
}
799800

800-
return SUCCESS;
801+
return Z_ARRVAL(retval);
801802
}
802803
/* }}} */
803804

@@ -864,7 +865,7 @@ static int php_var_serialize_get_sleep_props(
864865
zend_hash_init(ht, zend_hash_num_elements(sleep_retval), NULL, ZVAL_PTR_DTOR, 0);
865866
/* TODO: Rewrite this by fetching the property info instead of trying out different
866867
* name manglings? */
867-
ZEND_HASH_FOREACH_VAL(sleep_retval, name_val) {
868+
ZEND_HASH_FOREACH_VAL_IND(sleep_retval, name_val) {
868869
zend_string *name, *tmp_name, *priv_name, *prot_name;
869870

870871
ZVAL_DEREF(name_val);
@@ -977,10 +978,11 @@ static void php_var_serialize_nested_data(smart_str *buf, zval *struc, HashTable
977978
}
978979
/* }}} */
979980

980-
static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, php_serialize_data_t var_hash) /* {{{ */
981+
static void php_var_serialize_class(smart_str *buf, zval *struc, HashTable *ht, php_serialize_data_t var_hash) /* {{{ */
981982
{
982983
HashTable props;
983-
if (php_var_serialize_get_sleep_props(&props, struc, HASH_OF(retval_ptr)) == SUCCESS) {
984+
985+
if (php_var_serialize_get_sleep_props(&props, struc, ht) == SUCCESS) {
984986
php_var_serialize_class_name(buf, struc);
985987
php_var_serialize_nested_data(
986988
buf, struc, &props, zend_hash_num_elements(&props), /* incomplete_class */ 0, var_hash);
@@ -1158,10 +1160,11 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_
11581160
zval *zv = zend_hash_find_ex(&ce->function_table, ZSTR_KNOWN(ZEND_STR_SLEEP), 1);
11591161

11601162
if (zv) {
1161-
zval retval, tmp;
1163+
HashTable *ht;
1164+
zval tmp;
11621165

11631166
ZVAL_OBJ_COPY(&tmp, Z_OBJ_P(struc));
1164-
if (php_var_serialize_call_sleep(Z_OBJ(tmp), Z_FUNC_P(zv), &retval) == FAILURE) {
1167+
if (!(ht = php_var_serialize_call_sleep(Z_OBJ(tmp), Z_FUNC_P(zv)))) {
11651168
if (!EG(exception)) {
11661169
/* we should still add element even if it's not OK,
11671170
* since we already wrote the length of the array before */
@@ -1171,8 +1174,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_
11711174
return;
11721175
}
11731176

1174-
php_var_serialize_class(buf, &tmp, &retval, var_hash);
1175-
zval_ptr_dtor(&retval);
1177+
php_var_serialize_class(buf, &tmp, ht, var_hash);
1178+
zend_array_release(ht);
11761179
OBJ_RELEASE(Z_OBJ(tmp));
11771180
return;
11781181
}

0 commit comments

Comments
 (0)