PR #25474 opened by Kilian (lusoris) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25474 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25474.patch
These patches address GCC 14.4.0 and 16.2.1 -Wstringop-overflow diagnostics in libavfilter/af_afftfilt.c and libavfilter/af_firequalizer.c, and -Wstack-usage diagnostics against -Wstack-usage=122880 in median filtering across libavfilter/vf_median.c, libavfilter/median_template.c and libavfilter/median.h. What the patch does: - `avfilter/af_afftfilt: assert window and hop size bounds`: adds an always-on assertion that window and hop sizes are positive and the hop does not exceed the window. - `avfilter/af_firequalizer: assert the minimum cepstrum length`: adds an always-on assertion that the cepstrum length is at least two during kernel generation. - `avfilter/vf_median: allocate per-job histogram scratch`: allocates coarse, fine and luc scratch per job, flattens fine-histogram indexing and frees buffers during uninitialization, including after partial allocation. Behaviour change: invalid sizes trigger always-on assertions, and median scratch uses per-job allocations and cleanup; filtering calculations within the supported bounds are 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 1 -Wstack-usage warning in libavfilter/median_template.c; 2 -Wstringop-overflow warnings in libavfilter/af_afftfilt.c, libavfilter/af_firequalizer.c with each compiler; with these patches there are none and no new ones. - FATE with GCC 16.2.1, `firequalizer` and `fate-filter-median*` tests (3 tests): all pass on master and with these patches. - FATE has no test for af_afftfilt. Split out of #25111 so that each part reaches the reviewers for its area. >From c0a89825f1fb6c7f209f8f9b2f788a7b4d47ea49 Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Thu, 15 Oct 2026 22:06:36 +0200 Subject: [PATCH 1/3] avfilter/af_afftfilt: assert window and hop size bounds GCC 14.4.0 and 16.2.1 report -Wstringop-overflow in channel filtering. The window and hop sizes govern buffer movement, so inconsistent sizes risk writes outside the window storage. Assert that both sizes are positive and the hop does not exceed the window. Filtering with sizes satisfying these bounds is unchanged. Signed-off-by: lusoris <[email protected]> --- libavfilter/af_afftfilt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c index 926ce96e054..469c2ee92f3 100644 --- a/libavfilter/af_afftfilt.c +++ b/libavfilter/af_afftfilt.c @@ -258,6 +258,8 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_job const int end = ff_slice_pos(channels, jobnr + 1, nb_jobs); double values[VAR_VARS_NB]; + av_assert0(window_size > 0 && s->hop_size > 0 && s->hop_size <= window_size); + memcpy(values, arg, sizeof(values)); for (int ch = start; ch < end; ch++) { -- 2.54.0 >From a4f9db9e797ae3ef39220c1d81ae7e4e41bf37fb Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Thu, 15 Oct 2026 22:06:36 +0200 Subject: [PATCH 2/3] avfilter/af_firequalizer: assert the minimum cepstrum length GCC 14.4.0 and 16.2.1 report -Wstringop-overflow in minimum-phase kernel generation. The trailing buffer clear uses cepstrum_len / 2 - 1 as its element count, so lengths below two yield a negative count converted to an oversized write length. Assert the minimum length before initializing the cepstrum buffers. Kernel calculations for lengths of at least two are unchanged. Signed-off-by: lusoris <[email protected]> --- libavfilter/af_firequalizer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavfilter/af_firequalizer.c b/libavfilter/af_firequalizer.c index 809741218df..15da10e972c 100644 --- a/libavfilter/af_firequalizer.c +++ b/libavfilter/af_firequalizer.c @@ -542,6 +542,8 @@ static void generate_min_phase_kernel(FIREqualizerContext *s, float *rdft_buf) double norm = 2.0 / cepstrum_len; double minval = 1e-7 / rdft_len; + av_assert0(cepstrum_len >= 2); + memset(s->cepstrum_buf, 0, cepstrum_len * sizeof(*s->cepstrum_buf)); memset(s->cepstrum_tbuf, 0, (cepstrum_len + 2) * sizeof(*s->cepstrum_tbuf)); memcpy(s->cepstrum_buf, rdft_buf, rdft_len/2 * sizeof(*rdft_buf)); -- 2.54.0 >From f5a56484faf26d3890b7d18eb494e2bd19026086 Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Thu, 15 Oct 2026 22:06:36 +0200 Subject: [PATCH 3/3] avfilter/vf_median: allocate per-job histogram scratch GCC 14.4.0 and 16.2.1 report -Wstack-usage against FFmpeg's default -Wstack-usage=122880 limit. The row histograms occupy large automatic arrays. Allocate coarse, fine and luc scratch per job and release all buffers during uninitialization, including after partial allocation. Preserve row resets and flatten fine-histogram indexing without changing the filtering calculations. Signed-off-by: lusoris <[email protected]> --- libavfilter/median.h | 1 + libavfilter/median_template.c | 23 +++++++++++++---------- libavfilter/vf_median.c | 28 +++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/libavfilter/median.h b/libavfilter/median.h index 672607caa83..8c928a8f902 100644 --- a/libavfilter/median.h +++ b/libavfilter/median.h @@ -40,6 +40,7 @@ typedef struct MedianContext { int nb_threads; uint16_t **coarse, **fine; + uint16_t **coarse_tmp, **fine_tmp, **luc_tmp; int coarse_size, fine_size; int bins; int t; diff --git a/libavfilter/median_template.c b/libavfilter/median_template.c index 6f719df57f3..8d679b3447e 100644 --- a/libavfilter/median_template.c +++ b/libavfilter/median_template.c @@ -54,6 +54,9 @@ static void fn(filter_plane)(AVFilterContext *ctx, const uint8_t *ssrc, int src_ MedianContext *s = ctx->priv; htype *ccoarse = s->coarse[jobnr]; htype *cfine = s->fine[jobnr]; + htype *coarse = s->coarse_tmp[jobnr]; + htype *fine = s->fine_tmp[jobnr]; + htype *luc = s->luc_tmp[jobnr]; const int radius = s->radius; const int radiusV = s->radiusV; const int t = s->t; @@ -88,9 +91,9 @@ static void fn(filter_plane)(AVFilterContext *ctx, const uint8_t *ssrc, int src_ srcp = src; for (int i = slice_h_start; i < slice_h_end; i++) { - htype coarse[BINS] = { 0 }; - htype fine[BINS][BINS] = { { 0 } }; - htype luc[BINS] = { 0 }; + memset(coarse, 0, BINS * sizeof(*coarse)); + memset(fine, 0, BINS * BINS * sizeof(*fine)); + memset(luc, 0, BINS * sizeof(*luc)); p = srcp + src_linesize * FFMAX(0, i - radiusV - 1); for (int j = 0; j < width; j++) { @@ -108,7 +111,7 @@ static void fn(filter_plane)(AVFilterContext *ctx, const uint8_t *ssrc, int src_ for (int j = 0; j < radius; j++) s->hadd(coarse, &ccoarse[BINS * j], BINS); for (int k = 0; k < BINS; k++) - s->hmuladd(&fine[k][0], &cfine[BINS * width * k], 2 * radius + 1, BINS); + s->hmuladd(&fine[BINS * k], &cfine[BINS * width * k], 2 * radius + 1, BINS); for (int j = 0; j < width; j++) { int sum = 0, k, b; @@ -126,23 +129,23 @@ static void fn(filter_plane)(AVFilterContext *ctx, const uint8_t *ssrc, int src_ av_assert0(k < BINS); if (luc[k] <= j - radius) { - memset(&fine[k], 0, BINS * sizeof(htype)); + memset(&fine[BINS * k], 0, BINS * sizeof(htype)); for (luc[k] = j - radius; luc[k] < FFMIN(j + radius + 1, width); luc[k]++) - s->hadd(fine[k], &cfine[BINS * (width * k + luc[k])], BINS); + s->hadd(&fine[BINS * k], &cfine[BINS * (width * k + luc[k])], BINS); if (luc[k] < j + radius + 1) { - s->hmuladd(&fine[k][0], &cfine[BINS * (width * k + width - 1)], j + radius + 1 - width, BINS); + s->hmuladd(&fine[BINS * k], &cfine[BINS * (width * k + width - 1)], j + radius + 1 - width, BINS); luc[k] = j + radius + 1; } } else { for (; luc[k] < j + radius + 1; luc[k]++) { - s->hsub(fine[k], &cfine[BINS * (width * k + FFMAX(luc[k] - 2 * radius - 1, 0))], BINS); - s->hadd(fine[k], &cfine[BINS * (width * k + FFMIN(luc[k], width - 1))], BINS); + s->hsub(&fine[BINS * k], &cfine[BINS * (width * k + FFMAX(luc[k] - 2 * radius - 1, 0))], BINS); + s->hadd(&fine[BINS * k], &cfine[BINS * (width * k + FFMIN(luc[k], width - 1))], BINS); } } s->hsub(coarse, &ccoarse[BINS * FFMAX(j - radius, 0)], BINS); - segment = fine[k]; + segment = &fine[BINS * k]; for (b = 0; b < BINS; b++) { sum += segment[b]; if (sum > t) { diff --git a/libavfilter/vf_median.c b/libavfilter/vf_median.c index 3b11adbcad1..c6ef65e52ca 100644 --- a/libavfilter/vf_median.c +++ b/libavfilter/vf_median.c @@ -147,12 +147,19 @@ static int config_input(AVFilterLink *inlink) s->coarse_size = s->bins * inlink->w; s->coarse = av_calloc(s->nb_threads, sizeof(*s->coarse)); s->fine = av_calloc(s->nb_threads, sizeof(*s->fine)); - if (!s->coarse || !s->fine) + s->coarse_tmp = av_calloc(s->nb_threads, sizeof(*s->coarse_tmp)); + s->fine_tmp = av_calloc(s->nb_threads, sizeof(*s->fine_tmp)); + s->luc_tmp = av_calloc(s->nb_threads, sizeof(*s->luc_tmp)); + if (!s->coarse || !s->fine || !s->coarse_tmp || !s->fine_tmp || !s->luc_tmp) return AVERROR(ENOMEM); for (int i = 0; i < s->nb_threads; i++) { s->coarse[i] = av_malloc_array(s->coarse_size, sizeof(**s->coarse)); s->fine[i] = av_malloc_array(s->fine_size, sizeof(**s->fine)); - if (!s->coarse[i] || !s->fine[i]) + s->coarse_tmp[i] = av_malloc_array(s->bins, sizeof(**s->coarse_tmp)); + s->fine_tmp[i] = av_malloc_array(s->bins * s->bins, sizeof(**s->fine_tmp)); + s->luc_tmp[i] = av_malloc_array(s->bins, sizeof(**s->luc_tmp)); + if (!s->coarse[i] || !s->fine[i] || !s->coarse_tmp[i] || + !s->fine_tmp[i] || !s->luc_tmp[i]) return AVERROR(ENOMEM); } @@ -235,13 +242,24 @@ static av_cold void uninit(AVFilterContext *ctx) { MedianContext *s = ctx->priv; - for (int i = 0; i < s->nb_threads && s->coarse && s->fine; i++) { - av_freep(&s->coarse[i]); - av_freep(&s->fine[i]); + for (int i = 0; i < s->nb_threads; i++) { + if (s->coarse) + av_freep(&s->coarse[i]); + if (s->fine) + av_freep(&s->fine[i]); + if (s->coarse_tmp) + av_freep(&s->coarse_tmp[i]); + if (s->fine_tmp) + av_freep(&s->fine_tmp[i]); + if (s->luc_tmp) + av_freep(&s->luc_tmp[i]); } av_freep(&s->coarse); av_freep(&s->fine); + av_freep(&s->coarse_tmp); + av_freep(&s->fine_tmp); + av_freep(&s->luc_tmp); } static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
