Apply "default unsafe" annotation across webputils

Import bounds_safety.h across all of webputils, with one exception being
dsp.h, since it's imported by webputils.h in one place. Also prepend
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI to every webputil file to indicate to
the compiler that every pointer should be treated as __unsafe_indexable.

We also need to replace memcpy/memset/memmove with the unsafe variants
WEBP_UNSAFE_*, as memcpy/memset/memmove require bounded/sized pointers.

With this change, all of libwebputils (and libwebp) should build with
-DWEBP_ENABLE_FBOUNDS_SAFETY=true

Change-Id: Iad87be0455182d534c074ef6dc1a30fa66b74b6c
This commit is contained in:
mxms
2025-07-31 23:06:07 +00:00
committed by Max Shavrick
parent 44257cb826
commit ff87eeecc9
29 changed files with 130 additions and 29 deletions

View File

@@ -19,8 +19,11 @@
#endif
#include "src/dsp/cpu.h"
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -26,10 +26,13 @@
#include "src/dsp/cpu.h"
#include "src/dsp/dsp.h"
#include "src/utils/bit_reader_utils.h"
#include "src/utils/bounds_safety.h"
#include "src/utils/endian_inl_utils.h"
#include "src/utils/utils.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif
@@ -79,7 +82,7 @@ static WEBP_UBSAN_IGNORE_UNDEF WEBP_INLINE void VP8LoadNewBytes(
: "memory", "at");
#else
lbit_t in_bits;
memcpy(&in_bits, br->buf, sizeof(in_bits));
WEBP_UNSAFE_MEMCPY(&in_bits, br->buf, sizeof(in_bits));
#endif
br->buf += BITS >> 3;
#if !defined(WORDS_BIGENDIAN)

View File

@@ -21,10 +21,13 @@
#include "src/dsp/cpu.h"
#include "src/utils/bit_reader_inl_utils.h"
#include "src/utils/bit_reader_utils.h"
#include "src/utils/bounds_safety.h"
#include "src/utils/endian_inl_utils.h"
#include "src/utils/utils.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
//------------------------------------------------------------------------------
// VP8BitReader
@@ -258,7 +261,7 @@ static void PrintBitTraces(void) {
void BitTrace(const struct VP8BitReader* const br, const char label[]) {
int i, pos;
if (!init_done) {
memset(kLabels, 0, sizeof(kLabels));
WEBP_UNSAFE_MEMSET(kLabels, 0, sizeof(kLabels));
atexit(PrintBitTraces);
buf_start = br->buf;
init_done = 1;

View File

@@ -22,8 +22,11 @@
#include <stdlib.h> // _byteswap_ulong
#endif
#include "src/dsp/cpu.h"
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
// Warning! This macro triggers quite some MACRO wizardry around func signature!
#if !defined(BITTRACE)
#define BITTRACE 0 // 0 = off, 1 = print bits, 2 = print bytes

View File

@@ -18,10 +18,13 @@
#include <stdlib.h>
#include <string.h> // for memcpy()
#include "src/utils/bounds_safety.h"
#include "src/utils/endian_inl_utils.h"
#include "src/utils/utils.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
//------------------------------------------------------------------------------
// VP8BitWriter
@@ -46,7 +49,7 @@ static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) {
}
if (bw->pos > 0) {
assert(bw->buf != NULL);
memcpy(new_buf, bw->buf, bw->pos);
WEBP_UNSAFE_MEMCPY(new_buf, bw->buf, bw->pos);
}
WebPSafeFree(bw->buf);
bw->buf = new_buf;
@@ -180,7 +183,7 @@ int VP8BitWriterAppend(VP8BitWriter* const bw, const uint8_t* data,
assert(data != NULL);
if (bw->nb_bits != -8) return 0; // Flush() must have been called
if (!BitWriterResize(bw, size)) return 0;
memcpy(bw->buf + bw->pos, data, size);
WEBP_UNSAFE_MEMCPY(bw->buf + bw->pos, data, size);
bw->pos += size;
return 1;
}
@@ -188,7 +191,7 @@ int VP8BitWriterAppend(VP8BitWriter* const bw, const uint8_t* data,
void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
if (bw != NULL) {
WebPSafeFree(bw->buf);
memset(bw, 0, sizeof(*bw));
WEBP_UNSAFE_MEMSET(bw, 0, sizeof(*bw));
}
}
@@ -222,7 +225,7 @@ static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
return 0;
}
if (current_size > 0) {
memcpy(allocated_buf, bw->buf, current_size);
WEBP_UNSAFE_MEMCPY(allocated_buf, bw->buf, current_size);
}
WebPSafeFree(bw->buf);
bw->buf = allocated_buf;
@@ -232,7 +235,7 @@ static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
}
int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) {
memset(bw, 0, sizeof(*bw));
WEBP_UNSAFE_MEMSET(bw, 0, sizeof(*bw));
return VP8LBitWriterResize(bw, expected_size);
}
@@ -241,7 +244,7 @@ int VP8LBitWriterClone(const VP8LBitWriter* const src,
const size_t current_size = src->cur - src->buf;
assert(src->cur >= src->buf && src->cur <= src->end);
if (!VP8LBitWriterResize(dst, current_size)) return 0;
memcpy(dst->buf, src->buf, current_size);
WEBP_UNSAFE_MEMCPY(dst->buf, src->buf, current_size);
dst->bits = src->bits;
dst->used = src->used;
dst->error = src->error;
@@ -252,7 +255,7 @@ int VP8LBitWriterClone(const VP8LBitWriter* const src,
void VP8LBitWriterWipeOut(VP8LBitWriter* const bw) {
if (bw != NULL) {
WebPSafeFree(bw->buf);
memset(bw, 0, sizeof(*bw));
WEBP_UNSAFE_MEMSET(bw, 0, sizeof(*bw));
}
}

View File

@@ -16,8 +16,11 @@
#include <stddef.h>
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -17,9 +17,12 @@
#include <stdlib.h>
#include <string.h>
#include "src/utils/bounds_safety.h"
#include "src/utils/utils.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
//------------------------------------------------------------------------------
// VP8LColorCache.
@@ -47,6 +50,6 @@ void VP8LColorCacheCopy(const VP8LColorCache* const src,
assert(src != NULL);
assert(dst != NULL);
assert(src->hash_bits == dst->hash_bits);
memcpy(dst->colors, src->colors,
((size_t)1u << dst->hash_bits) * sizeof(*dst->colors));
WEBP_UNSAFE_MEMCPY(dst->colors, src->colors,
((size_t)1u << dst->hash_bits) * sizeof(*dst->colors));
}

View File

@@ -19,8 +19,11 @@
#include "src/dsp/cpu.h"
#include "src/dsp/dsp.h"
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -17,8 +17,11 @@
#endif
#include "src/dsp/dsp.h"
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#if defined(WORDS_BIGENDIAN)
#define HToLE32 BSwap32
#define HToLE16 BSwap16

View File

@@ -17,8 +17,11 @@
#include <string.h>
#include "src/dsp/dsp.h"
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
// -----------------------------------------------------------------------------
// Quick estimate of a potentially interesting filter mode to try.
@@ -34,7 +37,7 @@ WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data, int width,
int height, int stride) {
int i, j;
int bins[WEBP_FILTER_LAST][SMAX];
memset(bins, 0, sizeof(bins));
WEBP_UNSAFE_MEMSET(bins, 0, sizeof(bins));
// We only sample every other pixels. That's enough.
for (j = 2; j < height - 1; j += 2) {

View File

@@ -15,8 +15,11 @@
#define WEBP_UTILS_FILTERS_UTILS_H_
#include "src/dsp/dsp.h"
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -17,10 +17,13 @@
#include <stdlib.h>
#include <string.h>
#include "src/utils/bounds_safety.h"
#include "src/utils/utils.h"
#include "src/webp/format_constants.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
// -----------------------------------------------------------------------------
// Util function to optimize the symbol map for RLE coding
@@ -228,7 +231,8 @@ static void GenerateOptimalTree(const uint32_t* const histogram,
break;
}
}
memmove(tree + (k + 1), tree + k, (tree_size - k) * sizeof(*tree));
WEBP_UNSAFE_MEMMOVE(tree + (k + 1), tree + k,
(tree_size - k) * sizeof(*tree));
tree[k].total_count = count;
tree[k].value = -1;
@@ -408,7 +412,7 @@ void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
uint8_t* const buf_rle, HuffmanTree* const huff_tree,
HuffmanTreeCode* const huff_code) {
const int num_symbols = huff_code->num_symbols;
memset(buf_rle, 0, num_symbols * sizeof(*buf_rle));
WEBP_UNSAFE_MEMSET(buf_rle, 0, num_symbols * sizeof(*buf_rle));
OptimizeHuffmanForRle(num_symbols, buf_rle, histogram);
GenerateOptimalTree(histogram, num_symbols, huff_tree, tree_depth_limit,
huff_code->code_lengths);

View File

@@ -14,8 +14,11 @@
#ifndef WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_
#define WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -17,10 +17,13 @@
#include <stdlib.h>
#include <string.h>
#include "src/utils/bounds_safety.h"
#include "src/utils/utils.h"
#include "src/webp/format_constants.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
// Huffman data read via DecodeImageStream is represented in two (red and green)
// bytes.
#define MAX_HTREE_GROUPS 0x10000

View File

@@ -16,9 +16,12 @@
#include <assert.h>
#include "src/utils/bounds_safety.h"
#include "src/webp/format_constants.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -18,12 +18,15 @@
#include <string.h>
#include "src/dsp/lossless_common.h"
#include "src/utils/bounds_safety.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/utils.h"
#include "src/webp/encode.h"
#include "src/webp/format_constants.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
// -----------------------------------------------------------------------------
// Palette reordering for smaller sum of deltas (and for smaller storage).
@@ -82,7 +85,7 @@ int SearchColorNoIdx(const uint32_t sorted[], uint32_t color, int num_colors) {
void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
uint32_t sorted[], uint32_t idx_map[]) {
uint32_t i;
memcpy(sorted, palette, num_colors * sizeof(*sorted));
WEBP_UNSAFE_MEMCPY(sorted, palette, num_colors * sizeof(*sorted));
qsort(sorted, num_colors, sizeof(*sorted), PaletteCompareColorsForQsort);
for (i = 0; i < num_colors; ++i) {
idx_map[SearchColorNoIdx(sorted, palette[i], num_colors)] = i;
@@ -188,7 +191,7 @@ static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
int num_colors, uint32_t* const palette) {
uint32_t predict = 0x00000000;
int i, k;
memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
WEBP_UNSAFE_MEMCPY(palette, palette_sorted, num_colors * sizeof(*palette));
if (!PaletteHasNonMonotonousDeltas(palette_sorted, num_colors)) return;
// Find greedily always the closest color of the predicted color to minimize
// deltas in the palette. This reduces storage needs since the
@@ -393,11 +396,12 @@ int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic,
switch (method) {
case kSortedDefault:
if (palette_sorted[0] == 0 && num_colors > 17) {
memcpy(palette, palette_sorted + 1,
(num_colors - 1) * sizeof(*palette_sorted));
WEBP_UNSAFE_MEMCPY(palette, palette_sorted + 1,
(num_colors - 1) * sizeof(*palette_sorted));
palette[num_colors - 1] = 0;
} else {
memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
WEBP_UNSAFE_MEMCPY(palette, palette_sorted,
num_colors * sizeof(*palette));
}
return 1;
case kMinimizeDelta:

View File

@@ -14,8 +14,11 @@
#ifndef WEBP_UTILS_PALETTE_H_
#define WEBP_UTILS_PALETTE_H_
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
struct WebPPicture;
// The different ways a palette can be sorted.

View File

@@ -18,9 +18,12 @@
#include <string.h> // for memset
#include "src/utils/bounds_safety.h"
#include "src/utils/utils.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
// #define USE_DITHERING // uncomment to enable ordered dithering (not vital)
#define FIX 16 // fix-point precision for averaging
@@ -230,7 +233,7 @@ static int InitParams(uint8_t* const data, int width, int height, int stride,
p->cur = p->start;
p->end = p->start + R * width;
p->top = p->end - width;
memset(p->top, 0, width * sizeof(*p->top));
WEBP_UNSAFE_MEMSET(p->top, 0, width * sizeof(*p->top));
mem += size_scratch_m;
p->average = (uint16_t*)mem;
@@ -270,7 +273,7 @@ int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
if (radius > 0) {
SmoothParams p;
memset(&p, 0, sizeof(p));
WEBP_UNSAFE_MEMSET(&p, 0, sizeof(p));
if (!InitParams(data, width, height, stride, radius, &p)) return 0;
if (p.num_levels > 2) {
for (; p.row < p.height; ++p.row) {

View File

@@ -14,8 +14,11 @@
#ifndef WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_
#define WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -17,6 +17,7 @@
#include <assert.h>
#include <stddef.h>
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
#define NUM_SYMBOLS 256
@@ -24,6 +25,8 @@
#define MAX_ITER 6 // Maximum number of convergence steps.
#define ERROR_THRESHOLD 1e-4 // MSE stopping criterion.
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
// -----------------------------------------------------------------------------
// Quantize levels.

View File

@@ -16,8 +16,11 @@
#include <stdlib.h>
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -15,8 +15,11 @@
#include <string.h>
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
//------------------------------------------------------------------------------
// 31b-range values
@@ -33,7 +36,7 @@ static const uint32_t kRandomTable[VP8_RANDOM_TABLE_SIZE] = {
0x27e5ed3c};
void VP8InitRandom(VP8Random* const rg, float dithering) {
memcpy(rg->tab, kRandomTable, sizeof(rg->tab));
WEBP_UNSAFE_MEMCPY(rg->tab, kRandomTable, sizeof(rg->tab));
rg->index1 = 0;
rg->index2 = 31;
rg->amp = (dithering < 0.0) ? 0

View File

@@ -16,8 +16,11 @@
#include <assert.h>
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -19,9 +19,12 @@
#include <string.h>
#include "src/dsp/dsp.h"
#include "src/utils/bounds_safety.h"
#include "src/utils/utils.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
//------------------------------------------------------------------------------
int WebPRescalerInit(WebPRescaler* const rescaler, int src_width,
@@ -78,7 +81,7 @@ int WebPRescalerInit(WebPRescaler* const rescaler, int src_width,
}
rescaler->irow = work;
rescaler->frow = work + num_channels * dst_width;
memset(work, 0, (size_t)total_size);
WEBP_UNSAFE_MEMSET(work, 0, (size_t)total_size);
WebPRescalerDspInit();
return 1;

View File

@@ -18,8 +18,11 @@
extern "C" {
#endif
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#define WEBP_RESCALER_RFIX 32 // fixed-point precision for multiplies
#define WEBP_RESCALER_ONE (1ull << WEBP_RESCALER_RFIX)
#define WEBP_RESCALER_FRAC(x, y) \

View File

@@ -16,8 +16,11 @@
#include <assert.h>
#include <string.h> // for memset()
#include "src/utils/bounds_safety.h"
#include "src/utils/utils.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef WEBP_USE_THREAD
#if defined(_WIN32)
@@ -257,7 +260,7 @@ static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) {
//------------------------------------------------------------------------------
static void Init(WebPWorker* const worker) {
memset(worker, 0, sizeof(*worker));
WEBP_UNSAFE_MEMSET(worker, 0, sizeof(*worker));
worker->status = NOT_OK;
}

View File

@@ -18,8 +18,11 @@
#include "src/webp/config.h"
#endif
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -17,10 +17,13 @@
#include <stdlib.h>
#include <string.h> // for memcpy()
#include "src/utils/bounds_safety.h"
#include "src/utils/palette.h"
#include "src/webp/encode.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow,
// and not multi-thread safe!).
@@ -228,9 +231,21 @@ void WebPSafeFree(void* const ptr) {
// Public API functions.
void* WebPMalloc(size_t size) { return WebPSafeMalloc(1, size); }
void* WEBP_SINGLE WebPMalloc(size_t size) {
// Currently WebPMalloc/WebPFree are declared in src/webp/types.h, which does
// not include bounds_safety.h. As such, the "default" annotation for the
// pointers they accept/return is __single.
//
// All callers will need to immediately cast the returned pointer to
// WEBP_BIDI_INDEXABLE or WEBP_INDEXABLE via
// WEBP_UNSAFE_FORGE_BIDI_INDEXABLE.
//
// TODO: https://issues.webmproject.org/432511225 - Remove this once we can
// annotate WebPMalloc/WebPFree.
return WEBP_UNSAFE_FORGE_SINGLE(void*, WebPSafeMalloc(1, size));
}
void WebPFree(void* ptr) { WebPSafeFree(ptr); }
void WebPFree(void* WEBP_SINGLE ptr) { WebPSafeFree(ptr); }
//------------------------------------------------------------------------------
@@ -239,7 +254,7 @@ void WebPCopyPlane(const uint8_t* src, int src_stride, uint8_t* dst,
assert(src != NULL && dst != NULL);
assert(abs(src_stride) >= width && abs(dst_stride) >= width);
while (height-- > 0) {
memcpy(dst, src, width);
WEBP_UNSAFE_MEMCPY(dst, src, width);
src += src_stride;
dst += dst_stride;
}

View File

@@ -21,8 +21,11 @@
#include <assert.h>
#include "src/utils/bounds_safety.h"
#include "src/webp/types.h"
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
#ifdef __cplusplus
extern "C" {
#endif
@@ -69,7 +72,7 @@ WEBP_EXTERN void WebPSafeFree(void* const ptr);
// memcpy() is the safe way of moving potentially unaligned 32b memory.
static WEBP_INLINE uint32_t WebPMemToUint32(const uint8_t* const ptr) {
uint32_t A;
memcpy(&A, ptr, sizeof(A));
WEBP_UNSAFE_MEMCPY(&A, ptr, sizeof(A));
return A;
}
@@ -78,7 +81,7 @@ static WEBP_INLINE int32_t WebPMemToInt32(const uint8_t* const ptr) {
}
static WEBP_INLINE void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) {
memcpy(ptr, &val, sizeof(val));
WEBP_UNSAFE_MEMCPY(ptr, &val, sizeof(val));
}
static WEBP_INLINE void WebPInt32ToMem(uint8_t* const ptr, int val) {