Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libwebp/src/utils/utils.c
20900 views
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 ([email protected])
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
//------------------------------------------------------------------------------
285
286