mirror of
https://github.com/webmproject/libwebp.git
synced 2025-08-29 15:22:12 +02:00
Merge "Add fbounds-safety annotations in huffman_utils.c/.h
." into main
This commit is contained in:
@@ -54,15 +54,17 @@ static WEBP_INLINE uint32_t GetNextKey(uint32_t key, int len) {
|
|||||||
return step ? (key & (step - 1)) + step : key;
|
return step ? (key & (step - 1)) + step : key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stores code in table[0], table[step], table[2*step], ..., table[end].
|
// Stores code in table[0], table[step], table[2*step], ..., table[end-step].
|
||||||
// Assumes that end is an integer multiple of step.
|
// Assumes that end is an integer multiple of step.
|
||||||
static WEBP_INLINE void ReplicateValue(HuffmanCode* table, int step, int end,
|
static WEBP_INLINE void ReplicateValue(HuffmanCode* WEBP_COUNTED_BY(end - step +
|
||||||
HuffmanCode code) {
|
1) table,
|
||||||
assert(end % step == 0);
|
int step, int end, HuffmanCode code) {
|
||||||
|
int current_end = end;
|
||||||
|
assert(current_end % step == 0);
|
||||||
do {
|
do {
|
||||||
end -= step;
|
current_end -= step;
|
||||||
table[end] = code;
|
table[current_end] = code;
|
||||||
} while (end > 0);
|
} while (current_end > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the table width of the next 2nd level table. count is the histogram
|
// Returns the table width of the next 2nd level table. count is the histogram
|
||||||
@@ -83,11 +85,13 @@ static WEBP_INLINE int NextTableBitSize(
|
|||||||
|
|
||||||
// sorted[code_lengths_size] is a pre-allocated array for sorting symbols
|
// sorted[code_lengths_size] is a pre-allocated array for sorting symbols
|
||||||
// by code length.
|
// by code length.
|
||||||
static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
static int BuildHuffmanTable(HuffmanCode* const WEBP_BIDI_INDEXABLE root_table,
|
||||||
const int code_lengths[], int code_lengths_size,
|
int root_bits, const int code_lengths[],
|
||||||
|
int code_lengths_size,
|
||||||
uint16_t WEBP_COUNTED_BY_OR_NULL(code_lengths_size)
|
uint16_t WEBP_COUNTED_BY_OR_NULL(code_lengths_size)
|
||||||
sorted[]) {
|
sorted[]) {
|
||||||
HuffmanCode* table = root_table; // next available space in table
|
// next available space in table
|
||||||
|
HuffmanCode* WEBP_BIDI_INDEXABLE table = root_table;
|
||||||
int total_size = 1 << root_bits; // total size root table + 2nd level table
|
int total_size = 1 << root_bits; // total size root table + 2nd level table
|
||||||
int len; // current code length
|
int len; // current code length
|
||||||
int symbol; // symbol index in original or sorted table
|
int symbol; // symbol index in original or sorted table
|
||||||
@@ -250,13 +254,18 @@ int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
|
|||||||
// We need at least 'total_size' but if that value is small, it is better to
|
// We need at least 'total_size' but if that value is small, it is better to
|
||||||
// allocate a big chunk to prevent more allocations later. 'segment_size' is
|
// allocate a big chunk to prevent more allocations later. 'segment_size' is
|
||||||
// therefore chosen (any other arbitrary value could be chosen).
|
// therefore chosen (any other arbitrary value could be chosen).
|
||||||
next->size = total_size > segment_size ? total_size : segment_size;
|
{
|
||||||
next->start =
|
const int next_size =
|
||||||
(HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start));
|
total_size > segment_size ? total_size : segment_size;
|
||||||
if (next->start == NULL) {
|
HuffmanCode* WEBP_BIDI_INDEXABLE const next_start =
|
||||||
|
(HuffmanCode*)WebPSafeMalloc(next_size, sizeof(*next_start));
|
||||||
|
if (next_start == NULL) {
|
||||||
WebPSafeFree(next);
|
WebPSafeFree(next);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
next->size = next_size;
|
||||||
|
next->start = next_start;
|
||||||
|
}
|
||||||
next->curr_table = next->start;
|
next->curr_table = next->start;
|
||||||
next->next = NULL;
|
next->next = NULL;
|
||||||
// Point to the new segment.
|
// Point to the new segment.
|
||||||
@@ -266,15 +275,20 @@ int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
|
|||||||
if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
||||||
// use local stack-allocated array.
|
// use local stack-allocated array.
|
||||||
uint16_t sorted[SORTED_SIZE_CUTOFF];
|
uint16_t sorted[SORTED_SIZE_CUTOFF];
|
||||||
BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
|
BuildHuffmanTable(
|
||||||
code_lengths, code_lengths_size, sorted);
|
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
|
||||||
|
HuffmanCode*, root_table->curr_segment->curr_table,
|
||||||
|
total_size * sizeof(*root_table->curr_segment->curr_table)),
|
||||||
|
root_bits, code_lengths, code_lengths_size, sorted);
|
||||||
} else { // rare case. Use heap allocation.
|
} else { // rare case. Use heap allocation.
|
||||||
uint16_t* const sorted =
|
uint16_t* const sorted =
|
||||||
(uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
|
(uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
|
||||||
if (sorted == NULL) return 0;
|
if (sorted == NULL) return 0;
|
||||||
BuildHuffmanTable(
|
BuildHuffmanTable(
|
||||||
root_table->curr_segment->curr_table, root_bits, code_lengths,
|
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
|
||||||
code_lengths_size,
|
HuffmanCode*, root_table->curr_segment->curr_table,
|
||||||
|
total_size * sizeof(*root_table->curr_segment->curr_table)),
|
||||||
|
root_bits, code_lengths, code_lengths_size,
|
||||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
|
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
|
||||||
uint16_t*, sorted, (size_t)code_lengths_size * sizeof(*sorted)));
|
uint16_t*, sorted, (size_t)code_lengths_size * sizeof(*sorted)));
|
||||||
WebPSafeFree(sorted);
|
WebPSafeFree(sorted);
|
||||||
@@ -288,10 +302,18 @@ int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
|
|||||||
huffman_tables->curr_segment = root;
|
huffman_tables->curr_segment = root;
|
||||||
root->next = NULL;
|
root->next = NULL;
|
||||||
// Allocate root.
|
// Allocate root.
|
||||||
root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
|
{
|
||||||
if (root->start == NULL) return 0;
|
HuffmanCode* WEBP_BIDI_INDEXABLE const start =
|
||||||
root->curr_table = root->start;
|
(HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
|
||||||
|
if (start == NULL) {
|
||||||
|
root->start = NULL;
|
||||||
|
root->size = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
root->size = size;
|
root->size = size;
|
||||||
|
root->start = start;
|
||||||
|
}
|
||||||
|
root->curr_table = root->start;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,6 +325,7 @@ void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) {
|
|||||||
next = current->next;
|
next = current->next;
|
||||||
WebPSafeFree(current->start);
|
WebPSafeFree(current->start);
|
||||||
current->start = NULL;
|
current->start = NULL;
|
||||||
|
current->size = 0;
|
||||||
current->next = NULL;
|
current->next = NULL;
|
||||||
current = next;
|
current = next;
|
||||||
// Free the following nodes.
|
// Free the following nodes.
|
||||||
|
@@ -48,10 +48,10 @@ typedef struct {
|
|||||||
|
|
||||||
// Contiguous memory segment of HuffmanCodes.
|
// Contiguous memory segment of HuffmanCodes.
|
||||||
typedef struct HuffmanTablesSegment {
|
typedef struct HuffmanTablesSegment {
|
||||||
HuffmanCode* start;
|
HuffmanCode* WEBP_COUNTED_BY_OR_NULL(size) start;
|
||||||
// Pointer to where we are writing into the segment. Starts at 'start' and
|
// Pointer to where we are writing into the segment. Starts at 'start' and
|
||||||
// cannot go beyond 'start' + 'size'.
|
// cannot go beyond 'start' + 'size'.
|
||||||
HuffmanCode* curr_table;
|
HuffmanCode* WEBP_UNSAFE_INDEXABLE curr_table;
|
||||||
// Pointer to the next segment in the chain.
|
// Pointer to the next segment in the chain.
|
||||||
struct HuffmanTablesSegment* next;
|
struct HuffmanTablesSegment* next;
|
||||||
int size;
|
int size;
|
||||||
|
@@ -201,14 +201,15 @@ static int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* WebPSafeMalloc(uint64_t nmemb, size_t size) {
|
void* WEBP_SIZED_BY_OR_NULL(nmemb* size)
|
||||||
|
WebPSafeMalloc(uint64_t nmemb, size_t size) {
|
||||||
void* ptr;
|
void* ptr;
|
||||||
Increment(&num_malloc_calls);
|
Increment(&num_malloc_calls);
|
||||||
if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;
|
if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;
|
||||||
assert(nmemb * size > 0);
|
assert(nmemb * size > 0);
|
||||||
ptr = malloc((size_t)(nmemb * size));
|
ptr = malloc((size_t)(nmemb * size));
|
||||||
AddMem(ptr, (size_t)(nmemb * size));
|
AddMem(ptr, (size_t)(nmemb * size));
|
||||||
return ptr;
|
return WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(void*, ptr, (size_t)(nmemb * size));
|
||||||
}
|
}
|
||||||
|
|
||||||
void* WEBP_SIZED_BY_OR_NULL(nmemb* size)
|
void* WEBP_SIZED_BY_OR_NULL(nmemb* size)
|
||||||
|
@@ -54,7 +54,8 @@ static WEBP_INLINE int CheckSizeOverflow(uint64_t size) {
|
|||||||
// somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this
|
// somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this
|
||||||
// safe malloc() borrows the signature from calloc(), pointing at the dangerous
|
// safe malloc() borrows the signature from calloc(), pointing at the dangerous
|
||||||
// underlying multiply involved.
|
// underlying multiply involved.
|
||||||
WEBP_EXTERN void* WebPSafeMalloc(uint64_t nmemb, size_t size);
|
WEBP_EXTERN void* WEBP_SIZED_BY_OR_NULL(nmemb* size)
|
||||||
|
WebPSafeMalloc(uint64_t nmemb, size_t size);
|
||||||
// Note that WebPSafeCalloc() expects the second argument type to be 'size_t'
|
// Note that WebPSafeCalloc() expects the second argument type to be 'size_t'
|
||||||
// in order to favor the "calloc(num_foo, sizeof(foo))" pattern.
|
// in order to favor the "calloc(num_foo, sizeof(foo))" pattern.
|
||||||
WEBP_EXTERN void* WEBP_SIZED_BY_OR_NULL(nmemb* size)
|
WEBP_EXTERN void* WEBP_SIZED_BY_OR_NULL(nmemb* size)
|
||||||
|
Reference in New Issue
Block a user