tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

utils.c (8892B)


      1 // Copyright 2012 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // Misc. common utility functions
     11 //
     12 // Author: Skal (pascal.massimino@gmail.com)
     13 
     14 #include "src/utils/utils.h"
     15 
     16 #include <assert.h>
     17 #include <stdlib.h>
     18 #include <string.h>  // for memcpy()
     19 
     20 #include "src/webp/types.h"
     21 #include "src/utils/palette.h"
     22 #include "src/webp/encode.h"
     23 
     24 // If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
     25 // alloc/free etc) is printed. For debugging/tuning purpose only (it's slow,
     26 // and not multi-thread safe!).
     27 // An interesting alternative is valgrind's 'massif' tool:
     28 //    https://valgrind.org/docs/manual/ms-manual.html
     29 // Here is an example command line:
     30 /*    valgrind --tool=massif --massif-out-file=massif.out \
     31               --stacks=yes --alloc-fn=WebPSafeMalloc --alloc-fn=WebPSafeCalloc
     32      ms_print massif.out
     33 */
     34 // In addition:
     35 // * if PRINT_MEM_TRAFFIC is defined, all the details of the malloc/free cycles
     36 //   are printed.
     37 // * if MALLOC_FAIL_AT is defined, the global environment variable
     38 //   $MALLOC_FAIL_AT is used to simulate a memory error when calloc or malloc
     39 //   is called for the nth time. Example usage:
     40 //   export MALLOC_FAIL_AT=50 && ./examples/cwebp input.png
     41 // * if MALLOC_LIMIT is defined, the global environment variable $MALLOC_LIMIT
     42 //   sets the maximum amount of memory (in bytes) made available to libwebp.
     43 //   This can be used to emulate environment with very limited memory.
     44 //   Example: export MALLOC_LIMIT=64000000 && ./examples/dwebp picture.webp
     45 
     46 // #define PRINT_MEM_INFO
     47 // #define PRINT_MEM_TRAFFIC
     48 // #define MALLOC_FAIL_AT
     49 // #define MALLOC_LIMIT
     50 
     51 //------------------------------------------------------------------------------
     52 // Checked memory allocation
     53 
     54 #if defined(PRINT_MEM_INFO)
     55 
     56 #include <stdio.h>
     57 
     58 static int num_malloc_calls = 0;
     59 static int num_calloc_calls = 0;
     60 static int num_free_calls = 0;
     61 static int countdown_to_fail = 0;     // 0 = off
     62 
     63 typedef struct MemBlock MemBlock;
     64 struct MemBlock {
     65  void* ptr;
     66  size_t size;
     67  MemBlock* next;
     68 };
     69 
     70 static MemBlock* all_blocks = NULL;
     71 static size_t total_mem = 0;
     72 static size_t total_mem_allocated = 0;
     73 static size_t high_water_mark = 0;
     74 static size_t mem_limit = 0;
     75 
     76 static int exit_registered = 0;
     77 
     78 static void PrintMemInfo(void) {
     79  fprintf(stderr, "\nMEMORY INFO:\n");
     80  fprintf(stderr, "num calls to: malloc = %4d\n", num_malloc_calls);
     81  fprintf(stderr, "              calloc = %4d\n", num_calloc_calls);
     82  fprintf(stderr, "              free   = %4d\n", num_free_calls);
     83  fprintf(stderr, "total_mem: %u\n", (uint32_t)total_mem);
     84  fprintf(stderr, "total_mem allocated: %u\n", (uint32_t)total_mem_allocated);
     85  fprintf(stderr, "high-water mark: %u\n", (uint32_t)high_water_mark);
     86  while (all_blocks != NULL) {
     87    MemBlock* b = all_blocks;
     88    all_blocks = b->next;
     89    free(b);
     90  }
     91 }
     92 
     93 static void Increment(int* const v) {
     94  if (!exit_registered) {
     95 #if defined(MALLOC_FAIL_AT)
     96    {
     97      const char* const malloc_fail_at_str = getenv("MALLOC_FAIL_AT");
     98      if (malloc_fail_at_str != NULL) {
     99        countdown_to_fail = atoi(malloc_fail_at_str);
    100      }
    101    }
    102 #endif
    103 #if defined(MALLOC_LIMIT)
    104    {
    105      const char* const malloc_limit_str = getenv("MALLOC_LIMIT");
    106 #if MALLOC_LIMIT > 1
    107      mem_limit = (size_t)MALLOC_LIMIT;
    108 #endif
    109      if (malloc_limit_str != NULL) {
    110        mem_limit = atoi(malloc_limit_str);
    111      }
    112    }
    113 #endif
    114    (void)countdown_to_fail;
    115    (void)mem_limit;
    116    atexit(PrintMemInfo);
    117    exit_registered = 1;
    118  }
    119  ++*v;
    120 }
    121 
    122 static void AddMem(void* ptr, size_t size) {
    123  if (ptr != NULL) {
    124    MemBlock* const b = (MemBlock*)malloc(sizeof(*b));
    125    if (b == NULL) abort();
    126    b->next = all_blocks;
    127    all_blocks = b;
    128    b->ptr = ptr;
    129    b->size = size;
    130    total_mem += size;
    131    total_mem_allocated += size;
    132 #if defined(PRINT_MEM_TRAFFIC)
    133 #if defined(MALLOC_FAIL_AT)
    134    fprintf(stderr, "fail-count: %5d [mem=%u]\n",
    135            num_malloc_calls + num_calloc_calls, (uint32_t)total_mem);
    136 #else
    137    fprintf(stderr, "Mem: %u (+%u)\n", (uint32_t)total_mem, (uint32_t)size);
    138 #endif
    139 #endif
    140    if (total_mem > high_water_mark) high_water_mark = total_mem;
    141  }
    142 }
    143 
    144 static void SubMem(void* ptr) {
    145  if (ptr != NULL) {
    146    MemBlock** b = &all_blocks;
    147    // Inefficient search, but that's just for debugging.
    148    while (*b != NULL && (*b)->ptr != ptr) b = &(*b)->next;
    149    if (*b == NULL) {
    150      fprintf(stderr, "Invalid pointer free! (%p)\n", ptr);
    151      abort();
    152    }
    153    {
    154      MemBlock* const block = *b;
    155      *b = block->next;
    156      total_mem -= block->size;
    157 #if defined(PRINT_MEM_TRAFFIC)
    158      fprintf(stderr, "Mem: %u (-%u)\n",
    159              (uint32_t)total_mem, (uint32_t)block->size);
    160 #endif
    161      free(block);
    162    }
    163  }
    164 }
    165 
    166 #else
    167 #define Increment(v) do {} while (0)
    168 #define AddMem(p, s) do {} while (0)
    169 #define SubMem(p)    do {} while (0)
    170 #endif
    171 
    172 // Returns 0 in case of overflow of nmemb * size.
    173 static int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
    174  const uint64_t total_size = nmemb * size;
    175  if (nmemb == 0) return 1;
    176  if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0;
    177  if (!CheckSizeOverflow(total_size)) return 0;
    178 #if defined(PRINT_MEM_INFO) && defined(MALLOC_FAIL_AT)
    179  if (countdown_to_fail > 0 && --countdown_to_fail == 0) {
    180    return 0;    // fake fail!
    181  }
    182 #endif
    183 #if defined(PRINT_MEM_INFO) && defined(MALLOC_LIMIT)
    184  if (mem_limit > 0) {
    185    const uint64_t new_total_mem = (uint64_t)total_mem + total_size;
    186    if (!CheckSizeOverflow(new_total_mem) ||
    187        new_total_mem > mem_limit) {
    188      return 0;   // fake fail!
    189    }
    190  }
    191 #endif
    192 
    193  return 1;
    194 }
    195 
    196 void* WebPSafeMalloc(uint64_t nmemb, size_t size) {
    197  void* ptr;
    198  Increment(&num_malloc_calls);
    199  if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;
    200  assert(nmemb * size > 0);
    201  ptr = malloc((size_t)(nmemb * size));
    202  AddMem(ptr, (size_t)(nmemb * size));
    203  return ptr;
    204 }
    205 
    206 void* WebPSafeCalloc(uint64_t nmemb, size_t size) {
    207  void* ptr;
    208  Increment(&num_calloc_calls);
    209  if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;
    210  assert(nmemb * size > 0);
    211  ptr = calloc((size_t)nmemb, size);
    212  AddMem(ptr, (size_t)(nmemb * size));
    213  return ptr;
    214 }
    215 
    216 void WebPSafeFree(void* const ptr) {
    217  if (ptr != NULL) {
    218    Increment(&num_free_calls);
    219    SubMem(ptr);
    220  }
    221  free(ptr);
    222 }
    223 
    224 // Public API functions.
    225 
    226 void* WebPMalloc(size_t size) {
    227  return WebPSafeMalloc(1, size);
    228 }
    229 
    230 void WebPFree(void* ptr) {
    231  WebPSafeFree(ptr);
    232 }
    233 
    234 //------------------------------------------------------------------------------
    235 
    236 void WebPCopyPlane(const uint8_t* src, int src_stride,
    237                   uint8_t* dst, int dst_stride, int width, int height) {
    238  assert(src != NULL && dst != NULL);
    239  assert(abs(src_stride) >= width && abs(dst_stride) >= width);
    240  while (height-- > 0) {
    241    memcpy(dst, src, width);
    242    src += src_stride;
    243    dst += dst_stride;
    244  }
    245 }
    246 
    247 void WebPCopyPixels(const WebPPicture* const src, WebPPicture* const dst) {
    248  assert(src != NULL && dst != NULL);
    249  assert(src->width == dst->width && src->height == dst->height);
    250  assert(src->use_argb && dst->use_argb);
    251  WebPCopyPlane((uint8_t*)src->argb, 4 * src->argb_stride, (uint8_t*)dst->argb,
    252                4 * dst->argb_stride, 4 * src->width, src->height);
    253 }
    254 
    255 //------------------------------------------------------------------------------
    256 
    257 int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
    258  return GetColorPalette(pic, palette);
    259 }
    260 
    261 //------------------------------------------------------------------------------
    262 
    263 #if defined(WEBP_NEED_LOG_TABLE_8BIT)
    264 const uint8_t WebPLogTable8bit[256] = {   // 31 ^ clz(i)
    265  0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
    266  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
    267  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    268  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    269  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    270  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    271  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    272  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    273  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    274  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    275  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    276  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    277  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    278  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    279  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    280  7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
    281 };
    282 #endif
    283 
    284 //------------------------------------------------------------------------------