fix multiple allocation for transform buffer

We were not updating the current_width_, which is usually
not a problem, unless we use Delta Palette with small number
of colors
-> Addressed this re-entrancy problem by checking we have
enough capacity for transform buffer.

The problem is not currently visible, until we restrict
the number of gradient used in delta-palette to less than 16.
Then the buffers have different current_width_ and the problem
surfaces.

Change-Id: Icd84b919905d7789014bb6668bfb6813c93fb36e
This commit is contained in:
Pascal Massimino 2016-02-17 05:45:38 +01:00
parent 8ce975ac82
commit 2f5e8986cf
2 changed files with 18 additions and 9 deletions

View File

@ -1114,6 +1114,12 @@ static WebPEncodingError WriteImage(const WebPPicture* const pic,
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
static void ClearTransformBuffer(VP8LEncoder* const enc) {
WebPSafeFree(enc->transform_mem_);
enc->transform_mem_ = NULL;
enc->transform_mem_size_ = 0;
}
// Allocates the memory for argb (W x H) buffer, 2 rows of context for // Allocates the memory for argb (W x H) buffer, 2 rows of context for
// prediction and transform data. // prediction and transform data.
// Flags influencing the memory allocated: // Flags influencing the memory allocated:
@ -1122,7 +1128,6 @@ static WebPEncodingError WriteImage(const WebPPicture* const pic,
static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc, static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
int width, int height) { int width, int height) {
WebPEncodingError err = VP8_ENC_OK; WebPEncodingError err = VP8_ENC_OK;
if (enc->argb_ == NULL) {
const int tile_size = 1 << enc->transform_bits_; const int tile_size = 1 << enc->transform_bits_;
const uint64_t image_size = width * height; const uint64_t image_size = width * height;
// Ensure enough size for tiles, as well as for two scanlines and two // Ensure enough size for tiles, as well as for two scanlines and two
@ -1134,31 +1139,32 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
? VP8LSubSampleSize(width, enc->transform_bits_) * ? VP8LSubSampleSize(width, enc->transform_bits_) *
VP8LSubSampleSize(height, enc->transform_bits_) VP8LSubSampleSize(height, enc->transform_bits_)
: 0; : 0;
const uint64_t total_size = const uint64_t mem_size =
image_size + WEBP_ALIGN_CST + image_size + WEBP_ALIGN_CST +
argb_scratch_size + WEBP_ALIGN_CST + argb_scratch_size + WEBP_ALIGN_CST +
(uint64_t)transform_data_size; (uint64_t)transform_data_size;
uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem)); uint32_t* mem = enc->transform_mem_;
if (mem == NULL || mem_size > enc->transform_mem_size_) {
ClearTransformBuffer(enc);
mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem));
if (mem == NULL) { if (mem == NULL) {
err = VP8_ENC_ERROR_OUT_OF_MEMORY; err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error; goto Error;
} }
enc->transform_mem_ = mem;
enc->transform_mem_size_ = (size_t)mem_size;
}
enc->argb_ = mem; enc->argb_ = mem;
mem = (uint32_t*)WEBP_ALIGN(mem + image_size); mem = (uint32_t*)WEBP_ALIGN(mem + image_size);
enc->argb_scratch_ = mem; enc->argb_scratch_ = mem;
mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size); mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size);
enc->transform_data_ = mem; enc->transform_data_ = mem;
enc->current_width_ = width; enc->current_width_ = width;
}
Error: Error:
return err; return err;
} }
static void ClearTransformBuffer(VP8LEncoder* const enc) {
WebPSafeFree(enc->argb_);
enc->argb_ = NULL;
}
static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) { static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
WebPEncodingError err = VP8_ENC_OK; WebPEncodingError err = VP8_ENC_OK;
const WebPPicture* const picture = enc->pic_; const WebPPicture* const picture = enc->pic_;

View File

@ -32,6 +32,9 @@ typedef struct {
uint32_t* argb_scratch_; // Scratch memory for argb rows uint32_t* argb_scratch_; // Scratch memory for argb rows
// (used for prediction). // (used for prediction).
uint32_t* transform_data_; // Scratch memory for transform data. uint32_t* transform_data_; // Scratch memory for transform data.
uint32_t* transform_mem_; // Currently allocated memory.
size_t transform_mem_size_; // Currently allocated memory size.
int current_width_; // Corresponds to packed image width. int current_width_; // Corresponds to packed image width.
// Encoding parameters derived from quality parameter. // Encoding parameters derived from quality parameter.