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

Reply via email to