use WebPSafe[CM]alloc/WebPSafeFree instead of [cm]alloc/free

there's still some malloc/free in the external example
This is an encoder API change because of the introduction
of WebPMemoryWriterClear() for symmetry reasons.

The MemoryWriter object should probably go in examples/ instead
of being in the main lib, though.
mux_types.h stil contain some inlined free()/malloc() that are
harder to remove (we need to put them in the libwebputils lib
and make sure link is ok). Left as a TODO for now.

Also: WebPDecodeRGB*() function are still returning a pointer
that needs to be free()'d. We should call WebPSafeFree() on
these, but it means exposing the whole mechanism. TODO(later).

Change-Id: Iad2c9060f7fa6040e3ba489c8b07f4caadfab77b
This commit is contained in:
skal 2014-03-27 23:27:32 +01:00 committed by Gerrit Code Review
parent 51f406a5d7
commit af93bdd6bc
32 changed files with 168 additions and 134 deletions

7
README
View File

@ -443,15 +443,20 @@ The encoding flow looks like:
// Set up a byte-output write method. WebPMemoryWriter, for instance. // Set up a byte-output write method. WebPMemoryWriter, for instance.
WebPMemoryWriter wrt; WebPMemoryWriter wrt;
WebPMemoryWriterInit(&wrt); // initialize 'wrt'
pic.writer = MyFileWriter; pic.writer = MyFileWriter;
pic.custom_ptr = my_opaque_structure_to_make_MyFileWriter_work; pic.custom_ptr = my_opaque_structure_to_make_MyFileWriter_work;
// initialize 'wrt' here...
// Compress! // Compress!
int ok = WebPEncode(&config, &pic); // ok = 0 => error occurred! int ok = WebPEncode(&config, &pic); // ok = 0 => error occurred!
WebPPictureFree(&pic); // must be called independently of the 'ok' result. WebPPictureFree(&pic); // must be called independently of the 'ok' result.
// output data should have been handled by the writer at that point. // output data should have been handled by the writer at that point.
// -> compressed data is the memory buffer described by wrt.mem / wrt.size
// deallocate the memory used by compressed data
WebPMemoryWriterClear(&wrt);
-------------------------------------- END PSEUDO EXAMPLE -------------------------------------- END PSEUDO EXAMPLE

View File

@ -1121,7 +1121,7 @@ int main(int argc, const char *argv[]) {
return_value = 0; return_value = 0;
Error: Error:
free(memory_writer.mem); WebPMemoryWriterClear(&memory_writer);
free(picture.extra_info); free(picture.extra_info);
MetadataFree(&metadata); MetadataFree(&metadata);
WebPPictureFree(&picture); WebPPictureFree(&picture);

View File

@ -469,10 +469,10 @@ static int SetFrame(const WebPConfig* const config, int allow_mixed,
// TODO(later): Perhaps a rough SSIM/PSNR produced by the encoder should // TODO(later): Perhaps a rough SSIM/PSNR produced by the encoder should
// also be a criteria, in addition to sizes. // also be a criteria, in addition to sizes.
if (mem1.size <= mem2.size) { if (mem1.size <= mem2.size) {
free(mem2.mem); WebPMemoryWriterClear(&mem2);
GetEncodedData(&mem1, encoded_data); GetEncodedData(&mem1, encoded_data);
} else { } else {
free(mem1.mem); WebPMemoryWriterClear(&mem1);
GetEncodedData(&mem2, encoded_data); GetEncodedData(&mem2, encoded_data);
} }
} else { } else {
@ -481,8 +481,8 @@ static int SetFrame(const WebPConfig* const config, int allow_mixed,
return 1; return 1;
Err: Err:
free(mem1.mem); WebPMemoryWriterClear(&mem1);
free(mem2.mem); WebPMemoryWriterClear(&mem2);
return 0; return 0;
} }

View File

@ -16,13 +16,14 @@
#include "./vp8i.h" #include "./vp8i.h"
#include "./vp8li.h" #include "./vp8li.h"
#include "../utils/quant_levels_dec.h" #include "../utils/quant_levels_dec.h"
#include "../utils/utils.h"
#include "../webp/format_constants.h" #include "../webp/format_constants.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// ALPHDecoder object. // ALPHDecoder object.
ALPHDecoder* ALPHNew(void) { ALPHDecoder* ALPHNew(void) {
ALPHDecoder* const dec = (ALPHDecoder*)calloc(1, sizeof(*dec)); ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
return dec; return dec;
} }
@ -30,7 +31,7 @@ void ALPHDelete(ALPHDecoder* const dec) {
if (dec != NULL) { if (dec != NULL) {
VP8LDelete(dec->vp8l_dec_); VP8LDelete(dec->vp8l_dec_);
dec->vp8l_dec_ = NULL; dec->vp8l_dec_ = NULL;
free(dec); WebPSafeFree(dec);
} }
} }
@ -158,4 +159,3 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
// Return a pointer to the current decoded row. // Return a pointer to the current decoded row.
return dec->alpha_plane_ + row * width; return dec->alpha_plane_ + row * width;
} }

View File

@ -216,8 +216,9 @@ int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
void WebPFreeDecBuffer(WebPDecBuffer* buffer) { void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
if (buffer != NULL) { if (buffer != NULL) {
if (!buffer->is_external_memory) if (!buffer->is_external_memory) {
free(buffer->private_memory); WebPSafeFree(buffer->private_memory);
}
buffer->private_memory = NULL; buffer->private_memory = NULL;
} }
} }

View File

@ -549,7 +549,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
if (needed != (size_t)needed) return 0; // check for overflow if (needed != (size_t)needed) return 0; // check for overflow
if (needed > dec->mem_size_) { if (needed > dec->mem_size_) {
free(dec->mem_); WebPSafeFree(dec->mem_);
dec->mem_size_ = 0; dec->mem_size_ = 0;
dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t)); dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t));
if (dec->mem_ == NULL) { if (dec->mem_ == NULL) {

View File

@ -188,7 +188,7 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
(uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf)); (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
if (new_buf == NULL) return 0; if (new_buf == NULL) return 0;
memcpy(new_buf, old_base, current_size); memcpy(new_buf, old_base, current_size);
free(mem->buf_); WebPSafeFree(mem->buf_);
mem->buf_ = new_buf; mem->buf_ = new_buf;
mem->buf_size_ = (size_t)extra_size; mem->buf_size_ = (size_t)extra_size;
mem->start_ = new_mem_start; mem->start_ = new_mem_start;
@ -230,8 +230,8 @@ static void InitMemBuffer(MemBuffer* const mem) {
static void ClearMemBuffer(MemBuffer* const mem) { static void ClearMemBuffer(MemBuffer* const mem) {
assert(mem); assert(mem);
if (mem->mode_ == MEM_MODE_APPEND) { if (mem->mode_ == MEM_MODE_APPEND) {
free(mem->buf_); WebPSafeFree(mem->buf_);
free((void*)mem->part0_buf_); WebPSafeFree((void*)mem->part0_buf_);
} }
} }
@ -373,7 +373,7 @@ static int CopyParts0Data(WebPIDecoder* const idec) {
assert(psize <= mem->part0_size_); // Format limit: no need for runtime check assert(psize <= mem->part0_size_); // Format limit: no need for runtime check
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*)malloc(psize); uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, psize);
if (part0_buf == NULL) { if (part0_buf == NULL) {
return 0; return 0;
} }
@ -573,7 +573,7 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
// Public functions // Public functions
WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) { WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec)); WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
if (idec == NULL) { if (idec == NULL) {
return NULL; return NULL;
} }
@ -632,7 +632,7 @@ void WebPIDelete(WebPIDecoder* idec) {
} }
ClearMemBuffer(&idec->mem_); ClearMemBuffer(&idec->mem_);
WebPFreeDecBuffer(&idec->output_); WebPFreeDecBuffer(&idec->output_);
free(idec); WebPSafeFree(idec);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -17,6 +17,7 @@
#include "./webpi.h" #include "./webpi.h"
#include "../dsp/dsp.h" #include "../dsp/dsp.h"
#include "../dsp/yuv.h" #include "../dsp/yuv.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Main YUV<->RGB conversion functions // Main YUV<->RGB conversion functions
@ -324,7 +325,7 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
if (has_alpha) { if (has_alpha) {
tmp_size += work_size; tmp_size += work_size;
} }
p->memory = calloc(1, tmp_size * sizeof(*work)); p->memory = WebPSafeCalloc(1ULL, tmp_size * sizeof(*work));
if (p->memory == NULL) { if (p->memory == NULL) {
return 0; // memory error return 0; // memory error
} }
@ -492,7 +493,7 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const size_t work_size = 2 * out_width; // scratch memory for one rescaler const size_t work_size = 2 * out_width; // scratch memory for one rescaler
int32_t* work; // rescalers work area int32_t* work; // rescalers work area
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
size_t tmp_size1, tmp_size2; size_t tmp_size1, tmp_size2, total_size;
tmp_size1 = 3 * work_size; tmp_size1 = 3 * work_size;
tmp_size2 = 3 * out_width; tmp_size2 = 3 * out_width;
@ -500,7 +501,8 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
tmp_size1 += work_size; tmp_size1 += work_size;
tmp_size2 += out_width; tmp_size2 += out_width;
} }
p->memory = calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp)); total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
p->memory = WebPSafeCalloc(1ULL, total_size);
if (p->memory == NULL) { if (p->memory == NULL) {
return 0; // memory error return 0; // memory error
} }
@ -564,7 +566,7 @@ static int CustomSetup(VP8Io* io) {
if (io->fancy_upsampling) { if (io->fancy_upsampling) {
#ifdef FANCY_UPSAMPLING #ifdef FANCY_UPSAMPLING
const int uv_width = (io->mb_w + 1) >> 1; const int uv_width = (io->mb_w + 1) >> 1;
p->memory = malloc(io->mb_w + 2 * uv_width); p->memory = WebPSafeMalloc(1ULL, (size_t)(io->mb_w + 2 * uv_width));
if (p->memory == NULL) { if (p->memory == NULL) {
return 0; // memory error. return 0; // memory error.
} }
@ -620,7 +622,7 @@ static int CustomPut(const VP8Io* io) {
static void CustomTeardown(const VP8Io* io) { static void CustomTeardown(const VP8Io* io) {
WebPDecParams* const p = (WebPDecParams*)io->opaque; WebPDecParams* const p = (WebPDecParams*)io->opaque;
free(p->memory); WebPSafeFree(p->memory);
p->memory = NULL; p->memory = NULL;
} }

View File

@ -18,6 +18,7 @@
#include "./vp8li.h" #include "./vp8li.h"
#include "./webpi.h" #include "./webpi.h"
#include "../utils/bit_reader.h" #include "../utils/bit_reader.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -44,7 +45,7 @@ int VP8InitIoInternal(VP8Io* const io, int version) {
} }
VP8Decoder* VP8New(void) { VP8Decoder* VP8New(void) {
VP8Decoder* const dec = (VP8Decoder*)calloc(1, sizeof(*dec)); VP8Decoder* const dec = (VP8Decoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec != NULL) { if (dec != NULL) {
SetOk(dec); SetOk(dec);
WebPWorkerInit(&dec->worker_); WebPWorkerInit(&dec->worker_);
@ -68,7 +69,7 @@ const char* VP8StatusMessage(VP8Decoder* const dec) {
void VP8Delete(VP8Decoder* const dec) { void VP8Delete(VP8Decoder* const dec) {
if (dec != NULL) { if (dec != NULL) {
VP8Clear(dec); VP8Clear(dec);
free(dec); WebPSafeFree(dec);
} }
} }
@ -689,7 +690,7 @@ void VP8Clear(VP8Decoder* const dec) {
} }
ALPHDelete(dec->alph_dec_); ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL; dec->alph_dec_ = NULL;
free(dec->mem_); WebPSafeFree(dec->mem_);
dec->mem_ = NULL; dec->mem_ = NULL;
dec->mem_size_ = 0; dec->mem_size_ = 0;
memset(&dec->br_, 0, sizeof(dec->br_)); memset(&dec->br_, 0, sizeof(dec->br_));

View File

@ -285,7 +285,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
if (ok) { if (ok) {
ok = HuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size); ok = HuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size);
} }
free(code_lengths); WebPSafeFree(code_lengths);
} }
ok = ok && !br->error_; ok = ok && !br->error_;
if (!ok) { if (!ok) {
@ -304,7 +304,7 @@ static void DeleteHtreeGroups(HTreeGroup* htree_groups, int num_htree_groups) {
HuffmanTreeRelease(&htrees[j]); HuffmanTreeRelease(&htrees[j]);
} }
} }
free(htree_groups); WebPSafeFree(htree_groups);
} }
} }
@ -368,7 +368,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
return 1; return 1;
Error: Error:
free(huffman_image); WebPSafeFree(huffman_image);
DeleteHtreeGroups(htree_groups, num_htree_groups); DeleteHtreeGroups(htree_groups, num_htree_groups);
return 0; return 0;
} }
@ -933,7 +933,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
// VP8LTransform // VP8LTransform
static void ClearTransform(VP8LTransform* const transform) { static void ClearTransform(VP8LTransform* const transform) {
free(transform->data_); WebPSafeFree(transform->data_);
transform->data_ = NULL; transform->data_ = NULL;
} }
@ -957,7 +957,7 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
} }
for (; i < 4 * final_num_colors; ++i) for (; i < 4 * final_num_colors; ++i)
new_data[i] = 0; // black tail. new_data[i] = 0; // black tail.
free(transform->data_); WebPSafeFree(transform->data_);
transform->data_ = new_color_map; transform->data_ = new_color_map;
} }
return 1; return 1;
@ -1027,7 +1027,7 @@ static void InitMetadata(VP8LMetadata* const hdr) {
static void ClearMetadata(VP8LMetadata* const hdr) { static void ClearMetadata(VP8LMetadata* const hdr) {
assert(hdr); assert(hdr);
free(hdr->huffman_image_); WebPSafeFree(hdr->huffman_image_);
DeleteHtreeGroups(hdr->htree_groups_, hdr->num_htree_groups_); DeleteHtreeGroups(hdr->htree_groups_, hdr->num_htree_groups_);
VP8LColorCacheClear(&hdr->color_cache_); VP8LColorCacheClear(&hdr->color_cache_);
InitMetadata(hdr); InitMetadata(hdr);
@ -1037,7 +1037,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
// VP8LDecoder // VP8LDecoder
VP8LDecoder* VP8LNew(void) { VP8LDecoder* VP8LNew(void) {
VP8LDecoder* const dec = (VP8LDecoder*)calloc(1, sizeof(*dec)); VP8LDecoder* const dec = (VP8LDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec == NULL) return NULL; if (dec == NULL) return NULL;
dec->status_ = VP8_STATUS_OK; dec->status_ = VP8_STATUS_OK;
dec->action_ = READ_DIM; dec->action_ = READ_DIM;
@ -1053,7 +1053,7 @@ void VP8LClear(VP8LDecoder* const dec) {
if (dec == NULL) return; if (dec == NULL) return;
ClearMetadata(&dec->hdr_); ClearMetadata(&dec->hdr_);
free(dec->pixels_); WebPSafeFree(dec->pixels_);
dec->pixels_ = NULL; dec->pixels_ = NULL;
for (i = 0; i < dec->next_transform_; ++i) { for (i = 0; i < dec->next_transform_; ++i) {
ClearTransform(&dec->transforms_[i]); ClearTransform(&dec->transforms_[i]);
@ -1061,7 +1061,7 @@ void VP8LClear(VP8LDecoder* const dec) {
dec->next_transform_ = 0; dec->next_transform_ = 0;
dec->transforms_seen_ = 0; dec->transforms_seen_ = 0;
free(dec->rescaler_memory); WebPSafeFree(dec->rescaler_memory);
dec->rescaler_memory = NULL; dec->rescaler_memory = NULL;
dec->output_ = NULL; // leave no trace behind dec->output_ = NULL; // leave no trace behind
@ -1070,7 +1070,7 @@ void VP8LClear(VP8LDecoder* const dec) {
void VP8LDelete(VP8LDecoder* const dec) { void VP8LDelete(VP8LDecoder* const dec) {
if (dec != NULL) { if (dec != NULL) {
VP8LClear(dec); VP8LClear(dec);
free(dec); WebPSafeFree(dec);
} }
} }
@ -1157,7 +1157,7 @@ static int DecodeImageStream(int xsize, int ysize,
End: End:
if (!ok) { if (!ok) {
free(data); WebPSafeFree(data);
ClearMetadata(hdr); ClearMetadata(hdr);
// If not enough data (br.eos_) resulted in BIT_STREAM_ERROR, update the // If not enough data (br.eos_) resulted in BIT_STREAM_ERROR, update the
// status appropriately. // status appropriately.

View File

@ -289,7 +289,7 @@ static ParseStatus NewFrame(const MemBuffer* const mem,
if (actual_size < min_size) return PARSE_ERROR; if (actual_size < min_size) return PARSE_ERROR;
if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
*frame = (Frame*)calloc(1, sizeof(**frame)); *frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(**frame));
return (*frame == NULL) ? PARSE_ERROR : PARSE_OK; return (*frame == NULL) ? PARSE_ERROR : PARSE_OK;
} }
@ -317,7 +317,7 @@ static ParseStatus ParseAnimationFrame(
(bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) {
free(frame); WebPSafeFree(frame);
return PARSE_ERROR; return PARSE_ERROR;
} }
@ -333,7 +333,7 @@ static ParseStatus ParseAnimationFrame(
} }
} }
if (!added_frame) free(frame); if (!added_frame) WebPSafeFree(frame);
return status; return status;
} }
@ -368,7 +368,7 @@ static ParseStatus ParseFragment(WebPDemuxer* const dmux,
} }
} }
if (!added_fragment) free(frame); if (!added_fragment) WebPSafeFree(frame);
return status; return status;
} }
#endif // WEBP_EXPERIMENTAL_FEATURES #endif // WEBP_EXPERIMENTAL_FEATURES
@ -379,7 +379,7 @@ static ParseStatus ParseFragment(WebPDemuxer* const dmux,
// Returns true on success, false otherwise. // Returns true on success, false otherwise.
static int StoreChunk(WebPDemuxer* const dmux, static int StoreChunk(WebPDemuxer* const dmux,
size_t start_offset, uint32_t size) { size_t start_offset, uint32_t size) {
Chunk* const chunk = (Chunk*)calloc(1, sizeof(*chunk)); Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk));
if (chunk == NULL) return 0; if (chunk == NULL) return 0;
chunk->data_.offset_ = start_offset; chunk->data_.offset_ = start_offset;
@ -427,7 +427,7 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
frame = (Frame*)calloc(1, sizeof(*frame)); frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
if (frame == NULL) return PARSE_ERROR; if (frame == NULL) return PARSE_ERROR;
// For the single image case we allow parsing of a partial frame, but we need // For the single image case we allow parsing of a partial frame, but we need
@ -458,7 +458,7 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
} }
} }
if (!image_added) free(frame); if (!image_added) WebPSafeFree(frame);
return status; return status;
} }
@ -729,7 +729,7 @@ WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
partial = (mem.buf_size_ < mem.riff_end_); partial = (mem.buf_size_ < mem.riff_end_);
if (!allow_partial && partial) return NULL; if (!allow_partial && partial) return NULL;
dmux = (WebPDemuxer*)calloc(1, sizeof(*dmux)); dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux));
if (dmux == NULL) return NULL; if (dmux == NULL) return NULL;
InitDemux(dmux, &mem); InitDemux(dmux, &mem);
@ -761,14 +761,14 @@ void WebPDemuxDelete(WebPDemuxer* dmux) {
for (f = dmux->frames_; f != NULL;) { for (f = dmux->frames_; f != NULL;) {
Frame* const cur_frame = f; Frame* const cur_frame = f;
f = f->next_; f = f->next_;
free(cur_frame); WebPSafeFree(cur_frame);
} }
for (c = dmux->chunks_; c != NULL;) { for (c = dmux->chunks_; c != NULL;) {
Chunk* const cur_chunk = c; Chunk* const cur_chunk = c;
c = c->next_; c = c->next_;
free(cur_chunk); WebPSafeFree(cur_chunk);
} }
free(dmux); WebPSafeFree(dmux);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -17,6 +17,7 @@
#include "./vp8enci.h" #include "./vp8enci.h"
#include "../utils/filters.h" #include "../utils/filters.h"
#include "../utils/quant_levels.h" #include "../utils/quant_levels.h"
#include "../utils/utils.h"
#include "../webp/format_constants.h" #include "../webp/format_constants.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -34,7 +35,7 @@
// //
// 'output' corresponds to the buffer containing compressed alpha data. // 'output' corresponds to the buffer containing compressed alpha data.
// This buffer is allocated by this method and caller should call // This buffer is allocated by this method and caller should call
// free(*output) when done. // WebPSafeFree(*output) when done.
// 'output_size' corresponds to size of this compressed alpha buffer. // 'output_size' corresponds to size of this compressed alpha buffer.
// //
// Returns 1 on successfully encoding the alpha and // Returns 1 on successfully encoding the alpha and
@ -231,7 +232,7 @@ static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height,
GetFilterMap(alpha, width, height, filter, effort_level); GetFilterMap(alpha, width, height, filter, effort_level);
InitFilterTrial(&best); InitFilterTrial(&best);
if (try_map != FILTER_TRY_NONE) { if (try_map != FILTER_TRY_NONE) {
uint8_t* filtered_alpha = (uint8_t*)malloc(data_size); uint8_t* filtered_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
if (filtered_alpha == NULL) return 0; if (filtered_alpha == NULL) return 0;
for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) { for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) {
@ -248,7 +249,7 @@ static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height,
} }
} }
} }
free(filtered_alpha); WebPSafeFree(filtered_alpha);
} else { } else {
ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE, ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE,
reduce_levels, effort_level, NULL, &best); reduce_levels, effort_level, NULL, &best);
@ -298,7 +299,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
filter = WEBP_FILTER_NONE; filter = WEBP_FILTER_NONE;
} }
quant_alpha = (uint8_t*)malloc(data_size); quant_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
if (quant_alpha == NULL) { if (quant_alpha == NULL) {
return 0; return 0;
} }
@ -325,7 +326,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
} }
} }
free(quant_alpha); WebPSafeFree(quant_alpha);
return ok; return ok;
} }
@ -346,7 +347,7 @@ static int CompressAlphaJob(VP8Encoder* const enc, void* dummy) {
return 0; return 0;
} }
if (alpha_size != (uint32_t)alpha_size) { // Sanity check. if (alpha_size != (uint32_t)alpha_size) { // Sanity check.
free(alpha_data); WebPSafeFree(alpha_data);
return 0; return 0;
} }
enc->alpha_data_size_ = (uint32_t)alpha_size; enc->alpha_data_size_ = (uint32_t)alpha_size;
@ -401,7 +402,7 @@ int VP8EncDeleteAlpha(VP8Encoder* const enc) {
ok = WebPWorkerSync(worker); // finish anything left in flight ok = WebPWorkerSync(worker); // finish anything left in flight
WebPWorkerEnd(worker); // still need to end the worker, even if !ok WebPWorkerEnd(worker); // still need to end the worker, even if !ok
} }
free(enc->alpha_data_); WebPSafeFree(enc->alpha_data_);
enc->alpha_data_ = NULL; enc->alpha_data_ = NULL;
enc->alpha_data_size_ = 0; enc->alpha_data_size_ = 0;
enc->has_alpha_ = 0; enc->has_alpha_ = 0;

View File

@ -63,7 +63,7 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
mb->segment_ = tmp[x + y * w]; mb->segment_ = tmp[x + y * w];
} }
} }
free(tmp); WebPSafeFree(tmp);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -89,7 +89,7 @@ void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs) {
void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) { void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) {
if (refs != NULL) { if (refs != NULL) {
free(refs->refs); WebPSafeFree(refs->refs);
VP8LInitBackwardRefs(refs); VP8LInitBackwardRefs(refs);
} }
} }
@ -116,13 +116,13 @@ static WEBP_INLINE uint64_t GetPixPairHash64(const uint32_t* const argb) {
static HashChain* HashChainNew(int size) { static HashChain* HashChainNew(int size) {
int i; int i;
HashChain* const p = (HashChain*)malloc(sizeof(*p)); HashChain* const p = (HashChain*)WebPSafeMalloc(1ULL, sizeof(*p));
if (p == NULL) { if (p == NULL) {
return NULL; return NULL;
} }
p->chain_ = (int*)WebPSafeMalloc((uint64_t)size, sizeof(*p->chain_)); p->chain_ = (int*)WebPSafeMalloc((uint64_t)size, sizeof(*p->chain_));
if (p->chain_ == NULL) { if (p->chain_ == NULL) {
free(p); WebPSafeFree(p);
return NULL; return NULL;
} }
for (i = 0; i < size; ++i) { for (i = 0; i < size; ++i) {
@ -136,8 +136,8 @@ static HashChain* HashChainNew(int size) {
static void HashChainDelete(HashChain* const p) { static void HashChainDelete(HashChain* const p) {
if (p != NULL) { if (p != NULL) {
free(p->chain_); WebPSafeFree(p->chain_);
free(p); WebPSafeFree(p);
} }
} }
@ -490,7 +490,7 @@ static int BackwardReferencesHashChainDistanceOnly(
const int use_color_cache = (cache_bits > 0); const int use_color_cache = (cache_bits > 0);
float* const cost = float* const cost =
(float*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost)); (float*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost));
CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model)); CostModel* cost_model = (CostModel*)WebPSafeMalloc(1ULL, sizeof(*cost_model));
HashChain* hash_chain = HashChainNew(pix_count); HashChain* hash_chain = HashChainNew(pix_count);
VP8LColorCache hashers; VP8LColorCache hashers;
const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68; const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68;
@ -597,8 +597,8 @@ static int BackwardReferencesHashChainDistanceOnly(
Error: Error:
if (cc_init) VP8LColorCacheClear(&hashers); if (cc_init) VP8LColorCacheClear(&hashers);
HashChainDelete(hash_chain); HashChainDelete(hash_chain);
free(cost_model); WebPSafeFree(cost_model);
free(cost); WebPSafeFree(cost);
return ok; return ok;
} }
@ -724,7 +724,7 @@ static int BackwardReferencesTraceBackwards(int xsize, int ysize,
} }
ok = 1; ok = 1;
Error: Error:
free(dist_array); WebPSafeFree(dist_array);
return ok; return ok;
} }
@ -768,7 +768,8 @@ int VP8LGetBackwardReferences(int width, int height,
{ {
double bit_cost_lz77, bit_cost_rle; double bit_cost_lz77, bit_cost_rle;
VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo)); VP8LHistogram* const histo =
(VP8LHistogram*)WebPSafeMalloc(1ULL, sizeof(*histo));
if (histo == NULL) goto Error1; if (histo == NULL) goto Error1;
// Evaluate lz77 coding // Evaluate lz77 coding
VP8LHistogramCreate(histo, &refs_lz77, cache_bits); VP8LHistogramCreate(histo, &refs_lz77, cache_bits);
@ -778,7 +779,7 @@ int VP8LGetBackwardReferences(int width, int height,
bit_cost_rle = VP8LHistogramEstimateBits(histo); bit_cost_rle = VP8LHistogramEstimateBits(histo);
// Decide if LZ77 is useful. // Decide if LZ77 is useful.
lz77_is_useful = (bit_cost_lz77 < bit_cost_rle); lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
free(histo); WebPSafeFree(histo);
} }
// Choose appropriate backward reference. // Choose appropriate backward reference.

View File

@ -162,7 +162,7 @@ static int Record(int bit, proba_t* const stats) {
return bit; return bit;
} }
// We keep the table free variant around for reference, in case. // We keep the table-free variant around for reference, in case.
#define USE_LEVEL_CODE_TABLE #define USE_LEVEL_CODE_TABLE
// Simulate block coding, but only record statistics. // Simulate block coding, but only record statistics.

View File

@ -723,7 +723,8 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
// bin_map[n][num_histo + 1] ... bin_map[n][bin_depth - 1] = un-used indices. // bin_map[n][num_histo + 1] ... bin_map[n][bin_depth - 1] = un-used indices.
const int bin_depth = histo_image_raw_size + 1; const int bin_depth = histo_image_raw_size + 1;
int16_t* bin_map = NULL; int16_t* bin_map = NULL;
VP8LHistogram* const histos = (VP8LHistogram*)malloc(2 * sizeof(*histos)); VP8LHistogram* const histos =
(VP8LHistogram*)WebPSafeMalloc(2ULL, sizeof(*histos));
VP8LHistogramSet* const init_histo = VP8LHistogramSet* const init_histo =
VP8LAllocateHistogramSet(histo_image_raw_size, cache_bits); VP8LAllocateHistogramSet(histo_image_raw_size, cache_bits);
@ -760,8 +761,8 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
ok = 1; ok = 1;
Error: Error:
free(bin_map); WebPSafeFree(bin_map);
free(init_histo); WebPSafeFree(init_histo);
free(histos); WebPSafeFree(histos);
return ok; return ok;
} }

View File

@ -46,7 +46,7 @@ typedef struct {
} VP8LHistogram; } VP8LHistogram;
// Collection of histograms with fixed capacity, allocated as one // Collection of histograms with fixed capacity, allocated as one
// big memory chunk. Can be destroyed by simply calling 'free()'. // big memory chunk. Can be destroyed by calling WebPSafeFree().
typedef struct { typedef struct {
int size; // number of slots currently in use int size; // number of slots currently in use
int max_size; // maximum capacity int max_size; // maximum capacity

View File

@ -14,6 +14,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "./vp8enci.h" #include "./vp8enci.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -39,6 +40,5 @@ int VP8EncFinishLayer(VP8Encoder* const enc) {
} }
void VP8EncDeleteLayer(VP8Encoder* enc) { void VP8EncDeleteLayer(VP8Encoder* enc) {
free(enc->layer_data_); WebPSafeFree(enc->layer_data_);
} }

View File

@ -175,7 +175,7 @@ static void WebPPictureGrabSpecs(const WebPPicture* const src,
// the other YUV(A) buffer. // the other YUV(A) buffer.
static int PictureAllocARGB(WebPPicture* const picture) { static int PictureAllocARGB(WebPPicture* const picture) {
WebPPicture tmp; WebPPicture tmp;
free(picture->memory_argb_); WebPSafeFree(picture->memory_argb_);
PictureResetARGB(picture); PictureResetARGB(picture);
picture->use_argb = 1; picture->use_argb = 1;
WebPPictureGrabSpecs(picture, &tmp); WebPPictureGrabSpecs(picture, &tmp);
@ -191,8 +191,8 @@ static int PictureAllocARGB(WebPPicture* const picture) {
// Release memory owned by 'picture' (both YUV and ARGB buffers). // Release memory owned by 'picture' (both YUV and ARGB buffers).
void WebPPictureFree(WebPPicture* picture) { void WebPPictureFree(WebPPicture* picture) {
if (picture != NULL) { if (picture != NULL) {
free(picture->memory_); WebPSafeFree(picture->memory_);
free(picture->memory_argb_); WebPSafeFree(picture->memory_argb_);
PictureResetYUVA(picture); PictureResetYUVA(picture);
PictureResetARGB(picture); PictureResetARGB(picture);
} }
@ -504,7 +504,7 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
AlphaMultiplyARGB(&tmp, 1); AlphaMultiplyARGB(&tmp, 1);
} }
WebPPictureFree(pic); WebPPictureFree(pic);
free(work); WebPSafeFree(work);
*pic = tmp; *pic = tmp;
return 1; return 1;
} }
@ -538,7 +538,7 @@ int WebPMemoryWrite(const uint8_t* data, size_t data_size,
if (w->size > 0) { if (w->size > 0) {
memcpy(new_mem, w->mem, w->size); memcpy(new_mem, w->mem, w->size);
} }
free(w->mem); WebPSafeFree(w->mem);
w->mem = new_mem; w->mem = new_mem;
// down-cast is ok, thanks to WebPSafeMalloc // down-cast is ok, thanks to WebPSafeMalloc
w->max_size = (size_t)next_max_size; w->max_size = (size_t)next_max_size;
@ -550,6 +550,15 @@ int WebPMemoryWrite(const uint8_t* data, size_t data_size,
return 1; return 1;
} }
void WebPMemoryWriterClear(WebPMemoryWriter* writer) {
if (writer != NULL) {
WebPSafeFree(writer->mem);
writer->mem = NULL;
writer->size = 0;
writer->max_size = 0;
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Detection of non-trivial transparency // Detection of non-trivial transparency
@ -1323,7 +1332,7 @@ static size_t Encode(const uint8_t* rgba, int width, int height, int stride,
ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic); ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);
WebPPictureFree(&pic); WebPPictureFree(&pic);
if (!ok) { if (!ok) {
free(wrt.mem); WebPMemoryWriterClear(&wrt);
*output = NULL; *output = NULL;
return 0; return 0;
} }

View File

@ -22,6 +22,7 @@
#include "./cost.h" #include "./cost.h"
#include "./vp8enci.h" #include "./vp8enci.h"
#include "../utils/utils.h"
#if !defined(DISABLE_TOKEN_BUFFER) #if !defined(DISABLE_TOKEN_BUFFER)
@ -51,7 +52,7 @@ void VP8TBufferClear(VP8TBuffer* const b) {
const VP8Tokens* p = b->pages_; const VP8Tokens* p = b->pages_;
while (p != NULL) { while (p != NULL) {
const VP8Tokens* const next = p->next_; const VP8Tokens* const next = p->next_;
free((void*)p); WebPSafeFree((void*)p);
p = next; p = next;
} }
VP8TBufferInit(b); VP8TBufferInit(b);
@ -59,7 +60,8 @@ void VP8TBufferClear(VP8TBuffer* const b) {
} }
static int TBufferNewPage(VP8TBuffer* const b) { static int TBufferNewPage(VP8TBuffer* const b) {
VP8Tokens* const page = b->error_ ? NULL : (VP8Tokens*)malloc(sizeof(*page)); VP8Tokens* const page =
b->error_ ? NULL : (VP8Tokens*)WebPSafeMalloc(1ULL, sizeof(*page));
if (page == NULL) { if (page == NULL) {
b->error_ = 1; b->error_ = 1;
return 0; return 0;
@ -228,7 +230,7 @@ int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
VP8PutBit(bw, bit, probas[token & 0x3fffu]); VP8PutBit(bw, bit, probas[token & 0x3fffu]);
} }
} }
if (final_pass) free((void*)p); if (final_pass) WebPSafeFree((void*)p);
p = next; p = next;
} }
if (final_pass) b->pages_ = NULL; if (final_pass) b->pages_ = NULL;

View File

@ -108,7 +108,7 @@ static int AnalyzeEntropy(const uint32_t* argb,
VP8LHistogram* nonpredicted = NULL; VP8LHistogram* nonpredicted = NULL;
VP8LHistogram* predicted = VP8LHistogram* predicted =
(VP8LHistogram*)malloc(2 * sizeof(*predicted)); (VP8LHistogram*)WebPSafeMalloc(2ULL, sizeof(*predicted));
if (predicted == NULL) return 0; if (predicted == NULL) return 0;
nonpredicted = predicted + 1; nonpredicted = predicted + 1;
@ -135,7 +135,7 @@ static int AnalyzeEntropy(const uint32_t* argb,
} }
*nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted); *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
*predicted_bits = VP8LHistogramEstimateBitsBulk(predicted); *predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
free(predicted); WebPSafeFree(predicted);
return 1; return 1;
} }
@ -228,7 +228,7 @@ static int GetHuffBitLengthsAndCodes(
End: End:
if (!ok) { if (!ok) {
free(mem_buf); WebPSafeFree(mem_buf);
// If one VP8LCreateHuffmanTree() above fails, we need to clean up behind. // If one VP8LCreateHuffmanTree() above fails, we need to clean up behind.
memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes)); memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
} }
@ -362,7 +362,7 @@ static int StoreFullHuffmanCode(VP8LBitWriter* const bw,
} }
ok = 1; ok = 1;
End: End:
free(tokens); WebPSafeFree(tokens);
return ok; return ok;
} }
@ -503,9 +503,9 @@ static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
ok = 1; ok = 1;
Error: Error:
free(histogram_image); WebPSafeFree(histogram_image);
VP8LClearBackwardRefs(&refs); VP8LClearBackwardRefs(&refs);
free(huffman_codes[0].codes); WebPSafeFree(huffman_codes[0].codes);
return ok; return ok;
} }
@ -532,8 +532,8 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
assert(histogram_bits <= MAX_HUFFMAN_BITS); assert(histogram_bits <= MAX_HUFFMAN_BITS);
if (histogram_image == NULL || histogram_symbols == NULL) { if (histogram_image == NULL || histogram_symbols == NULL) {
free(histogram_image); WebPSafeFree(histogram_image);
free(histogram_symbols); WebPSafeFree(histogram_symbols);
return 0; return 0;
} }
@ -559,7 +559,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
goto Error; goto Error;
} }
// Free combined histograms. // Free combined histograms.
free(histogram_image); WebPSafeFree(histogram_image);
histogram_image = NULL; histogram_image = NULL;
// Color Cache parameters. // Color Cache parameters.
@ -593,7 +593,7 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
VP8LSubSampleSize(width, histogram_bits), VP8LSubSampleSize(width, histogram_bits),
VP8LSubSampleSize(height, histogram_bits), VP8LSubSampleSize(height, histogram_bits),
quality); quality);
free(histogram_argb); WebPSafeFree(histogram_argb);
if (!ok) goto Error; if (!ok) goto Error;
} }
} }
@ -614,14 +614,14 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
ok = 1; ok = 1;
Error: Error:
free(histogram_image); WebPSafeFree(histogram_image);
VP8LClearBackwardRefs(&refs); VP8LClearBackwardRefs(&refs);
if (huffman_codes != NULL) { if (huffman_codes != NULL) {
free(huffman_codes->codes); WebPSafeFree(huffman_codes->codes);
free(huffman_codes); WebPSafeFree(huffman_codes);
} }
free(histogram_symbols); WebPSafeFree(histogram_symbols);
return ok; return ok;
} }
@ -637,7 +637,8 @@ static int EvalAndApplySubtractGreen(VP8LEncoder* const enc,
int i; int i;
const uint32_t* const argb = enc->argb_; const uint32_t* const argb = enc->argb_;
double bit_cost_before, bit_cost_after; double bit_cost_before, bit_cost_after;
VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo)); VP8LHistogram* const histo =
(VP8LHistogram*)WebPSafeMalloc(1ULL, sizeof(*histo));
if (histo == NULL) return 0; if (histo == NULL) return 0;
VP8LHistogramInit(histo, 1); VP8LHistogramInit(histo, 1);
@ -656,7 +657,7 @@ static int EvalAndApplySubtractGreen(VP8LEncoder* const enc,
++histo->blue_[((c >> 0) - green) & 0xff]; ++histo->blue_[((c >> 0) - green) & 0xff];
} }
bit_cost_after = VP8LHistogramEstimateBits(histo); bit_cost_after = VP8LHistogramEstimateBits(histo);
free(histo); WebPSafeFree(histo);
// Check if subtracting green yields low entropy. // Check if subtracting green yields low entropy.
enc->use_subtract_green_ = (bit_cost_after < bit_cost_before); enc->use_subtract_green_ = (bit_cost_after < bit_cost_before);
@ -907,7 +908,7 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
} }
Error: Error:
free(row); WebPSafeFree(row);
return err; return err;
} }
@ -944,7 +945,7 @@ static void FinishEncParams(VP8LEncoder* const enc) {
static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config, static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
const WebPPicture* const picture) { const WebPPicture* const picture) {
VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc)); VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc));
if (enc == NULL) { if (enc == NULL) {
WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
return NULL; return NULL;
@ -959,9 +960,9 @@ static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
static void VP8LEncoderDelete(VP8LEncoder* enc) { static void VP8LEncoderDelete(VP8LEncoder* enc) {
if (enc != NULL) { if (enc != NULL) {
free(enc->argb_); WebPSafeFree(enc->argb_);
WebPSafeFree(enc);
} }
free(enc);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -269,7 +269,7 @@ static int DeleteVP8Encoder(VP8Encoder* enc) {
VP8EncDeleteLayer(enc); VP8EncDeleteLayer(enc);
#endif #endif
VP8TBufferClear(&enc->tokens_); VP8TBufferClear(&enc->tokens_);
free(enc); WebPSafeFree(enc);
} }
return ok; return ok;
} }

View File

@ -28,7 +28,7 @@ WebPMux* WebPNewInternal(int version) {
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) { if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) {
return NULL; return NULL;
} else { } else {
WebPMux* const mux = (WebPMux*)malloc(sizeof(WebPMux)); WebPMux* const mux = (WebPMux*)WebPSafeMalloc(1ULL, sizeof(WebPMux));
// If mux is NULL MuxInit is a noop. // If mux is NULL MuxInit is a noop.
MuxInit(mux); MuxInit(mux);
return mux; return mux;
@ -56,7 +56,7 @@ static void MuxRelease(WebPMux* const mux) {
void WebPMuxDelete(WebPMux* mux) { void WebPMuxDelete(WebPMux* mux) {
// If mux is NULL MuxRelease is a noop. // If mux is NULL MuxRelease is a noop.
MuxRelease(mux); MuxRelease(mux);
free(mux); WebPSafeFree(mux);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -102,7 +102,7 @@ static WebPMuxError CreateFrameFragmentData(
assert(info->dispose_method == (info->dispose_method & 1)); assert(info->dispose_method == (info->dispose_method & 1));
// Note: assertion on upper bounds is done in PutLE24(). // Note: assertion on upper bounds is done in PutLE24().
frame_frgm_bytes = (uint8_t*)malloc(frame_frgm_size); frame_frgm_bytes = (uint8_t*)WebPSafeMalloc(1ULL, frame_frgm_size);
if (frame_frgm_bytes == NULL) return WEBP_MUX_MEMORY_ERROR; if (frame_frgm_bytes == NULL) return WEBP_MUX_MEMORY_ERROR;
PutLE24(frame_frgm_bytes + 0, info->x_offset / 2); PutLE24(frame_frgm_bytes + 0, info->x_offset / 2);
@ -619,7 +619,7 @@ WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) {
+ ChunkListDiskSize(mux->exif_) + ChunkListDiskSize(mux->xmp_) + ChunkListDiskSize(mux->exif_) + ChunkListDiskSize(mux->xmp_)
+ ChunkListDiskSize(mux->unknown_) + RIFF_HEADER_SIZE; + ChunkListDiskSize(mux->unknown_) + RIFF_HEADER_SIZE;
data = (uint8_t*)malloc(size); data = (uint8_t*)WebPSafeMalloc(1ULL, size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR; if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
// Emit header & chunks. // Emit header & chunks.
@ -636,7 +636,7 @@ WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) {
// Validate mux. // Validate mux.
err = MuxValidate(mux); err = MuxValidate(mux);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
free(data); WebPSafeFree(data);
data = NULL; data = NULL;
size = 0; size = 0;
} }

View File

@ -165,7 +165,7 @@ WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
return WEBP_MUX_NOT_FOUND; return WEBP_MUX_NOT_FOUND;
} }
new_chunk = (WebPChunk*)malloc(sizeof(*new_chunk)); new_chunk = (WebPChunk*)WebPSafeMalloc(1ULL, sizeof(*new_chunk));
if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR; if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR;
*new_chunk = *chunk; *new_chunk = *chunk;
chunk->owner_ = 0; chunk->owner_ = 0;
@ -179,7 +179,7 @@ WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
WebPChunk* ChunkDelete(WebPChunk* const chunk) { WebPChunk* ChunkDelete(WebPChunk* const chunk) {
WebPChunk* const next = ChunkRelease(chunk); WebPChunk* const next = ChunkRelease(chunk);
free(chunk); WebPSafeFree(chunk);
return next; return next;
} }
@ -312,7 +312,7 @@ WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) {
wpi_list = &cur_wpi->next_; wpi_list = &cur_wpi->next_;
} }
new_wpi = (WebPMuxImage*)malloc(sizeof(*new_wpi)); new_wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*new_wpi));
if (new_wpi == NULL) return WEBP_MUX_MEMORY_ERROR; if (new_wpi == NULL) return WEBP_MUX_MEMORY_ERROR;
*new_wpi = *wpi; *new_wpi = *wpi;
new_wpi->next_ = NULL; new_wpi->next_ = NULL;
@ -331,7 +331,7 @@ WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) {
WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) { WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) {
// Delete the components of wpi. If wpi is NULL this is a noop. // Delete the components of wpi. If wpi is NULL this is a noop.
WebPMuxImage* const next = MuxImageRelease(wpi); WebPMuxImage* const next = MuxImageRelease(wpi);
free(wpi); WebPSafeFree(wpi);
return next; return next;
} }

View File

@ -220,7 +220,7 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
data += RIFF_HEADER_SIZE; data += RIFF_HEADER_SIZE;
size -= RIFF_HEADER_SIZE; size -= RIFF_HEADER_SIZE;
wpi = (WebPMuxImage*)malloc(sizeof(*wpi)); wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*wpi));
if (wpi == NULL) goto Err; if (wpi == NULL) goto Err;
MuxImageInit(wpi); MuxImageInit(wpi);
@ -375,7 +375,7 @@ static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi,
// Note: No need to output ANMF/FRGM chunk for a single image. // Note: No need to output ANMF/FRGM chunk for a single image.
const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size + const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size +
ChunkDiskSize(wpi->img_); ChunkDiskSize(wpi->img_);
uint8_t* const data = (uint8_t*)malloc(size); uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR; if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
// Main RIFF header. // Main RIFF header.

View File

@ -15,7 +15,9 @@
#include <assert.h> #include <assert.h>
#include <string.h> // for memcpy() #include <string.h> // for memcpy()
#include <stdlib.h> #include <stdlib.h>
#include "./bit_writer.h" #include "./bit_writer.h"
#include "./utils.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// VP8BitWriter // VP8BitWriter
@ -34,7 +36,7 @@ static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) {
new_size = 2 * bw->max_pos_; new_size = 2 * bw->max_pos_;
if (new_size < needed_size) new_size = needed_size; if (new_size < needed_size) new_size = needed_size;
if (new_size < 1024) new_size = 1024; if (new_size < 1024) new_size = 1024;
new_buf = (uint8_t*)malloc(new_size); new_buf = (uint8_t*)WebPSafeMalloc(1ULL, new_size);
if (new_buf == NULL) { if (new_buf == NULL) {
bw->error_ = 1; bw->error_ = 1;
return 0; return 0;
@ -43,7 +45,7 @@ static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) {
assert(bw->buf_ != NULL); assert(bw->buf_ != NULL);
memcpy(new_buf, bw->buf_, bw->pos_); memcpy(new_buf, bw->buf_, bw->pos_);
} }
free(bw->buf_); WebPSafeFree(bw->buf_);
bw->buf_ = new_buf; bw->buf_ = new_buf;
bw->max_pos_ = new_size; bw->max_pos_ = new_size;
return 1; return 1;
@ -176,7 +178,7 @@ uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) {
int VP8BitWriterAppend(VP8BitWriter* const bw, int VP8BitWriterAppend(VP8BitWriter* const bw,
const uint8_t* data, size_t size) { const uint8_t* data, size_t size) {
assert(data); assert(data != NULL);
if (bw->nb_bits_ != -8) return 0; // kFlush() must have been called if (bw->nb_bits_ != -8) return 0; // kFlush() must have been called
if (!BitWriterResize(bw, size)) return 0; if (!BitWriterResize(bw, size)) return 0;
memcpy(bw->buf_ + bw->pos_, data, size); memcpy(bw->buf_ + bw->pos_, data, size);
@ -185,8 +187,8 @@ int VP8BitWriterAppend(VP8BitWriter* const bw,
} }
void VP8BitWriterWipeOut(VP8BitWriter* const bw) { void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
if (bw) { if (bw != NULL) {
free(bw->buf_); WebPSafeFree(bw->buf_);
memset(bw, 0, sizeof(*bw)); memset(bw, 0, sizeof(*bw));
} }
} }
@ -245,7 +247,7 @@ static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
if (allocated_size < size_required) allocated_size = size_required; if (allocated_size < size_required) allocated_size = size_required;
// make allocated size multiple of 1k // make allocated size multiple of 1k
allocated_size = (((allocated_size >> 10) + 1) << 10); allocated_size = (((allocated_size >> 10) + 1) << 10);
allocated_buf = (uint8_t*)malloc(allocated_size); allocated_buf = (uint8_t*)WebPSafeMalloc(1ULL, allocated_size);
if (allocated_buf == NULL) { if (allocated_buf == NULL) {
bw->error_ = 1; bw->error_ = 1;
return 0; return 0;
@ -253,7 +255,7 @@ static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
if (current_size > 0) { if (current_size > 0) {
memcpy(allocated_buf, bw->buf_, current_size); memcpy(allocated_buf, bw->buf_, current_size);
} }
free(bw->buf_); WebPSafeFree(bw->buf_);
bw->buf_ = allocated_buf; bw->buf_ = allocated_buf;
bw->cur_ = bw->buf_ + current_size; bw->cur_ = bw->buf_ + current_size;
bw->end_ = bw->buf_ + allocated_size; bw->end_ = bw->buf_ + allocated_size;
@ -267,7 +269,7 @@ int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) {
void VP8LBitWriterDestroy(VP8LBitWriter* const bw) { void VP8LBitWriterDestroy(VP8LBitWriter* const bw) {
if (bw != NULL) { if (bw != NULL) {
free(bw->buf_); WebPSafeFree(bw->buf_);
memset(bw, 0, sizeof(*bw)); memset(bw, 0, sizeof(*bw));
} }
} }
@ -307,4 +309,3 @@ uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -32,7 +32,7 @@ int VP8LColorCacheInit(VP8LColorCache* const cc, int hash_bits) {
void VP8LColorCacheClear(VP8LColorCache* const cc) { void VP8LColorCacheClear(VP8LColorCache* const cc) {
if (cc != NULL) { if (cc != NULL) {
free(cc->colors_); WebPSafeFree(cc->colors_);
cc->colors_ = NULL; cc->colors_ = NULL;
} }
} }

View File

@ -66,7 +66,7 @@ static int TreeInit(HuffmanTree* const tree, int num_leaves) {
void HuffmanTreeRelease(HuffmanTree* const tree) { void HuffmanTreeRelease(HuffmanTree* const tree) {
if (tree != NULL) { if (tree != NULL) {
free(tree->root_); WebPSafeFree(tree->root_);
tree->root_ = NULL; tree->root_ = NULL;
tree->max_nodes_ = 0; tree->max_nodes_ = 0;
tree->num_nodes_ = 0; tree->num_nodes_ = 0;
@ -245,7 +245,7 @@ int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
} }
ok = 1; ok = 1;
End: End:
free(codes); WebPSafeFree(codes);
ok = ok && IsFull(tree); ok = ok && IsFull(tree);
if (!ok) HuffmanTreeRelease(tree); if (!ok) HuffmanTreeRelease(tree);
return ok; return ok;

View File

@ -43,7 +43,7 @@ static int OptimizeHuffmanForRle(int length, int* const counts) {
} }
// 2) Let's mark all population counts that already can be encoded // 2) Let's mark all population counts that already can be encoded
// with an rle code. // with an rle code.
good_for_rle = (uint8_t*)calloc(length, 1); good_for_rle = (uint8_t*)WebPSafeCalloc(1ULL, length);
if (good_for_rle == NULL) { if (good_for_rle == NULL) {
return 0; return 0;
} }
@ -119,7 +119,7 @@ static int OptimizeHuffmanForRle(int length, int* const counts) {
} }
} }
} }
free(good_for_rle); WebPSafeFree(good_for_rle);
return 1; return 1;
} }
@ -272,7 +272,7 @@ static int GenerateOptimalTree(const int* const histogram, int histogram_size,
} }
} }
} }
free(tree); WebPSafeFree(tree);
return 1; return 1;
} }

View File

@ -38,5 +38,8 @@ void* WebPSafeCalloc(uint64_t nmemb, size_t size) {
return calloc((size_t)nmemb, size); return calloc((size_t)nmemb, size);
} }
//------------------------------------------------------------------------------ void WebPSafeFree(void* const ptr) {
free(ptr);
}
//------------------------------------------------------------------------------

View File

@ -40,6 +40,9 @@ void* WebPSafeMalloc(uint64_t nmemb, size_t size);
// in order to favor the "calloc(num_foo, sizeof(foo))" pattern. // in order to favor the "calloc(num_foo, sizeof(foo))" pattern.
void* WebPSafeCalloc(uint64_t nmemb, size_t size); void* WebPSafeCalloc(uint64_t nmemb, size_t size);
// Companion deallocation function to the above allocations.
void WebPSafeFree(void* const ptr);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Reading/writing data. // Reading/writing data.

View File

@ -20,7 +20,7 @@
extern "C" { extern "C" {
#endif #endif
#define WEBP_ENCODER_ABI_VERSION 0x0203 // MAJOR(8b) + MINOR(8b) #define WEBP_ENCODER_ABI_VERSION 0x0204 // MAJOR(8b) + MINOR(8b)
// Note: forward declaring enumerations is not allowed in (strict) C and C++, // Note: forward declaring enumerations is not allowed in (strict) C and C++,
// the types are left here for reference. // the types are left here for reference.
@ -229,9 +229,12 @@ struct WebPMemoryWriter {
// The following must be called first before any use. // The following must be called first before any use.
WEBP_EXTERN(void) WebPMemoryWriterInit(WebPMemoryWriter* writer); WEBP_EXTERN(void) WebPMemoryWriterInit(WebPMemoryWriter* writer);
// The following must be called to deallocate writer->mem memory. The 'writer'
// object itself is not deallocated.
WEBP_EXTERN(void) WebPMemoryWriterClear(WebPMemoryWriter* writer);
// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon // The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
// completion, writer.mem and writer.size will hold the coded data. // completion, writer.mem and writer.size will hold the coded data.
// writer.mem must be freed using the call 'free(writer.mem)'. // writer.mem must be freed by calling WebPMemoryWriterClear.
WEBP_EXTERN(int) WebPMemoryWrite(const uint8_t* data, size_t data_size, WEBP_EXTERN(int) WebPMemoryWrite(const uint8_t* data, size_t data_size,
const WebPPicture* picture); const WebPPicture* picture);