In addition to that bug, the code in zm_buffer.h/cpp seems to consider the 'size' member to have two different meanings. Usually it is assumed to indicate how much live data is actually stored in the buffer, but at other times (such as allocation or after an Expand) it seems to try to convey some notion of how much space is available. This can cause some strange behavior. I think it is cleanest if 'size' indicates how much live data is available. The following patch fixes both the data corruption bug as well as keeping 'size' to mean the amount of data in the buffer, i.e. size == (tail - head).
Diffs from zm_buffer.h:
Code: Select all
*** /tmp/ZoneMinder-1.23.3/src/zm_buffer.h Mon Feb 25 01:49:52 2008
--- ./zm_buffer.h Tue May 6 23:55:44 2008
***************
*** 35,41 ****
Buffer() : storage( 0 ), allocation( 0 ), size( 0 ), head( 0 ), tail( 0 )
{
}
! Buffer( unsigned int p_size ) : allocation( p_size ), size( p_size )
{
head = storage = new unsigned char[allocation];
tail = head;
--- 35,41 ----
Buffer() : storage( 0 ), allocation( 0 ), size( 0 ), head( 0 ), tail( 0 )
{
}
! Buffer( unsigned int p_size ) : allocation( p_size ), size( 0 )
{
head = storage = new unsigned char[allocation];
tail = head;
***************
*** 49,55 ****
Buffer( const Buffer &buffer ) : allocation( buffer.size ), size( buffer.size )
{
head = storage = new unsigned char[size];
! memcpy( storage, buffer.storage, size );
tail = head + size;
}
~Buffer()
--- 49,55 ----
Buffer( const Buffer &buffer ) : allocation( buffer.size ), size( buffer.size )
{
head = storage = new unsigned char[size];
! memcpy( storage, buffer.head, size );
tail = head + size;
}
~Buffer()
***************
*** 78,84 ****
unsigned int Assign( const unsigned char *p_storage, unsigned int p_size );
unsigned int Assign( const Buffer &buffer )
{
! return( Assign( buffer.storage, buffer.size ) );
}
unsigned int Consume( unsigned int count )
--- 75,81 ----
unsigned int Assign( const unsigned char *p_storage, unsigned int p_size );
unsigned int Assign( const Buffer &buffer )
{
! return( Assign( buffer.head, buffer.size ) );
}
unsigned int Consume( unsigned int count )
***************
*** 122,127 ****
--- 119,125 ----
Expand( p_size );
memcpy( tail, p_storage, p_size );
tail += p_size;
+ size += p_size;
return( size );
}
unsigned int Append( const Buffer &buffer )
Code: Select all
***************
*** 53,65 ****
unsigned char *new_storage = new unsigned char[allocation];
if ( storage )
{
! memcpy( new_storage, storage, size );
delete[] storage;
}
storage = new_storage;
head = storage;
tail = head + width;
}
- size += count;
return( size );
}
--- 57,68 ----
unsigned char *new_storage = new unsigned char[allocation];
if ( storage )
{
! memcpy( new_storage, head, size );
delete[] storage;
}
storage = new_storage;
head = storage;
tail = head + width;
}
return( size );
}
Prior to this fix, I would get a 'Corrupt JPEG data' message every few minutes (depending on server load causing the buffer to start filling up), causing zmc to exit/restart. I'm not sure I've got all of the buffering corner cases fixed, but it's been running 10x longer than before without any errors so far, so I think it's an improvement.