summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--Zend/tests/bug70187.phpt19
-rw-r--r--Zend/zend_hash.c8
-rw-r--r--Zend/zend_hash.h3
-rw-r--r--Zend/zend_object_handlers.c17
-rw-r--r--Zend/zend_objects.c3
-rw-r--r--ext/spl/spl_array.c1
-rw-r--r--ext/standard/var.c59
8 files changed, 80 insertions, 32 deletions
diff --git a/NEWS b/NEWS
index 0e5d9e5997..2b9730c7d0 100644
--- a/NEWS
+++ b/NEWS
@@ -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);