diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | Zend/tests/bug70187.phpt | 19 | ||||
-rw-r--r-- | Zend/zend_hash.c | 8 | ||||
-rw-r--r-- | Zend/zend_hash.h | 3 | ||||
-rw-r--r-- | Zend/zend_object_handlers.c | 17 | ||||
-rw-r--r-- | Zend/zend_objects.c | 3 | ||||
-rw-r--r-- | ext/spl/spl_array.c | 1 | ||||
-rw-r--r-- | ext/standard/var.c | 59 |
8 files changed, 80 insertions, 32 deletions
@@ -9,6 +9,8 @@ PHP NEWS (marcio dot web2 at gmail dot com) . Fixed bug #70321 (Magic getter breaks reference to array property). (Laruence) + . Fixed bug #70187 (Notice: unserialize(): Unexpected end of serialized data) + (Dmitry) . Fixed bug #70145 (From field incorrectly parsed from headers). (Anatol) . Fixed bug causing exception traces with anon classes to be truncated. (Bob) diff --git a/Zend/tests/bug70187.phpt b/Zend/tests/bug70187.phpt new file mode 100644 index 0000000000..a30f13b3ea --- /dev/null +++ b/Zend/tests/bug70187.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #70187 (Notice: unserialize(): Unexpected end of serialized data) +--FILE-- +<?php +class A { + public $b; +} + +$a = new A; +var_dump($a); // force properties HT +unset($a->b); +var_dump(serialize($a)); +?> +--EXPECT-- +object(A)#1 (1) { + ["b"]=> + NULL +} +string(12) "O:1:"A":0:{}" diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index eaade17838..139b0986f1 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -32,12 +32,12 @@ #if ZEND_DEBUG /* -#define HASH_MASK_CONSISTENCY 0x60 +#define HASH_MASK_CONSISTENCY 0xc0 */ #define HT_OK 0x00 -#define HT_IS_DESTROYING 0x20 -#define HT_DESTROYED 0x40 -#define HT_CLEANING 0x60 +#define HT_IS_DESTROYING 0x40 +#define HT_DESTROYED 0x80 +#define HT_CLEANING 0xc0 static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line) { diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 4a33b959cb..cdd635fa19 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -39,8 +39,9 @@ #define HASH_FLAG_PACKED (1<<2) #define HASH_FLAG_INITIALIZED (1<<3) #define HASH_FLAG_STATIC_KEYS (1<<4) +#define HASH_FLAG_HAS_EMPTY_IND (1<<5) -#define HASH_MASK_CONSISTENCY 0x60 +#define HASH_MASK_CONSISTENCY 0xc0 typedef struct _zend_hash_key { zend_ulong h; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 1c06f1ea5e..be9f50bfd4 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -82,8 +82,11 @@ ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */ zobj->properties->nInternalPointer = 0; ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) { if (/*prop_info->ce == ce &&*/ - (prop_info->flags & ZEND_ACC_STATIC) == 0 && - Z_TYPE_P(OBJ_PROP(zobj, prop_info->offset)) != IS_UNDEF) { + (prop_info->flags & ZEND_ACC_STATIC) == 0) { + + if (UNEXPECTED(Z_TYPE_P(OBJ_PROP(zobj, prop_info->offset)) == IS_UNDEF)) { + zobj->properties->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND; + } _zend_hash_append_ind(zobj->properties, prop_info->name, OBJ_PROP(zobj, prop_info->offset)); @@ -94,10 +97,13 @@ ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */ ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) { if (prop_info->ce == ce && (prop_info->flags & ZEND_ACC_STATIC) == 0 && - (prop_info->flags & ZEND_ACC_PRIVATE) != 0 && - Z_TYPE_P(OBJ_PROP(zobj, prop_info->offset)) != IS_UNDEF) { + (prop_info->flags & ZEND_ACC_PRIVATE) != 0) { zval zv; + if (UNEXPECTED(Z_TYPE_P(OBJ_PROP(zobj, prop_info->offset)) == IS_UNDEF)) { + zobj->properties->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND; + } + ZVAL_INDIRECT(&zv, OBJ_PROP(zobj, prop_info->offset)); zend_hash_add(zobj->properties, prop_info->name, &zv); } @@ -882,6 +888,9 @@ static void zend_std_unset_property(zval *object, zval *member, void **cache_slo if (Z_TYPE_P(slot) != IS_UNDEF) { zval_ptr_dtor(slot); ZVAL_UNDEF(slot); + if (zobj->properties) { + zobj->properties->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND; + } goto exit; } } else if (EXPECTED(zobj->properties != NULL)) { diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 9694cd6958..ca7ca52d89 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -204,6 +204,9 @@ ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object *o zend_hash_extend(new_object->properties, new_object->properties->nNumUsed + zend_hash_num_elements(old_object->properties), 0); } + new_object->properties->u.v.flags |= + old_object->properties->u.v.flags & HASH_FLAG_HAS_EMPTY_IND; + ZEND_HASH_FOREACH_KEY_VAL(old_object->properties, num_key, key, prop) { if (Z_TYPE_P(prop) == IS_INDIRECT) { ZVAL_INDIRECT(&new_prop, new_object->properties_table + (Z_INDIRECT_P(prop) - old_object->properties_table)); diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 3e664f0ee7..dedfaeb258 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -529,6 +529,7 @@ static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval } else { zval_ptr_dtor(data); ZVAL_UNDEF(data); + ht->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND; zend_hash_move_forward_ex(ht, spl_array_get_pos_ptr(ht, intern)); if (spl_array_is_object(intern)) { spl_array_skip_protected(intern, ht); diff --git a/ext/standard/var.c b/ext/standard/var.c index 7eaff11714..ddd82ffa75 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -37,18 +37,21 @@ static uint32_t zend_obj_num_elements(HashTable *ht) /* {{{ */ { - Bucket *p; - uint idx; - uint num; - - num = ht->nNumOfElements; - for (idx = 0; idx < ht->nNumUsed; idx++) { - p = ht->arData + idx; - if (Z_TYPE(p->val) == IS_UNDEF) continue; - if (Z_TYPE(p->val) == IS_INDIRECT) { - if (Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF) { - num--; + uint num = ht->nNumOfElements; + + if (UNEXPECTED(ht->u.v.flags & HASH_FLAG_HAS_EMPTY_IND)) { + zval *val; + + ZEND_HASH_FOREACH_VAL(ht, val) { + if (Z_TYPE_P(val) == IS_UNDEF) continue; + if (Z_TYPE_P(val) == IS_INDIRECT) { + if (Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF) { + num--; + } } + } ZEND_HASH_FOREACH_END(); + if (UNEXPECTED(ht->nNumOfElements == num)) { + ht->u.v.flags &= ~HASH_FLAG_HAS_EMPTY_IND; } } return num; @@ -678,14 +681,24 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_pt { uint32_t count; zend_bool incomplete_class; + HashTable *ht; incomplete_class = php_var_serialize_class_name(buf, struc); /* count after serializing name, since php_var_serialize_class_name * changes the count if the variable is incomplete class */ - count = zend_hash_num_elements(HASH_OF(retval_ptr)); - if (incomplete_class) { - --count; + if (Z_TYPE_P(retval_ptr) == IS_ARRAY) { + ht = Z_ARRVAL_P(retval_ptr); + count = zend_hash_num_elements(ht); + } else if (Z_TYPE_P(retval_ptr) == IS_OBJECT) { + ht = Z_OBJPROP_P(retval_ptr); + count = zend_obj_num_elements(ht); + if (incomplete_class) { + --count; + } + } else { + count = 0; } + smart_str_append_unsigned(buf, count); smart_str_appendl(buf, ":{", 2); @@ -694,12 +707,11 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_pt zval *d, *val; zval nval, *nvalp; zend_string *name; - HashTable *propers, *ht; + HashTable *propers; ZVAL_NULL(&nval); nvalp = &nval; - ht = HASH_OF(retval_ptr); ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { if (incomplete_class && strcmp(ZSTR_VAL(key), MAGIC_MEMBER) == 0) { continue; @@ -899,16 +911,17 @@ again: zend_bool incomplete_class = 0; if (Z_TYPE_P(struc) == IS_ARRAY) { smart_str_appendl(buf, "a:", 2); - myht = HASH_OF(struc); + myht = Z_ARRVAL_P(struc); + i = zend_hash_num_elements(myht); } else { incomplete_class = php_var_serialize_class_name(buf, struc); myht = Z_OBJPROP_P(struc); - } - /* count after serializing name, since php_var_serialize_class_name - * changes the count if the variable is incomplete class */ - i = myht ? zend_hash_num_elements(myht) : 0; - if (i > 0 && incomplete_class) { - --i; + /* count after serializing name, since php_var_serialize_class_name + * changes the count if the variable is incomplete class */ + i = zend_obj_num_elements(myht); + if (i > 0 && incomplete_class) { + --i; + } } smart_str_append_unsigned(buf, i); smart_str_appendl(buf, ":{", 2); |