1a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Copyright 2012 Google Inc. All Rights Reserved. 2a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// 30406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Use of this source code is governed by a BSD-style license 40406ce1417f76f2034833414dcecc9f56253640cVikas Arora// that can be found in the COPYING file in the root of the source 50406ce1417f76f2034833414dcecc9f56253640cVikas Arora// tree. An additional intellectual property rights grant can be found 60406ce1417f76f2034833414dcecc9f56253640cVikas Arora// in the file PATENTS. All contributing project authors may 70406ce1417f76f2034833414dcecc9f56253640cVikas Arora// be found in the AUTHORS file in the root of the source tree. 8a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// ----------------------------------------------------------------------------- 9a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// 10a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Misc. common utility functions 11a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// 12a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Author: Skal (pascal.massimino@gmail.com) 13a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 14a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include <stdlib.h> 15a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora#include "./utils.h" 16a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 1733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of 1833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow, 1933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// and not multi-thread safe!). 2033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// An interesting alternative is valgrind's 'massif' tool: 2133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// http://valgrind.org/docs/manual/ms-manual.html 2233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Here is an example command line: 2333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora/* valgrind --tool=massif --massif-out-file=massif.out \ 2433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora --stacks=yes --alloc-fn=WebPSafeAlloc --alloc-fn=WebPSafeCalloc 2533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora ms_print massif.out 2633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora*/ 2733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// In addition: 2833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// * if PRINT_MEM_TRAFFIC is defined, all the details of the malloc/free cycles 2933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// are printed. 3033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// * if MALLOC_FAIL_AT is defined, the global environment variable 3133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// $MALLOC_FAIL_AT is used to simulate a memory error when calloc or malloc 3233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// is called for the nth time. Example usage: 3333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// export MALLOC_FAIL_AT=50 && ./examples/cwebp input.png 3433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// * if MALLOC_LIMIT is defined, the global environment variable $MALLOC_LIMIT 3533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// sets the maximum amount of memory (in bytes) made available to libwebp. 3633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// This can be used to emulate environment with very limited memory. 3733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Example: export MALLOC_LIMIT=64000000 && ./examples/dwebp picture.webp 3833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 3933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// #define PRINT_MEM_INFO 4033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// #define PRINT_MEM_TRAFFIC 4133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// #define MALLOC_FAIL_AT 4233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// #define MALLOC_LIMIT 4333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 44a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------ 45a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Checked memory allocation 46a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 4733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(PRINT_MEM_INFO) 4833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 4933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include <stdio.h> 5033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include <stdlib.h> // for abort() 5133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 5233f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int num_malloc_calls = 0; 5333f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int num_calloc_calls = 0; 5433f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int num_free_calls = 0; 5533f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int countdown_to_fail = 0; // 0 = off 5633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 5733f74dabbc7920a65ed435d7417987589febdc16Vikas Aroratypedef struct MemBlock MemBlock; 5833f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastruct MemBlock { 5933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora void* ptr_; 6033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora size_t size_; 6133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora MemBlock* next_; 6233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}; 6333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 6433f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic MemBlock* all_blocks = NULL; 6533f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic size_t total_mem = 0; 6633f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic size_t total_mem_allocated = 0; 6733f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic size_t high_water_mark = 0; 6833f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic size_t mem_limit = 0; 6933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 7033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int exit_registered = 0; 7133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 7233f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void PrintMemInfo(void) { 7333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, "\nMEMORY INFO:\n"); 7433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, "num calls to: malloc = %4d\n", num_malloc_calls); 7533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, " calloc = %4d\n", num_calloc_calls); 7633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, " free = %4d\n", num_free_calls); 7733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, "total_mem: %u\n", (uint32_t)total_mem); 7833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, "total_mem allocated: %u\n", (uint32_t)total_mem_allocated); 7933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, "high-water mark: %u\n", (uint32_t)high_water_mark); 8033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora while (all_blocks != NULL) { 8133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora MemBlock* b = all_blocks; 8233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora all_blocks = b->next_; 8333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora free(b); 8433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 8533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora} 8633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 8733f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void Increment(int* const v) { 8833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (!exit_registered) { 8933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(MALLOC_FAIL_AT) 9033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora { 9133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora const char* const malloc_fail_at_str = getenv("MALLOC_FAIL_AT"); 9233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (malloc_fail_at_str != NULL) { 9333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora countdown_to_fail = atoi(malloc_fail_at_str); 9433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 9533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 9633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif 9733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(MALLOC_LIMIT) 9833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora { 9933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora const char* const malloc_limit_str = getenv("MALLOC_LIMIT"); 10033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (malloc_limit_str != NULL) { 10133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora mem_limit = atoi(malloc_limit_str); 10233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 10333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 10433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif 10533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora (void)countdown_to_fail; 10633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora (void)mem_limit; 10733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora atexit(PrintMemInfo); 10833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora exit_registered = 1; 10933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 11033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora ++*v; 11133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora} 11233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 11333f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void AddMem(void* ptr, size_t size) { 11433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (ptr != NULL) { 11533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora MemBlock* const b = (MemBlock*)malloc(sizeof(*b)); 11633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (b == NULL) abort(); 11733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora b->next_ = all_blocks; 11833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora all_blocks = b; 11933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora b->ptr_ = ptr; 12033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora b->size_ = size; 12133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora total_mem += size; 12233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora total_mem_allocated += size; 12333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(PRINT_MEM_TRAFFIC) 12433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(MALLOC_FAIL_AT) 12533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, "fail-count: %5d [mem=%u]\n", 12633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora num_malloc_calls + num_calloc_calls, (uint32_t)total_mem); 12733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#else 12833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, "Mem: %u (+%u)\n", (uint32_t)total_mem, (uint32_t)size); 12933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif 13033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif 13133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (total_mem > high_water_mark) high_water_mark = total_mem; 13233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 13333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora} 13433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 13533f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void SubMem(void* ptr) { 13633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (ptr != NULL) { 13733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora MemBlock** b = &all_blocks; 13833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora // Inefficient search, but that's just for debugging. 13933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora while (*b != NULL && (*b)->ptr_ != ptr) b = &(*b)->next_; 14033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (*b == NULL) { 14133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, "Invalid pointer free! (%p)\n", ptr); 14233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora abort(); 14333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 14433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora { 14533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora MemBlock* const block = *b; 14633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora *b = block->next_; 14733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora total_mem -= block->size_; 14833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(PRINT_MEM_TRAFFIC) 14933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora fprintf(stderr, "Mem: %u (-%u)\n", 15033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora (uint32_t)total_mem, (uint32_t)block->size_); 15133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif 15233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora free(block); 15333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 15433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 15533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora} 15633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 15733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#else 1588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define Increment(v) do {} while (0) 1598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define AddMem(p, s) do {} while (0) 1608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SubMem(p) do {} while (0) 16133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif 16233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 1631e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora// Returns 0 in case of overflow of nmemb * size. 1641e7bf8805bd030c19924a5306837ecd72c295751Vikas Arorastatic int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) { 165a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora const uint64_t total_size = nmemb * size; 166a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora if (nmemb == 0) return 1; 167a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0; 168a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora if (total_size != (size_t)total_size) return 0; 16933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(PRINT_MEM_INFO) && defined(MALLOC_FAIL_AT) 17033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (countdown_to_fail > 0 && --countdown_to_fail == 0) { 17133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora return 0; // fake fail! 17233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 17333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif 17433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(MALLOC_LIMIT) 17533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (mem_limit > 0 && total_mem + total_size >= mem_limit) { 17633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora return 0; // fake fail! 17733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 17833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif 17933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora 180a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora return 1; 181a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora} 182a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 183a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroravoid* WebPSafeMalloc(uint64_t nmemb, size_t size) { 18433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora void* ptr; 18533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora Increment(&num_malloc_calls); 1861e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL; 1871e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora assert(nmemb * size > 0); 18833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora ptr = malloc((size_t)(nmemb * size)); 18933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora AddMem(ptr, (size_t)(nmemb * size)); 19033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora return ptr; 191a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora} 192a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 193a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroravoid* WebPSafeCalloc(uint64_t nmemb, size_t size) { 19433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora void* ptr; 19533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora Increment(&num_calloc_calls); 1961e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL; 1971e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora assert(nmemb * size > 0); 19833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora ptr = calloc((size_t)nmemb, size); 19933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora AddMem(ptr, (size_t)(nmemb * size)); 20033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora return ptr; 201a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora} 202a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 20333f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid WebPSafeFree(void* const ptr) { 20433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora if (ptr != NULL) { 20533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora Increment(&num_free_calls); 20633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora SubMem(ptr); 20733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora } 20833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora free(ptr); 20933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora} 210a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 21133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------ 212