[PR] avcodec/cngdec: Fix SIGILL issue in cng_decode_frame() (PR #24012)

yongdev via ffmpeg-devel <[email protected]> Tue, 04 Aug 2026 21:10:30 -0000
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <178587783147.59.251898957659311718@29965ddac10e>
PR #24012 opened by yongdev
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24012
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24012.patch

The issue is caused by floating-point to integer overflow conversion
at function av_clip_int16(p->filter_out[i + p->order]).
The float value is out of bounds, which leads to undefined behavior
and a SIGILL crash when compiled with -fsanitize=float-cast-overflow.

- Handle NAN using isfinite()
- Clip float value into valid range of int16 with av_clipf
- Register the fate-comfortnoise test in FATE_VOICE.
- Use the 'astats' filter to verify the output RMS level (expecting < -3dB).
  This allows detecting the regression on standard builds (where the bug
  causes positive peaks to invert to the negative rail, leading to RMS near 0dB)
  while avoiding flakiness from cross-platform float divergence on intermediate samples.



>From ff9b8f3562d410603dd118b0fb6000745e8d9fe0 Mon Sep 17 00:00:00 2001
From: Yong Yu <[email protected]>
Date: Sun, 14 Jun 2026 03:57:01 +0000
Subject: [PATCH 1/2] avcodec/cngdec: Fix SIGILL issue in cng_decode_frame()

The issue is caused by floating-point to integer overflow conversion
at function av_clip_int16(p->filter_out[i + p->order]).
The float value is out of bounds, which leads to undefined behavior
and a SIGILL crash when compiled with -fsanitize=float-cast-overflow.

- Handle NAN using isfinite()
- Clip float value into valid range of int16 with av_clipf
- Register the fate-comfortnoise test in FATE_VOICE.
- Use the 'astats' filter to verify the output RMS level (expecting < -3dB).
  This allows detecting the regression on standard builds (where the bug
  causes positive peaks to invert to the negative rail, leading to RMS near 0dB)
  while avoiding flakiness from cross-platform float divergence on intermediate samples.
---
 libavcodec/cngdec.c  |  6 ++++--
 tests/fate/voice.mak | 15 +++++++++++++++
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/libavcodec/cngdec.c b/libavcodec/cngdec.c
index eb37c33eb4..9e7905ee6d 100644
--- a/libavcodec/cngdec.c
+++ b/libavcodec/cngdec.c
@@ -153,8 +153,10 @@ static int cng_decode_frame(AVCodecContext *avctx, AVFrame *frame,
     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
         return ret;
     buf_out = (int16_t *)frame->data[0];
-    for (i = 0; i < avctx->frame_size; i++)
-        buf_out[i] = av_clip_int16(p->filter_out[i + p->order]);
+    for (i = 0; i < avctx->frame_size; i++) {
+        const float f = p->filter_out[i + p->order];
+        buf_out[i] = !isfinite(f) ? 0 : av_clipf(f, INT16_MIN, INT16_MAX);
+    }
     memcpy(p->filter_out, p->filter_out + avctx->frame_size,
            p->order * sizeof(*p->filter_out));
 
diff --git a/tests/fate/voice.mak b/tests/fate/voice.mak
index 70855788d2..b6a5d7d113 100644
--- a/tests/fate/voice.mak
+++ b/tests/fate/voice.mak
@@ -94,5 +94,20 @@ fate-truespeech: CMD = pcm -i $(TARGET_SAMPLES)/truespeech/a6.wav
 fate-truespeech: CMP = oneoff
 fate-truespeech: REF = $(SAMPLES)/truespeech/a6.pcm
 
+# This test reproduces a float-cast-overflow in the comfortnoise decoder
+# (cngdec.c) when fed with a 24-byte all-zero G.723.1 frame.
+# The bug causes positive float values to overflow to negative integer values
+# during clipping, resulting in massive negative bias (RMS near 0dB).
+# The fixed version clips correctly, resulting in quieter output (RMS < -3dB).
+tests/data/g723_1-comfortnoise-sigill.bin:
+	$(M)mkdir -p tests/data
+	$(M)head -c 24 /dev/zero > $@
+
+FATE_VOICE-$(call FILTERDEMDECENCMUX, ASTATS, G723_1, COMFORTNOISE, PCM_S16LE, NULL) += fate-comfortnoise
+fate-comfortnoise: tests/data/g723_1-comfortnoise-sigill.bin
+fate-comfortnoise: CMP = grep
+fate-comfortnoise: REF = RMS level dB: \(-[3-9]\|-[1-9][0-9]\)
+fate-comfortnoise: CMD = ffmpeg -f g723_1 -codec:a comfortnoise -i $(TARGET_PATH)/tests/data/g723_1-comfortnoise-sigill.bin -af astats -c:a pcm_s16le -f null -
+
 FATE_SAMPLES_FFMPEG += $(FATE_VOICE-yes)
 fate-voice: $(FATE_VOICE-yes)
-- 
2.52.0


>From 531799372ff65b2a751516853523da7cf3f975bc Mon Sep 17 00:00:00 2001
From: yuyong05 <[email protected]>
Date: Sun, 14 Jun 2026 03:57:01 +0000
Subject: [PATCH 2/2] avcodec/cngdec: Fix SIGILL issue in cng_decode_frame()

The issue is caused by floating-point to integer overflow conversion
at function av_clip_int16(p->filter_out[i + p->order]).
The float value is out of bounds, which leads to undefined behavior
and a SIGILL crash when compiled with -fsanitize=float-cast-overflow.

- Handle NAN using isfinite()
- Clip float value into valid range of int16 with av_clipf
- Register the fate-comfortnoise test in FATE_VOICE.
- Use the 'astats' filter to verify the output RMS level (expecting < -3dB).
  This allows detecting the regression on standard builds (where the bug
  causes positive peaks to invert to the negative rail, leading to RMS near 0dB)
  while avoiding flakiness from cross-platform float divergence on intermediate samples.
---
 tests/fate/voice.mak | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/fate/voice.mak b/tests/fate/voice.mak
index b6a5d7d113..58805246ae 100644
--- a/tests/fate/voice.mak
+++ b/tests/fate/voice.mak
@@ -101,7 +101,7 @@ fate-truespeech: REF = $(SAMPLES)/truespeech/a6.pcm
 # The fixed version clips correctly, resulting in quieter output (RMS < -3dB).
 tests/data/g723_1-comfortnoise-sigill.bin:
 	$(M)mkdir -p tests/data
-	$(M)head -c 24 /dev/zero > $@
+	$(M)printf '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' > $@
 
 FATE_VOICE-$(call FILTERDEMDECENCMUX, ASTATS, G723_1, COMFORTNOISE, PCM_S16LE, NULL) += fate-comfortnoise
 fate-comfortnoise: tests/data/g723_1-comfortnoise-sigill.bin
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]