fix handling of zero-sized partition #0 corner case

reported in https://code.google.com/p/webp/issues/detail?id=237

An empty partition #0 should be indicative of a bitstream error.
The previous code was correct, only an assert was triggered in debug mode.
But we might as well handle the case properly right away...

Change-Id: I4dc31a46191fa9e65659c9a5bf5de9605e93f2f5
This commit is contained in:
Pascal Massimino 2015-01-10 15:24:08 -08:00
parent cbcdd5ffaf
commit 205c7f26af

View File

@ -355,30 +355,33 @@ static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
} }
// Partition #0 // Partition #0
static int CopyParts0Data(WebPIDecoder* const idec) { static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_; VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8BitReader* const br = &dec->br_; VP8BitReader* const br = &dec->br_;
const size_t psize = br->buf_end_ - br->buf_; const size_t part_size = br->buf_end_ - br->buf_;
MemBuffer* const mem = &idec->mem_; MemBuffer* const mem = &idec->mem_;
assert(!idec->is_lossless_); assert(!idec->is_lossless_);
assert(mem->part0_buf_ == NULL); assert(mem->part0_buf_ == NULL);
assert(psize > 0); // the following is a format limitation, no need for runtime check:
assert(psize <= mem->part0_size_); // Format limit: no need for runtime check assert(part_size <= mem->part0_size_);
if (part_size == 0) { // can't have zero-size partition #0
return VP8_STATUS_BITSTREAM_ERROR;
}
if (mem->mode_ == MEM_MODE_APPEND) { if (mem->mode_ == MEM_MODE_APPEND) {
// We copy and grab ownership of the partition #0 data. // We copy and grab ownership of the partition #0 data.
uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, psize); uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size);
if (part0_buf == NULL) { if (part0_buf == NULL) {
return 0; return VP8_STATUS_OUT_OF_MEMORY;
} }
memcpy(part0_buf, br->buf_, psize); memcpy(part0_buf, br->buf_, part_size);
mem->part0_buf_ = part0_buf; mem->part0_buf_ = part0_buf;
br->buf_ = part0_buf; br->buf_ = part0_buf;
br->buf_end_ = part0_buf + psize; br->buf_end_ = part0_buf + part_size;
} else { } else {
// Else: just keep pointers to the partition #0's data in dec_->br_. // Else: just keep pointers to the partition #0's data in dec_->br_.
} }
mem->start_ += psize; mem->start_ += part_size;
return 1; return VP8_STATUS_OK;
} }
static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
@ -412,8 +415,10 @@ static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
dec->mt_method_ = VP8GetThreadMethod(params->options, NULL, dec->mt_method_ = VP8GetThreadMethod(params->options, NULL,
io->width, io->height); io->width, io->height);
VP8InitDithering(params->options, dec); VP8InitDithering(params->options, dec);
if (!CopyParts0Data(idec)) {
return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY); dec->status_ = CopyParts0Data(idec);
if (dec->status_ != VP8_STATUS_OK) {
return IDecError(idec, dec->status_);
} }
// Finish setting up the decoding parameters. Will call io->setup(). // Finish setting up the decoding parameters. Will call io->setup().