Add fbounds-safety annotations for tokens.

Reasoning:

The errors reported for `tokens` in `CodeRepeatedValues`
(src/utils/huffman_encode_utils.c, lines 274, 283, 289, 294)
indicated pointer arithmetic on a pointer assumed to be `__single`.
Since `CodeRepeatedValues` is static and uses `tokens` as an iterator,
its signature was changed to use `HuffmanTreeToken* __indexable` for
both the parameter and return type. A similar static function,
`CodeRepeatedZeros`, was also updated to use `__indexable` pointers.

The caller, `VP8LCreateCompressedHuffmanTree`, passes a buffer `tokens`
with size `max_tokens`. Its signature (in .c and .h files) was
annotated to reflect this using `__counted_by(max_tokens)`. Because
`__counted_by` requires the size parameter to be updated alongside the
pointer if the pointer is modified, the implementation of
`VP8LCreateCompressedHuffmanTree` was refactored. Instead of modifying
the `tokens` parameter directly, a local iterator variable
`current_token` was introduced and explicitly annotated as
`__indexable` to ensure correct type propagation, especially when
`WEBP_ASSUME_UNSAFE_INDEXABLE_ABI` is active. This local iterator is
used for calls to `CodeRepeatedValues` and `CodeRepeatedZeros`.

Bug: 432511821
Change-Id: I07fe553341a613a0ea4d5284817098c31f3aefeb
This commit is contained in:
Arman Hasanzadeh
2025-08-18 18:57:06 -07:00
parent 3f96cbffa2
commit 101e2b303f
2 changed files with 17 additions and 13 deletions

View File

@@ -265,9 +265,9 @@ static void GenerateOptimalTree(const uint32_t* const histogram,
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Coding of the Huffman tree values // Coding of the Huffman tree values
static HuffmanTreeToken* CodeRepeatedValues(int repetitions, static HuffmanTreeToken* WEBP_INDEXABLE
HuffmanTreeToken* tokens, int value, CodeRepeatedValues(int repetitions, HuffmanTreeToken* WEBP_INDEXABLE tokens,
int prev_value) { int value, int prev_value) {
assert(value <= MAX_ALLOWED_CODE_LENGTH); assert(value <= MAX_ALLOWED_CODE_LENGTH);
if (value != prev_value) { if (value != prev_value) {
tokens->code = value; tokens->code = value;
@@ -299,8 +299,8 @@ static HuffmanTreeToken* CodeRepeatedValues(int repetitions,
return tokens; return tokens;
} }
static HuffmanTreeToken* CodeRepeatedZeros(int repetitions, static HuffmanTreeToken* WEBP_INDEXABLE
HuffmanTreeToken* tokens) { CodeRepeatedZeros(int repetitions, HuffmanTreeToken* WEBP_INDEXABLE tokens) {
while (repetitions >= 1) { while (repetitions >= 1) {
if (repetitions < 3) { if (repetitions < 3) {
int i; int i;
@@ -330,8 +330,10 @@ static HuffmanTreeToken* CodeRepeatedZeros(int repetitions,
return tokens; return tokens;
} }
int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree, int VP8LCreateCompressedHuffmanTree(
HuffmanTreeToken* tokens, int max_tokens) { const HuffmanTreeCode* const tree,
HuffmanTreeToken* WEBP_COUNTED_BY(max_tokens) tokens, int max_tokens) {
HuffmanTreeToken* WEBP_INDEXABLE current_token = tokens;
HuffmanTreeToken* const starting_token = tokens; HuffmanTreeToken* const starting_token = tokens;
HuffmanTreeToken* const ending_token = tokens + max_tokens; HuffmanTreeToken* const ending_token = tokens + max_tokens;
const int depth_size = tree->num_symbols; const int depth_size = tree->num_symbols;
@@ -345,16 +347,17 @@ int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree,
while (k < depth_size && tree->code_lengths[k] == value) ++k; while (k < depth_size && tree->code_lengths[k] == value) ++k;
runs = k - i; runs = k - i;
if (value == 0) { if (value == 0) {
tokens = CodeRepeatedZeros(runs, tokens); current_token = CodeRepeatedZeros(runs, current_token);
} else { } else {
tokens = CodeRepeatedValues(runs, tokens, value, prev_value); current_token =
CodeRepeatedValues(runs, current_token, value, prev_value);
prev_value = value; prev_value = value;
} }
i += runs; i += runs;
assert(tokens <= ending_token); assert(current_token <= ending_token);
} }
(void)ending_token; // suppress 'unused variable' warning (void)ending_token; // suppress 'unused variable' warning
return (int)(tokens - starting_token); return (int)(current_token - starting_token);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -48,8 +48,9 @@ typedef struct {
// Turn the Huffman tree into a token sequence. // Turn the Huffman tree into a token sequence.
// Returns the number of tokens used. // Returns the number of tokens used.
int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree, int VP8LCreateCompressedHuffmanTree(
HuffmanTreeToken* tokens, int max_tokens); const HuffmanTreeCode* const tree,
HuffmanTreeToken* WEBP_COUNTED_BY(max_tokens) tokens, int max_tokens);
// Create an optimized tree, and tokenize it. // Create an optimized tree, and tokenize it.
// 'buf_rle' and 'huff_tree' are pre-allocated and the 'tree' is the constructed // 'buf_rle' and 'huff_tree' are pre-allocated and the 'tree' is the constructed