[PR] audio: fix parsing, validation, and integer arithmetic edge cases (PR #24310)
AYOUB NABIL BOUBAGRAT via ffmpeg-devel <[email protected]>
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
PR #24310 opened by AYOUB NABIL BOUBAGRAT (ayoubnabil) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24310 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24310.patch this series fixes some independent edge cases in audio filters and the WavPack encoder, including fractional delay parsing, unsafe floating-point conversions, overflowing integer processing, INT32_MIN handling, and acceptance of non-finite parameters. each fix is kept in a separate commit. >From 2ba07f8f629d0bac7fb29bbbd17fd121b0a62f8c Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Thu, 27 Aug 2026 20:16:45 +0200 Subject: [PATCH 1/9] avfilter/adelay: parse fractional second delays correctly the initial integer scan stores '.' as the suffix for values such as 1.5s, causing them to be interpreted as milliseconds. inspect the actual final suffix instead. Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libavfilter/af_adelay.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c index c0d076fe64..4606e29c45 100644 --- a/libavfilter/af_adelay.c +++ b/libavfilter/af_adelay.c @@ -158,21 +158,27 @@ CHANGE_DELAY(dbl, double, 0) static int parse_delays(char *p, char **saveptr, int64_t *result, AVFilterContext *ctx, int sample_rate) { float delay, div; - int ret; char *arg; - char type = 0; + char suffix; if (!(arg = av_strtok(p, "|", saveptr))) return 1; - ret = av_sscanf(arg, "%"SCNd64"%c", result, &type); - if (ret != 2 || type != 'S') { - div = type == 's' ? 1.0 : 1000.0; + suffix = arg[strlen(arg) - 1]; + if (suffix != 'S') { + div = suffix == 's' ? 1.0 : 1000.0; if (av_sscanf(arg, "%f", &delay) != 1) { av_log(ctx, AV_LOG_ERROR, "Invalid syntax for delay.\n"); return AVERROR(EINVAL); } *result = delay * sample_rate / div; + } else { + char type; + + if (av_sscanf(arg, "%"SCNd64"%c", result, &type) != 2 || type != 'S') { + av_log(ctx, AV_LOG_ERROR, "Invalid syntax for delay.\n"); + return AVERROR(EINVAL); + } } if (*result < 0) { -- 2.52.0 >From 7922a874681325d635f070ecaa91a104b6967d88 Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Thu, 27 Aug 2026 20:16:59 +0200 Subject: [PATCH 2/9] avfilter/adelay: reject delays outside int64 range converting a non-finite or too large sample count to int64_t is undefined. validate the value before conversion. Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libavfilter/af_adelay.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c index 4606e29c45..0ce65e7b9b 100644 --- a/libavfilter/af_adelay.c +++ b/libavfilter/af_adelay.c @@ -157,7 +157,7 @@ CHANGE_DELAY(flt, float, 0) CHANGE_DELAY(dbl, double, 0) static int parse_delays(char *p, char **saveptr, int64_t *result, AVFilterContext *ctx, int sample_rate) { - float delay, div; + double delay, div; char *arg; char suffix; @@ -166,12 +166,19 @@ static int parse_delays(char *p, char **saveptr, int64_t *result, AVFilterContex suffix = arg[strlen(arg) - 1]; if (suffix != 'S') { + double delay_samples; + div = suffix == 's' ? 1.0 : 1000.0; - if (av_sscanf(arg, "%f", &delay) != 1) { + if (av_sscanf(arg, "%lf", &delay) != 1) { av_log(ctx, AV_LOG_ERROR, "Invalid syntax for delay.\n"); return AVERROR(EINVAL); } - *result = delay * sample_rate / div; + delay_samples = delay * sample_rate / div; + if (!isfinite(delay_samples) || delay_samples < -0x1p63 || delay_samples >= 0x1p63) { + av_log(ctx, AV_LOG_ERROR, "Delay is out of range.\n"); + return AVERROR(EINVAL); + } + *result = delay_samples; } else { char type; -- 2.52.0 >From 9dc74f451356c939b84f3c7a0e1c179a78aecabd Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Thu, 27 Aug 2026 20:17:04 +0200 Subject: [PATCH 3/9] avfilter/aderivative: saturate integer differences full-scale transitions overflow or wrap integer sample formats. use saturating subtraction for the integer paths. Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libavfilter/af_aderivative.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libavfilter/af_aderivative.c b/libavfilter/af_aderivative.c index 7ac730836a..9f15aad129 100644 --- a/libavfilter/af_aderivative.c +++ b/libavfilter/af_aderivative.c @@ -28,7 +28,7 @@ typedef struct ADerivativeContext { int nb_samples, int channels); } ADerivativeContext; -#define DERIVATIVE(name, type) \ +#define DERIVATIVE(name, type, difference) \ static void aderivative_## name ##p(void **d, void **p, const void **s, \ int nb_samples, int channels) \ { \ @@ -42,16 +42,16 @@ static void aderivative_## name ##p(void **d, void **p, const void **s, \ for (n = 0; n < nb_samples; n++) { \ const type current = src[n]; \ \ - dst[n] = current - prv[0]; \ + dst[n] = difference; \ prv[0] = current; \ } \ } \ } -DERIVATIVE(flt, float) -DERIVATIVE(dbl, double) -DERIVATIVE(s16, int16_t) -DERIVATIVE(s32, int32_t) +DERIVATIVE(flt, float, current - prv[0]) +DERIVATIVE(dbl, double, current - prv[0]) +DERIVATIVE(s16, int16_t, av_clip_int16(current - prv[0])) +DERIVATIVE(s32, int32_t, av_sat_sub32(current, prv[0])) #define INTEGRAL(name, type) \ static void aintegral_## name ##p(void **d, void **p, const void **s, \ -- 2.52.0 >From cf5e05f6437c97f68f59268d544c4f0bc411f433 Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Thu, 27 Aug 2026 20:17:09 +0200 Subject: [PATCH 4/9] avcodec/wavpackenc: handle INT32_MIN samples abs() cannot represent the magnitude of INT32_MIN. labs() has the same issue on platforms where long is 32 bits. use FFABSU for the full signed sample range. Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libavcodec/wavpackenc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libavcodec/wavpackenc.c b/libavcodec/wavpackenc.c index 12010d699b..17372b74a5 100644 --- a/libavcodec/wavpackenc.c +++ b/libavcodec/wavpackenc.c @@ -663,8 +663,9 @@ static uint32_t log2mono(int32_t *samples, int nb_samples, int limit) { uint32_t result = 0; while (nb_samples--) { - if (log2sample(abs(*samples++), limit, &result)) + if (log2sample(FFABSU(samples[0]), limit, &result)) return UINT32_MAX; + samples++; } return result; } @@ -674,9 +675,11 @@ static uint32_t log2stereo(int32_t *samples_l, int32_t *samples_r, { uint32_t result = 0; while (nb_samples--) { - if (log2sample(abs(*samples_l++), limit, &result) || - log2sample(abs(*samples_r++), limit, &result)) + if (log2sample(FFABSU(samples_l[0]), limit, &result) || + log2sample(FFABSU(samples_r[0]), limit, &result)) return UINT32_MAX; + samples_l++; + samples_r++; } return result; } @@ -992,7 +995,7 @@ static void scan_word(WavPackEncodeContext *s, WvChannel *c, samples += nb_samples - 1; while (nb_samples--) { - uint32_t low, value = labs(samples[0]); + uint32_t low, value = FFABSU(samples[0]); if (value < GET_MED(0)) { DEC_MED(0); -- 2.52.0 >From aa69a93df1d1a0c0c1d9db44bfa94622e63b0780 Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Fri, 28 Aug 2026 11:53:43 +0200 Subject: [PATCH 5/9] avfilter/aecho: reject non-finite delays and decays Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libavfilter/af_aecho.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c index ff316eaa67..dedd559465 100644 --- a/libavfilter/af_aecho.c +++ b/libavfilter/af_aecho.c @@ -136,11 +136,11 @@ static av_cold int init(AVFilterContext *ctx) return AVERROR(ENOMEM); for (i = 0; i < nb_delays; i++) { - if (s->delay[i] <= 0 || s->delay[i] > 90000) { + if (!(s->delay[i] > 0 && s->delay[i] <= 90000)) { av_log(ctx, AV_LOG_ERROR, "delay[%d]: %f is out of allowed range: (0, 90000]\n", i, s->delay[i]); return AVERROR(EINVAL); } - if (s->decay[i] <= 0 || s->decay[i] > 1) { + if (!(s->decay[i] > 0 && s->decay[i] <= 1)) { av_log(ctx, AV_LOG_ERROR, "decay[%d]: %f is out of allowed range: (0, 1]\n", i, s->decay[i]); return AVERROR(EINVAL); } -- 2.52.0 >From 8e14ea3f75a4bd9a0f95b073fc4113442324ec46 Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Fri, 28 Aug 2026 11:53:43 +0200 Subject: [PATCH 6/9] avfilter/firequalizer: reject overflowing delays Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libavfilter/af_firequalizer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libavfilter/af_firequalizer.c b/libavfilter/af_firequalizer.c index f14983b431..3621849328 100644 --- a/libavfilter/af_firequalizer.c +++ b/libavfilter/af_firequalizer.c @@ -736,6 +736,10 @@ static int config_input(AVFilterLink *inlink) s->next_pts = 0; s->frame_nsamples_max = 0; + if (inlink->sample_rate * s->delay >= (INT_MAX + 1.0) / 2) { + av_log(ctx, AV_LOG_ERROR, "too large delay, please decrease it.\n"); + return AVERROR(EINVAL); + } s->fir_len = FFMAX(2 * (int)(inlink->sample_rate * s->delay) + 1, 3); s->remaining = s->fir_len - 1; -- 2.52.0 >From f01c836b9300bfbfc007a8e5b0d7b296614ce123 Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Fri, 28 Aug 2026 11:53:43 +0200 Subject: [PATCH 7/9] avfilter/acrossover: reject non-finite parameters Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libavfilter/af_acrossover.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libavfilter/af_acrossover.c b/libavfilter/af_acrossover.c index 8b2786bae2..b5a2ad084d 100644 --- a/libavfilter/af_acrossover.c +++ b/libavfilter/af_acrossover.c @@ -172,6 +172,10 @@ static int parse_gains(AVFilterContext *ctx) s->gains[i] = expf(gain * M_LN10 / 20.f); else s->gains[i] = gain; + if (!isfinite(s->gains[i])) { + av_log(ctx, AV_LOG_ERROR, "Gain %f must be finite.\n", gain); + return AVERROR(EINVAL); + } } for (; i < MAX_BANDS; i++) @@ -203,7 +207,7 @@ static av_cold int init(AVFilterContext *ctx) av_log(ctx, AV_LOG_ERROR, "Invalid syntax for frequency[%d].\n", i); return AVERROR(EINVAL); } - if (freq <= 0) { + if (!(freq > 0)) { av_log(ctx, AV_LOG_ERROR, "Frequency %f must be positive number.\n", freq); return AVERROR(EINVAL); } -- 2.52.0 >From e0cbd76a7c8dcfea7558602515fdeb8daf33cdc4 Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Fri, 28 Aug 2026 11:53:43 +0200 Subject: [PATCH 8/9] avfilter/aiir: reject non-finite parameters Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libavfilter/af_aiir.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c index 2111a08c51..68fd78175e 100644 --- a/libavfilter/af_aiir.c +++ b/libavfilter/af_aiir.c @@ -377,7 +377,7 @@ static int read_gains(AVFilterContext *ctx, char *item_str, int nb_items) } p = NULL; - if (av_sscanf(arg, "%lf", &s->iir[i].g) != 1) { + if (av_sscanf(arg, "%lf", &s->iir[i].g) != 1 || !isfinite(s->iir[i].g)) { av_log(ctx, AV_LOG_ERROR, "Invalid gains supplied: %s\n", arg); av_freep(&old_str); return AVERROR(EINVAL); @@ -404,7 +404,7 @@ static int read_tf_coefficients(AVFilterContext *ctx, char *item_str, int nb_ite break; p = NULL; - if (av_sscanf(arg, "%lf", &dst[i]) != 1) { + if (av_sscanf(arg, "%lf", &dst[i]) != 1 || !isfinite(dst[i])) { av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg); av_freep(&old_str); return AVERROR(EINVAL); @@ -429,7 +429,8 @@ static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_ite break; p = NULL; - if (av_sscanf(arg, format, &dst[i*2], &dst[i*2+1]) != 2) { + if (av_sscanf(arg, format, &dst[i*2], &dst[i*2+1]) != 2 || + !isfinite(dst[i*2]) || !isfinite(dst[i*2+1])) { av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg); av_freep(&old_str); return AVERROR(EINVAL); -- 2.52.0 >From d301033c536dea1e3303a05efee7a6c55f81a2f8 Mon Sep 17 00:00:00 2001 From: Ayoub Nabil Boubagrat <[email protected]> Date: Fri, 28 Aug 2026 11:53:43 +0200 Subject: [PATCH 9/9] avfilter/aphaser: clip integer output Signed-off-by: Ayoub Nabil Boubagrat <[email protected]> --- libavfilter/af_aphaser.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libavfilter/af_aphaser.c b/libavfilter/af_aphaser.c index 8d7f624827..81535d6b28 100644 --- a/libavfilter/af_aphaser.c +++ b/libavfilter/af_aphaser.c @@ -86,7 +86,7 @@ static av_cold int init(AVFilterContext *ctx) #define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a)) -#define PHASER_PLANAR(name, type) \ +#define PHASER_PLANAR(name, type, output) \ static void phaser_## name ##p(AudioPhaserContext *s, \ uint8_t * const *ssrc, uint8_t **ddst, \ int nb_samples, int channels) \ @@ -114,7 +114,7 @@ static void phaser_## name ##p(AudioPhaserContext *s, \ delay_pos = MOD(delay_pos + 1, s->delay_buffer_length); \ buffer[delay_pos] = v; \ \ - *dst = v * s->out_gain; \ + *dst = output; \ } \ } \ \ @@ -122,7 +122,7 @@ static void phaser_## name ##p(AudioPhaserContext *s, \ s->modulation_pos = modulation_pos; \ } -#define PHASER(name, type) \ +#define PHASER(name, type, output) \ static void phaser_## name (AudioPhaserContext *s, \ uint8_t * const *ssrc, uint8_t **ddst, \ int nb_samples, int channels) \ @@ -147,7 +147,7 @@ static void phaser_## name (AudioPhaserContext *s, \ \ buffer[npos + c] = v; \ \ - *dst = v * s->out_gain; \ + *dst = output; \ } \ \ modulation_pos = MOD(modulation_pos + 1, \ @@ -158,15 +158,15 @@ static void phaser_## name (AudioPhaserContext *s, \ s->modulation_pos = modulation_pos; \ } -PHASER_PLANAR(dbl, double) -PHASER_PLANAR(flt, float) -PHASER_PLANAR(s16, int16_t) -PHASER_PLANAR(s32, int32_t) +PHASER_PLANAR(dbl, double, v * s->out_gain) +PHASER_PLANAR(flt, float, v * s->out_gain) +PHASER_PLANAR(s16, int16_t, av_clipd(v * s->out_gain, INT16_MIN, INT16_MAX)) +PHASER_PLANAR(s32, int32_t, av_clipd(v * s->out_gain, INT32_MIN, INT32_MAX)) -PHASER(dbl, double) -PHASER(flt, float) -PHASER(s16, int16_t) -PHASER(s32, int32_t) +PHASER(dbl, double, v * s->out_gain) +PHASER(flt, float, v * s->out_gain) +PHASER(s16, int16_t, av_clipd(v * s->out_gain, INT16_MIN, INT16_MAX)) +PHASER(s32, int32_t, av_clipd(v * s->out_gain, INT32_MIN, INT32_MAX)) static int config_output(AVFilterLink *outlink) { -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]