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.
WebPMemoryWriter wrt;
WebPMemoryWriterInit(&wrt); // initialize 'wrt'
pic.writer = MyFileWriter;
pic.custom_ptr = my_opaque_structure_to_make_MyFileWriter_work;
// initialize 'wrt' here...
// Compress!
int ok = WebPEncode(&config, &pic); // ok = 0 => error occurred!
WebPPictureFree(&pic); // must be called independently of the 'ok' result.
// 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

View File

@ -1121,7 +1121,7 @@ int main(int argc, const char *argv[]) {
return_value = 0;
Error:
free(memory_writer.mem);
WebPMemoryWriterClear(&memory_writer);
free(picture.extra_info);
MetadataFree(&metadata);
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
// also be a criteria, in addition to sizes.
if (mem1.size <= mem2.size) {
free(mem2.mem);
WebPMemoryWriterClear(&mem2);
GetEncodedData(&mem1, encoded_data);
} else {
free(mem1.mem);
WebPMemoryWriterClear(&mem1);
GetEncodedData(&mem2, encoded_data);
}
} else {
@ -481,8 +481,8 @@ static int SetFrame(const WebPConfig* const config, int allow_mixed,
return 1;
Err:
free(mem1.mem);
free(mem2.mem);
WebPMemoryWriterClear(&mem1);
WebPMemoryWriterClear(&mem2);
return 0;
}

View File

@ -16,13 +16,14 @@
#include "./vp8i.h"
#include "./vp8li.h"
#include "../utils/quant_levels_dec.h"
#include "../utils/utils.h"
#include "../webp/format_constants.h"
//------------------------------------------------------------------------------
// ALPHDecoder object.
ALPHDecoder* ALPHNew(void) {
ALPHDecoder* const dec = (ALPHDecoder*)calloc(1, sizeof(*dec));
ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
return dec;
}
@ -30,7 +31,7 @@ void ALPHDelete(ALPHDecoder* const dec) {
if (dec != NULL) {
VP8LDelete(dec->vp8l_dec_);
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 dec->alpha_plane_ + row * width;
}

View File

@ -216,8 +216,9 @@ int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
if (buffer != NULL) {
if (!buffer->is_external_memory)
free(buffer->private_memory);
if (!buffer->is_external_memory) {
WebPSafeFree(buffer->private_memory);
}
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 > dec->mem_size_) {
free(dec->mem_);
WebPSafeFree(dec->mem_);
dec->mem_size_ = 0;
dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t));
if (dec->mem_ == NULL) {

View File

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

View File

@ -17,6 +17,7 @@
#include "./webpi.h"
#include "../dsp/dsp.h"
#include "../dsp/yuv.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------
// Main YUV<->RGB conversion functions
@ -324,7 +325,7 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
if (has_alpha) {
tmp_size += work_size;
}
p->memory = calloc(1, tmp_size * sizeof(*work));
p->memory = WebPSafeCalloc(1ULL, tmp_size * sizeof(*work));
if (p->memory == NULL) {
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
int32_t* work; // rescalers work area
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_size2 = 3 * out_width;
@ -500,7 +501,8 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
tmp_size1 += work_size;
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) {
return 0; // memory error
}
@ -564,7 +566,7 @@ static int CustomSetup(VP8Io* io) {
if (io->fancy_upsampling) {
#ifdef FANCY_UPSAMPLING
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) {
return 0; // memory error.
}
@ -620,7 +622,7 @@ static int CustomPut(const VP8Io* io) {
static void CustomTeardown(const VP8Io* io) {
WebPDecParams* const p = (WebPDecParams*)io->opaque;
free(p->memory);
WebPSafeFree(p->memory);
p->memory = NULL;
}

View File

@ -18,6 +18,7 @@
#include "./vp8li.h"
#include "./webpi.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* const dec = (VP8Decoder*)calloc(1, sizeof(*dec));
VP8Decoder* const dec = (VP8Decoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec != NULL) {
SetOk(dec);
WebPWorkerInit(&dec->worker_);
@ -68,7 +69,7 @@ const char* VP8StatusMessage(VP8Decoder* const dec) {
void VP8Delete(VP8Decoder* const dec) {
if (dec != NULL) {
VP8Clear(dec);
free(dec);
WebPSafeFree(dec);
}
}
@ -689,7 +690,7 @@ void VP8Clear(VP8Decoder* const dec) {
}
ALPHDelete(dec->alph_dec_);
dec->alph_dec_ = NULL;
free(dec->mem_);
WebPSafeFree(dec->mem_);
dec->mem_ = NULL;
dec->mem_size_ = 0;
memset(&dec->br_, 0, sizeof(dec->br_));

View File

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

View File

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

View File

@ -17,6 +17,7 @@
#include "./vp8enci.h"
#include "../utils/filters.h"
#include "../utils/quant_levels.h"
#include "../utils/utils.h"
#include "../webp/format_constants.h"
// -----------------------------------------------------------------------------
@ -34,7 +35,7 @@
//
// 'output' corresponds to the buffer containing compressed alpha data.
// 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.
//
// 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);
InitFilterTrial(&best);
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;
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 {
ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE,
reduce_levels, effort_level, NULL, &best);
@ -298,7 +299,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
filter = WEBP_FILTER_NONE;
}
quant_alpha = (uint8_t*)malloc(data_size);
quant_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
if (quant_alpha == NULL) {
return 0;
}
@ -325,7 +326,7 @@ static int EncodeAlpha(VP8Encoder* const enc,
}
}
free(quant_alpha);
WebPSafeFree(quant_alpha);
return ok;
}
@ -346,7 +347,7 @@ static int CompressAlphaJob(VP8Encoder* const enc, void* dummy) {
return 0;
}
if (alpha_size != (uint32_t)alpha_size) { // Sanity check.
free(alpha_data);
WebPSafeFree(alpha_data);
return 0;
}
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
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_size_ = 0;
enc->has_alpha_ = 0;

View File

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

View File

@ -162,7 +162,7 @@ static int Record(int bit, proba_t* const stats) {
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
// 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.
const int bin_depth = histo_image_raw_size + 1;
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 =
VP8LAllocateHistogramSet(histo_image_raw_size, cache_bits);
@ -760,8 +761,8 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
ok = 1;
Error:
free(bin_map);
free(init_histo);
free(histos);
WebPSafeFree(bin_map);
WebPSafeFree(init_histo);
WebPSafeFree(histos);
return ok;
}

View File

@ -46,7 +46,7 @@ typedef struct {
} VP8LHistogram;
// 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 {
int size; // number of slots currently in use
int max_size; // maximum capacity

View File

@ -14,6 +14,7 @@
#include <stdlib.h>
#include "./vp8enci.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------
@ -39,6 +40,5 @@ int VP8EncFinishLayer(VP8Encoder* const 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.
static int PictureAllocARGB(WebPPicture* const picture) {
WebPPicture tmp;
free(picture->memory_argb_);
WebPSafeFree(picture->memory_argb_);
PictureResetARGB(picture);
picture->use_argb = 1;
WebPPictureGrabSpecs(picture, &tmp);
@ -191,8 +191,8 @@ static int PictureAllocARGB(WebPPicture* const picture) {
// Release memory owned by 'picture' (both YUV and ARGB buffers).
void WebPPictureFree(WebPPicture* picture) {
if (picture != NULL) {
free(picture->memory_);
free(picture->memory_argb_);
WebPSafeFree(picture->memory_);
WebPSafeFree(picture->memory_argb_);
PictureResetYUVA(picture);
PictureResetARGB(picture);
}
@ -504,7 +504,7 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
AlphaMultiplyARGB(&tmp, 1);
}
WebPPictureFree(pic);
free(work);
WebPSafeFree(work);
*pic = tmp;
return 1;
}
@ -538,7 +538,7 @@ int WebPMemoryWrite(const uint8_t* data, size_t data_size,
if (w->size > 0) {
memcpy(new_mem, w->mem, w->size);
}
free(w->mem);
WebPSafeFree(w->mem);
w->mem = new_mem;
// down-cast is ok, thanks to WebPSafeMalloc
w->max_size = (size_t)next_max_size;
@ -550,6 +550,15 @@ int WebPMemoryWrite(const uint8_t* data, size_t data_size,
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
@ -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);
WebPPictureFree(&pic);
if (!ok) {
free(wrt.mem);
WebPMemoryWriterClear(&wrt);
*output = NULL;
return 0;
}

View File

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

View File

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

View File

@ -28,7 +28,7 @@ WebPMux* WebPNewInternal(int version) {
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) {
return NULL;
} else {
WebPMux* const mux = (WebPMux*)malloc(sizeof(WebPMux));
WebPMux* const mux = (WebPMux*)WebPSafeMalloc(1ULL, sizeof(WebPMux));
// If mux is NULL MuxInit is a noop.
MuxInit(mux);
return mux;
@ -56,7 +56,7 @@ static void MuxRelease(WebPMux* const mux) {
void WebPMuxDelete(WebPMux* mux) {
// If mux is NULL MuxRelease is a noop.
MuxRelease(mux);
free(mux);
WebPSafeFree(mux);
}
//------------------------------------------------------------------------------
@ -102,7 +102,7 @@ static WebPMuxError CreateFrameFragmentData(
assert(info->dispose_method == (info->dispose_method & 1));
// 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;
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->unknown_) + RIFF_HEADER_SIZE;
data = (uint8_t*)malloc(size);
data = (uint8_t*)WebPSafeMalloc(1ULL, size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
// Emit header & chunks.
@ -636,7 +636,7 @@ WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) {
// Validate mux.
err = MuxValidate(mux);
if (err != WEBP_MUX_OK) {
free(data);
WebPSafeFree(data);
data = NULL;
size = 0;
}

View File

@ -165,7 +165,7 @@ WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
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;
*new_chunk = *chunk;
chunk->owner_ = 0;
@ -179,7 +179,7 @@ WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
WebPChunk* ChunkDelete(WebPChunk* const chunk) {
WebPChunk* const next = ChunkRelease(chunk);
free(chunk);
WebPSafeFree(chunk);
return next;
}
@ -312,7 +312,7 @@ WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) {
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;
*new_wpi = *wpi;
new_wpi->next_ = NULL;
@ -331,7 +331,7 @@ WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) {
WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) {
// Delete the components of wpi. If wpi is NULL this is a noop.
WebPMuxImage* const next = MuxImageRelease(wpi);
free(wpi);
WebPSafeFree(wpi);
return next;
}

View File

@ -220,7 +220,7 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
data += RIFF_HEADER_SIZE;
size -= RIFF_HEADER_SIZE;
wpi = (WebPMuxImage*)malloc(sizeof(*wpi));
wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*wpi));
if (wpi == NULL) goto Err;
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.
const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size +
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;
// Main RIFF header.

View File

@ -15,7 +15,9 @@
#include <assert.h>
#include <string.h> // for memcpy()
#include <stdlib.h>
#include "./bit_writer.h"
#include "./utils.h"
//------------------------------------------------------------------------------
// VP8BitWriter
@ -34,7 +36,7 @@ static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) {
new_size = 2 * bw->max_pos_;
if (new_size < needed_size) new_size = needed_size;
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) {
bw->error_ = 1;
return 0;
@ -43,7 +45,7 @@ static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) {
assert(bw->buf_ != NULL);
memcpy(new_buf, bw->buf_, bw->pos_);
}
free(bw->buf_);
WebPSafeFree(bw->buf_);
bw->buf_ = new_buf;
bw->max_pos_ = new_size;
return 1;
@ -176,7 +178,7 @@ uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) {
int VP8BitWriterAppend(VP8BitWriter* const bw,
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 (!BitWriterResize(bw, size)) return 0;
memcpy(bw->buf_ + bw->pos_, data, size);
@ -185,8 +187,8 @@ int VP8BitWriterAppend(VP8BitWriter* const bw,
}
void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
if (bw) {
free(bw->buf_);
if (bw != NULL) {
WebPSafeFree(bw->buf_);
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;
// make allocated size multiple of 1k
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) {
bw->error_ = 1;
return 0;
@ -253,7 +255,7 @@ static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
if (current_size > 0) {
memcpy(allocated_buf, bw->buf_, current_size);
}
free(bw->buf_);
WebPSafeFree(bw->buf_);
bw->buf_ = allocated_buf;
bw->cur_ = bw->buf_ + current_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) {
if (bw != NULL) {
free(bw->buf_);
WebPSafeFree(bw->buf_);
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) {
if (cc != NULL) {
free(cc->colors_);
WebPSafeFree(cc->colors_);
cc->colors_ = NULL;
}
}

View File

@ -66,7 +66,7 @@ static int TreeInit(HuffmanTree* const tree, int num_leaves) {
void HuffmanTreeRelease(HuffmanTree* const tree) {
if (tree != NULL) {
free(tree->root_);
WebPSafeFree(tree->root_);
tree->root_ = NULL;
tree->max_nodes_ = 0;
tree->num_nodes_ = 0;
@ -245,7 +245,7 @@ int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
}
ok = 1;
End:
free(codes);
WebPSafeFree(codes);
ok = ok && IsFull(tree);
if (!ok) HuffmanTreeRelease(tree);
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
// 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) {
return 0;
}
@ -119,7 +119,7 @@ static int OptimizeHuffmanForRle(int length, int* const counts) {
}
}
}
free(good_for_rle);
WebPSafeFree(good_for_rle);
return 1;
}
@ -272,7 +272,7 @@ static int GenerateOptimalTree(const int* const histogram, int histogram_size,
}
}
}
free(tree);
WebPSafeFree(tree);
return 1;
}

View File

@ -38,5 +38,8 @@ void* WebPSafeCalloc(uint64_t nmemb, size_t 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.
void* WebPSafeCalloc(uint64_t nmemb, size_t size);
// Companion deallocation function to the above allocations.
void WebPSafeFree(void* const ptr);
//------------------------------------------------------------------------------
// Reading/writing data.

View File

@ -20,7 +20,7 @@
extern "C" {
#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++,
// the types are left here for reference.
@ -229,9 +229,12 @@ struct WebPMemoryWriter {
// The following must be called first before any use.
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
// 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,
const WebPPicture* picture);