PR #25479 opened by Kilian (lusoris) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25479 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25479.patch
These patches address GCC 14.4.0 and 16.2.1 -Warray-bounds in libavcodec/vlc.c, -Wint-in-bool-context in libavcodec/h264dec.c and -Wstringop-overflow in libavcodec/wmadec.c, and GCC 14.4.0 -Wstringop-overflow in libavcodec/a64multienc.c. Result: warnings in these files go from 7 to 0 with GCC 14.4.0 and from 6 to 0 with GCC 16.2.1. What the patch does: - `avcodec/a64multienc: fill palette index tables by interval`: fills constant palette intervals with memset and adds always-on palette-size and interval-bounds assertions. - `avcodec/vlc: assert multi-symbol table bounds`: adds always-on assertions for width selectors, recursive construction levels and the selected array bound at each write. - `avcodec/wmadec: reject invalid block channel counts`: replaces a debug assertion with an unconditional invalid-data return for channel counts outside 1 to MAX_CHANNELS. - `avcodec/h264dec: compute the missing-field offsets before FF_PTR_ADD`: computes the two offsets in local variables before FF_PTR_ADD(); no functional change. Behaviour change: palette and table bounds gain always-on assertions, and invalid block channel counts return errors; valid palette, table and channel processing is unchanged. Base: FFmpeg master 46f23be8b1. Testing: - GCC 14.4.0 (`--enable-gpl --enable-vulkan`) and GCC 16.2.1 (`--enable-gpl --enable-vulkan --enable-vaapi --enable-libdrm --enable-nvenc`), targets all, alltools, examples, testprogs and checkasm: master 46f23be8b1 shows, with GCC 14.4.0, 3 -Warray-bounds warnings in libavcodec/vlc.c; 2 -Wint-in-bool-context warnings in libavcodec/h264dec.c; 2 -Wstringop-overflow warnings in libavcodec/a64multienc.c, libavcodec/wmadec.c, and with GCC 16.2.1, 3 -Warray-bounds warnings in libavcodec/vlc.c; 2 -Wint-in-bool-context warnings in libavcodec/h264dec.c; 1 -Wstringop-overflow warning in libavcodec/wmadec.c; with these patches there are none and no new ones. - FATE with GCC 16.2.1, tests whose name contains `h264`, `wma` or `a64` (294 tests): the same results on master and with these patches; 10 fail on both sides only because their samples are missing from my local FATE sample copy, all others pass. Split out of #25111 so that each part reaches the reviewers for its area. >From c68e9ce126feb2a6e46c3c1ce451eb8747a058a5 Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Thu, 15 Oct 2026 22:06:34 +0200 Subject: [PATCH 1/4] avcodec/a64multienc: fill palette index tables by interval GCC 14.4.0 reports -Wstringop-overflow when building the palette lookup tables. The index tables were filled one luma value at a time, leaving their store bounds unclear to the compiler. Fill each constant palette interval with memset and assert the palette size and interval bounds. For palettes satisfying these invariants, the index values and dithering calculation are unchanged. Signed-off-by: lusoris <[email protected]> --- libavcodec/a64multienc.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/libavcodec/a64multienc.c b/libavcodec/a64multienc.c index d81718dff5f..880b1547ec5 100644 --- a/libavcodec/a64multienc.c +++ b/libavcodec/a64multienc.c @@ -106,7 +106,7 @@ static void render_charset(AVCodecContext *avctx, uint8_t *charset, A64Context *c = avctx->priv_data; uint8_t row1, row2; int charpos, x, y; - int a, b; + int b; uint8_t pix; int lowdiff, highdiff; int *best_cb = c->mc_best_cb; @@ -116,12 +116,15 @@ static void render_charset(AVCodecContext *avctx, uint8_t *charset, int i; int distance; + av_assert0(c->mc_pal_size >= 4 && + c->mc_pal_size <= FF_ARRAY_ELEMS(c->mc_luma_vals)); + /* Generate lookup-tables for dither and index before looping. * This code relies on c->mc_luma_vals[c->mc_pal_size - 1] being * the maximum of all the mc_luma_vals values and on the minimum * being zero; this ensures that dither is properly initialized. */ i = 0; - for (a=0; a < 256; a++) { + for (size_t a = 0; a < FF_ARRAY_ELEMS(index1); a++) { if(i < c->mc_pal_size -1 && a == c->mc_luma_vals[i + 1]) { distance = c->mc_luma_vals[i + 1] - c->mc_luma_vals[i]; for(b = 0; b <= distance; b++) { @@ -130,10 +133,23 @@ static void render_charset(AVCodecContext *avctx, uint8_t *charset, i++; } if(i >= c->mc_pal_size - 1) dither[a] = 0; - index1[a] = i; - index2[a] = FFMIN(i + 1, c->mc_pal_size - 1); } + /* index1 and index2 are constant on each palette interval. Filling them + * per interval, rather than one byte per luma value in the loop above, + * keeps GCC 14 (seen with 14.4.0 on x86-64) from vectorising the fill + * into 16-byte stores that it then reports as overflowing the tables + * (-Wstringop-overflow). */ + for (i = 0; i < c->mc_pal_size - 1; i++) { + const int start = i ? c->mc_luma_vals[i] : 0; + const int end = c->mc_luma_vals[i + 1]; + av_assert0(start < end && end <= FF_ARRAY_ELEMS(index1)); + memset(index1 + start, i, end - start); + memset(index2 + start, i + 1, end - start); + } + memset(index1 + c->mc_luma_vals[i], i, FF_ARRAY_ELEMS(index1) - c->mc_luma_vals[i]); + memset(index2 + c->mc_luma_vals[i], i, FF_ARRAY_ELEMS(index2) - c->mc_luma_vals[i]); + /* and render charset */ for (charpos = 0; charpos < CHARSET_CHARS; charpos++) { lowdiff = 0; -- 2.54.0 >From 8815728bb83cb5ea3d956f8a90e9c8ae6b328cbc Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Thu, 15 Oct 2026 22:06:35 +0200 Subject: [PATCH 2/4] avcodec/vlc: assert multi-symbol table bounds GCC 14.4.0 and 16.2.1 report -Warray-bounds in multi-symbol table construction. The symbol width and current level determine which fixed-size array is written. Assert the width selector and level bounds, including the selected array bound at each write. Table construction for valid selectors and levels is unchanged. Signed-off-by: lusoris <[email protected]> --- libavcodec/vlc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libavcodec/vlc.c b/libavcodec/vlc.c index 93d88714f22..ed610a1df94 100644 --- a/libavcodec/vlc.c +++ b/libavcodec/vlc.c @@ -426,7 +426,11 @@ static void add_level(VLC_MULTI_ELEM *table, const int is16bit, const int minlen, const int max, unsigned* levelcnt, VLC_MULTI_ELEM info) { - int max_symbols = VLC_MULTI_MAX_SYMBOLS >> is16bit; + int max_symbols; + + av_assert0(is16bit == 0 || is16bit == 1); + max_symbols = VLC_MULTI_MAX_SYMBOLS >> is16bit; + av_assert0((unsigned)curlevel < max_symbols); for (int i = num-1; i >= max; i--) { for (int j = 0; j < 2; j++) { int newlimit, sym; @@ -440,8 +444,13 @@ static void add_level(VLC_MULTI_ELEM *table, const int is16bit, code = curcode + (buf[t].code >> curlen); newlimit = curlimit - l; l += curlen; - if (is16bit) info.val16[curlevel] = sym; - else info.val8[curlevel] = sym&0xFF; + if (is16bit) { + av_assert0((unsigned)curlevel < FF_ARRAY_ELEMS(info.val16)); + info.val16[curlevel] = sym; + } else { + av_assert0((unsigned)curlevel < FF_ARRAY_ELEMS(info.val8)); + info.val8[curlevel] = sym & 0xFF; + } if (curlevel) { // let's not add single entries uint32_t val = code >> (32 - numbits); -- 2.54.0 >From e340019a5dadb8b43593135d7907442de77d868d Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Thu, 15 Oct 2026 22:06:35 +0200 Subject: [PATCH 3/4] avcodec/wmadec: reject invalid block channel counts GCC 14.4.0 and 16.2.1 report -Wstringop-overflow in block decoding. The channel count controls access to fixed-size channel storage, but the existing debug assertion only checked its upper bound. Replace it with an error check for counts outside 1 to MAX_CHANNELS. Blocks with supported channel counts follow the same decoding path. Signed-off-by: lusoris <[email protected]> --- libavcodec/wmadec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libavcodec/wmadec.c b/libavcodec/wmadec.c index 65bd3845fd0..0969620d70a 100644 --- a/libavcodec/wmadec.c +++ b/libavcodec/wmadec.c @@ -457,7 +457,10 @@ static int wma_decode_block(WMACodecContext *s) AVTXContext *mdct; av_tx_fn mdct_fn; - av_assert2(channels <= MAX_CHANNELS); + if (channels < 1 || channels > MAX_CHANNELS) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid channel count %d\n", channels); + return AVERROR_INVALIDDATA; + } #ifdef TRACE ff_tlog(s->avctx, "***decode_block: %d:%d\n", -- 2.54.0 >From 476640a459372b44f07b0bc210e1454af4e0099c Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Thu, 15 Oct 2026 23:12:46 +0200 Subject: [PATCH 4/4] avcodec/h264dec: compute the missing-field offsets before FF_PTR_ADD GCC 16.2.1 reports -Wint-in-bool-context for the two FF_PTR_ADD() calls that fill a missing field: the macro tests its offset argument, and the argument here is a multiplication. The test is intended, it skips adding 0 to NULL plane pointers (4a511dc8eb). Compute the offsets into local variables first. No functional change. Signed-off-by: lusoris <[email protected]> --- libavcodec/h264dec.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index 597bdae548a..392b056c740 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -1033,8 +1033,11 @@ static int finalize_frame(H264Context *h, AVFrame *dst, H264Picture *out, int *g av_log(h->avctx, AV_LOG_DEBUG, "Duplicating field %d to fill missing\n", field); for (p = 0; p<4; p++) { - dst_data[p] = FF_PTR_ADD(f->data[p], (field^1)*f->linesize[p]); - src_data[p] = FF_PTR_ADD(f->data[p], field *f->linesize[p]); + const int dst_off = (field^1)*f->linesize[p]; + const int src_off = field *f->linesize[p]; + + dst_data[p] = FF_PTR_ADD(f->data[p], dst_off); + src_data[p] = FF_PTR_ADD(f->data[p], src_off); linesizes[p] = 2*f->linesize[p]; } -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
