Merge "Add fbounds-safety annotations in huffman_utils.c/.h." into main

This commit is contained in:
James Zern
2025-08-27 12:34:36 -07:00
committed by Gerrit Code Review
4 changed files with 53 additions and 28 deletions

View File

@@ -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,12 +254,17 @@ 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 =
WebPSafeFree(next); (HuffmanCode*)WebPSafeMalloc(next_size, sizeof(*next_start));
return 0; if (next_start == NULL) {
WebPSafeFree(next);
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;
@@ -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 =
(HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
if (start == NULL) {
root->start = NULL;
root->size = 0;
return 0;
}
root->size = size;
root->start = start;
}
root->curr_table = root->start; root->curr_table = root->start;
root->size = size;
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.

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)