Path: blob/master/thirdparty/libwebp/src/utils/utils.c
20897 views
// Copyright 2012 Google Inc. All Rights Reserved.1//2// Use of this source code is governed by a BSD-style license3// that can be found in the COPYING file in the root of the source4// tree. An additional intellectual property rights grant can be found5// in the file PATENTS. All contributing project authors may6// be found in the AUTHORS file in the root of the source tree.7// -----------------------------------------------------------------------------8//9// Misc. common utility functions10//11// Author: Skal ([email protected])1213#include "src/utils/utils.h"1415#include <assert.h>16#include <stdlib.h>17#include <string.h> // for memcpy()1819#include "src/webp/types.h"20#include "src/utils/palette.h"21#include "src/webp/encode.h"2223// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of24// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow,25// and not multi-thread safe!).26// An interesting alternative is valgrind's 'massif' tool:27// https://valgrind.org/docs/manual/ms-manual.html28// Here is an example command line:29/* valgrind --tool=massif --massif-out-file=massif.out \30--stacks=yes --alloc-fn=WebPSafeMalloc --alloc-fn=WebPSafeCalloc31ms_print massif.out32*/33// In addition:34// * if PRINT_MEM_TRAFFIC is defined, all the details of the malloc/free cycles35// are printed.36// * if MALLOC_FAIL_AT is defined, the global environment variable37// $MALLOC_FAIL_AT is used to simulate a memory error when calloc or malloc38// is called for the nth time. Example usage:39// export MALLOC_FAIL_AT=50 && ./examples/cwebp input.png40// * if MALLOC_LIMIT is defined, the global environment variable $MALLOC_LIMIT41// sets the maximum amount of memory (in bytes) made available to libwebp.42// This can be used to emulate environment with very limited memory.43// Example: export MALLOC_LIMIT=64000000 && ./examples/dwebp picture.webp4445// #define PRINT_MEM_INFO46// #define PRINT_MEM_TRAFFIC47// #define MALLOC_FAIL_AT48// #define MALLOC_LIMIT4950//------------------------------------------------------------------------------51// Checked memory allocation5253#if defined(PRINT_MEM_INFO)5455#include <stdio.h>5657static int num_malloc_calls = 0;58static int num_calloc_calls = 0;59static int num_free_calls = 0;60static int countdown_to_fail = 0; // 0 = off6162typedef struct MemBlock MemBlock;63struct MemBlock {64void* ptr;65size_t size;66MemBlock* next;67};6869static MemBlock* all_blocks = NULL;70static size_t total_mem = 0;71static size_t total_mem_allocated = 0;72static size_t high_water_mark = 0;73static size_t mem_limit = 0;7475static int exit_registered = 0;7677static void PrintMemInfo(void) {78fprintf(stderr, "\nMEMORY INFO:\n");79fprintf(stderr, "num calls to: malloc = %4d\n", num_malloc_calls);80fprintf(stderr, " calloc = %4d\n", num_calloc_calls);81fprintf(stderr, " free = %4d\n", num_free_calls);82fprintf(stderr, "total_mem: %u\n", (uint32_t)total_mem);83fprintf(stderr, "total_mem allocated: %u\n", (uint32_t)total_mem_allocated);84fprintf(stderr, "high-water mark: %u\n", (uint32_t)high_water_mark);85while (all_blocks != NULL) {86MemBlock* b = all_blocks;87all_blocks = b->next;88free(b);89}90}9192static void Increment(int* const v) {93if (!exit_registered) {94#if defined(MALLOC_FAIL_AT)95{96const char* const malloc_fail_at_str = getenv("MALLOC_FAIL_AT");97if (malloc_fail_at_str != NULL) {98countdown_to_fail = atoi(malloc_fail_at_str);99}100}101#endif102#if defined(MALLOC_LIMIT)103{104const char* const malloc_limit_str = getenv("MALLOC_LIMIT");105#if MALLOC_LIMIT > 1106mem_limit = (size_t)MALLOC_LIMIT;107#endif108if (malloc_limit_str != NULL) {109mem_limit = atoi(malloc_limit_str);110}111}112#endif113(void)countdown_to_fail;114(void)mem_limit;115atexit(PrintMemInfo);116exit_registered = 1;117}118++*v;119}120121static void AddMem(void* ptr, size_t size) {122if (ptr != NULL) {123MemBlock* const b = (MemBlock*)malloc(sizeof(*b));124if (b == NULL) abort();125b->next = all_blocks;126all_blocks = b;127b->ptr = ptr;128b->size = size;129total_mem += size;130total_mem_allocated += size;131#if defined(PRINT_MEM_TRAFFIC)132#if defined(MALLOC_FAIL_AT)133fprintf(stderr, "fail-count: %5d [mem=%u]\n",134num_malloc_calls + num_calloc_calls, (uint32_t)total_mem);135#else136fprintf(stderr, "Mem: %u (+%u)\n", (uint32_t)total_mem, (uint32_t)size);137#endif138#endif139if (total_mem > high_water_mark) high_water_mark = total_mem;140}141}142143static void SubMem(void* ptr) {144if (ptr != NULL) {145MemBlock** b = &all_blocks;146// Inefficient search, but that's just for debugging.147while (*b != NULL && (*b)->ptr != ptr) b = &(*b)->next;148if (*b == NULL) {149fprintf(stderr, "Invalid pointer free! (%p)\n", ptr);150abort();151}152{153MemBlock* const block = *b;154*b = block->next;155total_mem -= block->size;156#if defined(PRINT_MEM_TRAFFIC)157fprintf(stderr, "Mem: %u (-%u)\n",158(uint32_t)total_mem, (uint32_t)block->size);159#endif160free(block);161}162}163}164165#else166#define Increment(v) do {} while (0)167#define AddMem(p, s) do {} while (0)168#define SubMem(p) do {} while (0)169#endif170171// Returns 0 in case of overflow of nmemb * size.172static int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {173const uint64_t total_size = nmemb * size;174if (nmemb == 0) return 1;175if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0;176if (!CheckSizeOverflow(total_size)) return 0;177#if defined(PRINT_MEM_INFO) && defined(MALLOC_FAIL_AT)178if (countdown_to_fail > 0 && --countdown_to_fail == 0) {179return 0; // fake fail!180}181#endif182#if defined(PRINT_MEM_INFO) && defined(MALLOC_LIMIT)183if (mem_limit > 0) {184const uint64_t new_total_mem = (uint64_t)total_mem + total_size;185if (!CheckSizeOverflow(new_total_mem) ||186new_total_mem > mem_limit) {187return 0; // fake fail!188}189}190#endif191192return 1;193}194195void* WebPSafeMalloc(uint64_t nmemb, size_t size) {196void* ptr;197Increment(&num_malloc_calls);198if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;199assert(nmemb * size > 0);200ptr = malloc((size_t)(nmemb * size));201AddMem(ptr, (size_t)(nmemb * size));202return ptr;203}204205void* WebPSafeCalloc(uint64_t nmemb, size_t size) {206void* ptr;207Increment(&num_calloc_calls);208if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;209assert(nmemb * size > 0);210ptr = calloc((size_t)nmemb, size);211AddMem(ptr, (size_t)(nmemb * size));212return ptr;213}214215void WebPSafeFree(void* const ptr) {216if (ptr != NULL) {217Increment(&num_free_calls);218SubMem(ptr);219}220free(ptr);221}222223// Public API functions.224225void* WebPMalloc(size_t size) {226return WebPSafeMalloc(1, size);227}228229void WebPFree(void* ptr) {230WebPSafeFree(ptr);231}232233//------------------------------------------------------------------------------234235void WebPCopyPlane(const uint8_t* src, int src_stride,236uint8_t* dst, int dst_stride, int width, int height) {237assert(src != NULL && dst != NULL);238assert(abs(src_stride) >= width && abs(dst_stride) >= width);239while (height-- > 0) {240memcpy(dst, src, width);241src += src_stride;242dst += dst_stride;243}244}245246void WebPCopyPixels(const WebPPicture* const src, WebPPicture* const dst) {247assert(src != NULL && dst != NULL);248assert(src->width == dst->width && src->height == dst->height);249assert(src->use_argb && dst->use_argb);250WebPCopyPlane((uint8_t*)src->argb, 4 * src->argb_stride, (uint8_t*)dst->argb,2514 * dst->argb_stride, 4 * src->width, src->height);252}253254//------------------------------------------------------------------------------255256int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {257return GetColorPalette(pic, palette);258}259260//------------------------------------------------------------------------------261262#if defined(WEBP_NEED_LOG_TABLE_8BIT)263const uint8_t WebPLogTable8bit[256] = { // 31 ^ clz(i)2640, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,2654, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,2665, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,2675, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,2686, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,2696, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,2706, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,2716, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,2727, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,2737, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,2747, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,2757, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,2767, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,2777, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,2787, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,2797, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7280};281#endif282283//------------------------------------------------------------------------------284285286