[XviD-devel] bug in xvid decoder when parsing input bitstream
liang jian
jianliang79 at gmail.com
Tue Aug 29 10:12:13 CEST 2006
Hello every one, I have found a bug in xvid decoder when parsing input
bitstream, this bug can be reproduced through the following steps:
1) prepare a 16 x 16 image with YUY2 video format, clear it with black
color(y = 16, cb = cr = 128)
2) encode this image into an I-frame using xvid(simple profile level 3), the
coded stream is 52 bytes long.
3) allocate one page using VirtualAlloc (use mmap in linux), copy the
encoded stream to the end of this page.
4) decode the encoded stream in that page using xvid, an read access
violation occurs in BitstreamSkip() function when it execute the following
line:
tmp = *((uint32_t *) bs->tail + 2);
BitstreamSkip() function update bit position in the bitstream, and always
read a uint32_t value which is next to the uint32_t value contains the
current bit position, when decoder reach the end of the stream,
BitstreamSkip() will unavoidably read the memory which address is bigger
than the last byte of the input stream(and in the above case this addreass
is an invalid address).
the code is attached.
-------------- next part --------------
#include "stdafx.h"
#include <xvid.h>
static void create_codec(void **phEncoder, void **phDecoder,
int nWidth, int nHeight)
{
int nErr;
// initialize xvid library
xvid_gbl_init_t xvid_init;
memset(&xvid_init, 0, sizeof(xvid_gbl_init_t));
xvid_init.version = XVID_VERSION;
xvid_init.cpu_flags = 0; // auto detect
nErr = xvid_global(NULL, XVID_GBL_INIT, &xvid_init, NULL);
ASSERT(nErr >= 0);
// create encoder
xvid_enc_create_t enc_create;
memset(&enc_create, 0, sizeof(xvid_enc_create_t));
enc_create.version = XVID_VERSION;
enc_create.profile = XVID_PROFILE_S_L3;
enc_create.width = nWidth;
enc_create.height = nHeight;
enc_create.fincr = 1;
enc_create.fbase = 25;
enc_create.num_plugins = 0;
nErr = xvid_encore(NULL, XVID_ENC_CREATE, &enc_create, NULL);
ASSERT(nErr >= 0);
*phEncoder = enc_create.handle;
// create decoder
xvid_dec_create_t dec_create;
memset(&dec_create, 0, sizeof(xvid_dec_create_t));
dec_create.version = XVID_VERSION;
dec_create.width = nWidth;
dec_create.height = nHeight;
nErr = xvid_decore(NULL, XVID_DEC_CREATE, &dec_create, NULL);
ASSERT(nErr >= 0);
*phDecoder = dec_create.handle;
}
static int encode_image(void *hEncoder, void *pImage, int nPitch,
void *pFrame, int nMaxFrameLength)
{
xvid_enc_frame_t xvid_enc_frame;
xvid_enc_stats_t xvid_enc_stats;
int nBytes;
memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame_t));
xvid_enc_frame.version = XVID_VERSION;
xvid_enc_frame.vol_flags = 0;
xvid_enc_frame.vop_flags = 0;
xvid_enc_frame.type = XVID_TYPE_IVOP;
xvid_enc_frame.bitstream = pFrame;
xvid_enc_frame.length = nMaxFrameLength;
xvid_enc_frame.input.csp = XVID_CSP_YUY2;
xvid_enc_frame.input.plane[0] = pImage;
xvid_enc_frame.input.stride[0] = nPitch;
memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats_t));
xvid_enc_stats.version = XVID_VERSION;
nBytes = xvid_encore(hEncoder, XVID_ENC_ENCODE, &xvid_enc_frame, &xvid_enc_stats);
ASSERT(nBytes > 0);
return nBytes;
}
static void decode_image(void *hDecoder, void *pFrame, int nFrameSize,
void *pImage, int nPitch)
{
uint8_t *pui8Stream, *pui8StreamStart;
int nAllocSize;
nAllocSize = (nFrameSize + 4095) & (~4095) ;
pui8Stream = (uint8_t *)::VirtualAlloc(NULL, nAllocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
ASSERT(pui8Stream != NULL);
pui8StreamStart = pui8Stream + nAllocSize - nFrameSize;
memcpy(pui8StreamStart, pFrame, nFrameSize);
// decode
xvid_dec_frame_t xvid_dec_frame;
int nBytesConsumed;
memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t));
xvid_dec_frame.version = XVID_VERSION;
xvid_dec_frame.general = XVID_DISCONTINUITY;
xvid_dec_frame.bitstream = pui8StreamStart;
xvid_dec_frame.length = nFrameSize;
xvid_dec_frame.output.csp = XVID_CSP_YUY2;
xvid_dec_frame.output.plane[0] = pImage;
xvid_dec_frame.output.stride[0] = nPitch;
nBytesConsumed = xvid_decore(hDecoder, XVID_DEC_DECODE, &xvid_dec_frame, NULL);
ASSERT(nBytesConsumed == nFrameSize);
::VirtualFree(pui8Stream, 0, MEM_RELEASE);
}
#define IMAGE_WIDTH 16
#define IMAGE_HEIGHT 16
int main()
{
uint8_t aImage[IMAGE_WIDTH * 2 * IMAGE_HEIGHT];
uint8_t aFrame[4096];
void *hEncoder, *hDecoder;
uint32_t *pui32Buf;
int i, j, nSize;
// clear image
pui32Buf = (uint32_t *)aImage;
for (i = 0; i < IMAGE_HEIGHT; i++) {
for (j = 0; j < IMAGE_WIDTH / 2; j++)
*(pui32Buf++) = 0x80108010;
}
create_codec(&hEncoder, &hDecoder, IMAGE_WIDTH, IMAGE_HEIGHT);
// encode this image
nSize = encode_image(hEncoder, aImage, IMAGE_WIDTH * 2, aFrame, 4096);
memset(aImage, 0, sizeof(aImage));
decode_image(hDecoder, aFrame, nSize, aImage, IMAGE_WIDTH * 2);
xvid_encore(hEncoder, XVID_ENC_DESTROY, NULL, NULL);
xvid_decore(hDecoder, XVID_DEC_DESTROY, NULL, NULL);
return 0;
}
More information about the XviD-devel
mailing list