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...

(cherry picked from commit 205c7f26af)

Change-Id: I4dc31a46191fa9e65659c9a5bf5de9605e93f2f5
This commit is contained in:
Pascal Massimino 2015-01-10 15:24:08 -08:00 committed by James Zern
parent b2e71a9080
commit 5769623b6f

View File

@ -357,30 +357,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) {
@ -414,8 +417,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().