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

Reply via email to