I already posted this, but received no responses. For that reason, I
am posting it again.
I have been investigating the cause of bug 17490 which appears to have
been a problem with the serializer. I am working with the PHP 4.2.3 source.
http://bugs.php.net/bug.php?id=17490
The cause of the problem appears to be that zend_hash_num_elements was
returning a number smaller than the actual number of elements being iterated across
using the zend_hash_*_ex functions.
This caused the serializer to store a number of elements smaller than
the actual number of elements written. This in turn leads to the unserializer failing
later.
I would like to know if there is some reason why
zend_hash_num_elements would be expected to return a value smaller than the number of
actual elements iterated across using the zend_hash_*_ex functions. This problem is
rare, but was happening sporadically.
Below is the section of code that is displaying this behavior. If
you see any obvious errors please let me know.
Thank you in advance,
Douglas Q. Hawkins
static inline void php_var_serialize_hash_all(
smart_str *buf,
zval **struc,
HashTable *var_hash TSRMLS_DC )
{
int numElements;
int cur;
int actualCount;
smart_str tmp = {0};
numElements = zend_hash_num_elements( HASH_OF( *struc ) );
/* There is a problem with the value returned by
zend_hash_num_elements
not returning a value equivalent to the number elements
actually
iterated across using zend_hash_*_ex functions */
/* Solution iterate filling a temporary buffer and remembering
the count -
then copy the temporary buffer into the actual buffer */
if ( numElements > 0 )
{
char *key;
zval **data;
ulong index;
uint key_len;
HashPosition pos;
for (
/* initialize */
zend_hash_internal_pointer_reset_ex(
HASH_OF( *struc ),
&pos ),
actualCount = 0;
/* test */;
/* advance */
zend_hash_move_forward_ex(
HASH_OF( *struc ),
&pos ),
++actualCount )
{
cur = zend_hash_get_current_key_ex(
HASH_OF( *struc ),
&key,
&key_len,
&index,
0,
&pos );
if ( cur == HASH_KEY_NON_EXISTANT ) break;
switch ( cur )
{
case HASH_KEY_IS_LONG:
php_var_serialize_long( &tmp,
index );
break;
case HASH_KEY_IS_STRING:
php_var_serialize_string(
&tmp, key, key_len - 1 );
break;
}
/* we should still add element even if it's
not OK,
since we already wrote the length of the
array before */
if ( ( zend_hash_get_current_data_ex(
HASH_OF( *struc ),
( void ** ) &data,
&pos ) != SUCCESS ) ||
( ! data ) ||
( data == struc ) )
{
php_var_serialize_null( &tmp );
}
else
{
php_var_serialize_intern(
&tmp,
data,
var_hash TSRMLS_CC );
}
}
}
else
{
actualCount = 0;
}
smart_str_append_long( buf, actualCount );
smart_str_appendc( buf, TYPE_VALUE_DELIMITER_CHAR );
smart_str_appendc( buf, OPEN_HASH_CHAR );
smart_str_appendl( buf, tmp.c, tmp.len );
smart_str_appendc( buf, CLOSE_HASH_CHAR );
}
--
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php
