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 17af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of 18af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow, 19af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// and not multi-thread safe!). 20af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// An interesting alternative is valgrind's 'massif' tool: 21af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// http://valgrind.org/docs/manual/ms-manual.html 22af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Here is an example command line: 23af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora/* valgrind --tool=massif --massif-out-file=massif.out \ 24af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora --stacks=yes --alloc-fn=WebPSafeAlloc --alloc-fn=WebPSafeCalloc 25af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora ms_print massif.out 26af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora*/ 27af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// In addition: 28af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// * if PRINT_MEM_TRAFFIC is defined, all the details of the malloc/free cycles 29af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// are printed. 30af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// * if MALLOC_FAIL_AT is defined, the global environment variable 31af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// $MALLOC_FAIL_AT is used to simulate a memory error when calloc or malloc 32af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// is called for the nth time. Example usage: 33af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// export MALLOC_FAIL_AT=50 && ./examples/cwebp input.png 34af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// * if MALLOC_LIMIT is defined, the global environment variable $MALLOC_LIMIT 35af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// sets the maximum amount of memory (in bytes) made available to libwebp. 36af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// This can be used to emulate environment with very limited memory. 37af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// Example: export MALLOC_LIMIT=64000000 && ./examples/dwebp picture.webp 38af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 39af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// #define PRINT_MEM_INFO 40af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// #define PRINT_MEM_TRAFFIC 41af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// #define MALLOC_FAIL_AT 42af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora// #define MALLOC_LIMIT 43af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 44a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora//------------------------------------------------------------------------------ 45a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora// Checked memory allocation 46a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 47af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(PRINT_MEM_INFO) 48af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 49af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#include <stdio.h> 50af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#include <stdlib.h> // for abort() 51af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 52af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic int num_malloc_calls = 0; 53af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic int num_calloc_calls = 0; 54af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic int num_free_calls = 0; 55af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic int countdown_to_fail = 0; // 0 = off 56af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 57af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Aroratypedef struct MemBlock MemBlock; 58af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastruct MemBlock { 59af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora void* ptr_; 60af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora size_t size_; 61af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora MemBlock* next_; 62af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora}; 63af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 64af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic MemBlock* all_blocks = NULL; 65af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic size_t total_mem = 0; 66af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic size_t total_mem_allocated = 0; 67af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic size_t high_water_mark = 0; 68af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic size_t mem_limit = 0; 69af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 70af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic int exit_registered = 0; 71af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 72af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void PrintMemInfo(void) { 73af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, "\nMEMORY INFO:\n"); 74af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, "num calls to: malloc = %4d\n", num_malloc_calls); 75af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, " calloc = %4d\n", num_calloc_calls); 76af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, " free = %4d\n", num_free_calls); 77af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, "total_mem: %u\n", (uint32_t)total_mem); 78af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, "total_mem allocated: %u\n", (uint32_t)total_mem_allocated); 79af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, "high-water mark: %u\n", (uint32_t)high_water_mark); 80af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora while (all_blocks != NULL) { 81af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora MemBlock* b = all_blocks; 82af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora all_blocks = b->next_; 83af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora free(b); 84af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 85af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 86af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 87af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void Increment(int* const v) { 88af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (!exit_registered) { 89af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(MALLOC_FAIL_AT) 90af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora { 91af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const char* const malloc_fail_at_str = getenv("MALLOC_FAIL_AT"); 92af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (malloc_fail_at_str != NULL) { 93af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora countdown_to_fail = atoi(malloc_fail_at_str); 94af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 95af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 96af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 97af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(MALLOC_LIMIT) 98af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora { 99af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora const char* const malloc_limit_str = getenv("MALLOC_LIMIT"); 100af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (malloc_limit_str != NULL) { 101af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora mem_limit = atoi(malloc_limit_str); 102af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 103af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 104af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 105af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora (void)countdown_to_fail; 106af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora (void)mem_limit; 107af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora atexit(PrintMemInfo); 108af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora exit_registered = 1; 109af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 110af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora ++*v; 111af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 112af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 113af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void AddMem(void* ptr, size_t size) { 114af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (ptr != NULL) { 115af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora MemBlock* const b = (MemBlock*)malloc(sizeof(*b)); 116af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (b == NULL) abort(); 117af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora b->next_ = all_blocks; 118af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora all_blocks = b; 119af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora b->ptr_ = ptr; 120af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora b->size_ = size; 121af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora total_mem += size; 122af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora total_mem_allocated += size; 123af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(PRINT_MEM_TRAFFIC) 124af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(MALLOC_FAIL_AT) 125af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, "fail-count: %5d [mem=%u]\n", 126af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora num_malloc_calls + num_calloc_calls, (uint32_t)total_mem); 127af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#else 128af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, "Mem: %u (+%u)\n", (uint32_t)total_mem, (uint32_t)size); 129af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 130af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 131af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (total_mem > high_water_mark) high_water_mark = total_mem; 132af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 133af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 134af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 135af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arorastatic void SubMem(void* ptr) { 136af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (ptr != NULL) { 137af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora MemBlock** b = &all_blocks; 138af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora // Inefficient search, but that's just for debugging. 139af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora while (*b != NULL && (*b)->ptr_ != ptr) b = &(*b)->next_; 140af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (*b == NULL) { 141af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, "Invalid pointer free! (%p)\n", ptr); 142af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora abort(); 143af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 144af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora { 145af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora MemBlock* const block = *b; 146af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora *b = block->next_; 147af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora total_mem -= block->size_; 148af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(PRINT_MEM_TRAFFIC) 149af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora fprintf(stderr, "Mem: %u (-%u)\n", 150af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora (uint32_t)total_mem, (uint32_t)block->size_); 151af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 152af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora free(block); 153af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 154af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 155af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 156af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 157af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#else 158af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define Increment(v) do {} while(0) 159af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define AddMem(p, s) do {} while(0) 160af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#define SubMem(p) do {} while(0) 161af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 162af51b94a435132e9014c324e25fb686b3d07a8c8Vikas 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; 169af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(PRINT_MEM_INFO) && defined(MALLOC_FAIL_AT) 170af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (countdown_to_fail > 0 && --countdown_to_fail == 0) { 171af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora return 0; // fake fail! 172af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 173af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 174af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#if defined(MALLOC_LIMIT) 175af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (mem_limit > 0 && total_mem + total_size >= mem_limit) { 176af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora return 0; // fake fail! 177af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 178af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora#endif 179af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora 180a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora return 1; 181a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora} 182a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 183a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroravoid* WebPSafeMalloc(uint64_t nmemb, size_t size) { 184af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora void* ptr; 185af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora Increment(&num_malloc_calls); 1861e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL; 1871e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora assert(nmemb * size > 0); 188af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora ptr = malloc((size_t)(nmemb * size)); 189af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora AddMem(ptr, (size_t)(nmemb * size)); 190af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora return ptr; 191a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora} 192a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 193a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Aroravoid* WebPSafeCalloc(uint64_t nmemb, size_t size) { 194af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora void* ptr; 195af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora Increment(&num_calloc_calls); 1961e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL; 1971e7bf8805bd030c19924a5306837ecd72c295751Vikas Arora assert(nmemb * size > 0); 198af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora ptr = calloc((size_t)nmemb, size); 199af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora AddMem(ptr, (size_t)(nmemb * size)); 200af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora return ptr; 201a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora} 202a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 203af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Aroravoid WebPSafeFree(void* const ptr) { 204af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora if (ptr != NULL) { 205af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora Increment(&num_free_calls); 206af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora SubMem(ptr); 207af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora } 208af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora free(ptr); 209af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora} 210a2415724fb3466168b2af5b08bd94ba732c0e753Vikas Arora 211af51b94a435132e9014c324e25fb686b3d07a8c8Vikas Arora//------------------------------------------------------------------------------ 212