Patches attached.

- Andreas
From 56445c4d007f74b4b51282184b773791f6b24641 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Mon, 21 Apr 2025 18:48:10 +0200
Subject: [PATCH 1/5] avcodec/cri,tdsc,tiff: Use ff_mjpeg_decoder directly

This is simpler than calling avcodec_find_decoder().
Notice that av_codec_init_static() has already been called
by the time we reach these decoders' init functions,
so it is not necessary to call avcodec_find_decoder()
for it (which doesn't do anything for the mjpeg decoder
anyway).

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/cri.c  | 10 ++++------
 libavcodec/tdsc.c | 10 ++++------
 libavcodec/tiff.c | 10 ++++------
 3 files changed, 12 insertions(+), 18 deletions(-)

diff --git a/libavcodec/cri.c b/libavcodec/cri.c
index 6932bb6745..56ec485f7a 100644
--- a/libavcodec/cri.c
+++ b/libavcodec/cri.c
@@ -27,6 +27,7 @@
 
 #define BITSTREAM_READER_LE
 
+#include "libavutil/attributes_internal.h"
 #include "libavutil/intfloat.h"
 #include "libavutil/display.h"
 #include "avcodec.h"
@@ -51,7 +52,6 @@ typedef struct CRIContext {
 static av_cold int cri_decode_init(AVCodecContext *avctx)
 {
     CRIContext *s = avctx->priv_data;
-    const AVCodec *codec;
     int ret;
 
     s->jpgframe = av_frame_alloc();
@@ -62,16 +62,14 @@ static av_cold int cri_decode_init(AVCodecContext *avctx)
     if (!s->jpkt)
         return AVERROR(ENOMEM);
 
-    codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
-    if (!codec)
-        return AVERROR_BUG;
-    s->jpeg_avctx = avcodec_alloc_context3(codec);
+    EXTERN const FFCodec ff_mjpeg_decoder;
+    s->jpeg_avctx = avcodec_alloc_context3(&ff_mjpeg_decoder.p);
     if (!s->jpeg_avctx)
         return AVERROR(ENOMEM);
     s->jpeg_avctx->flags = avctx->flags;
     s->jpeg_avctx->flags2 = avctx->flags2;
     s->jpeg_avctx->idct_algo = avctx->idct_algo;
-    ret = avcodec_open2(s->jpeg_avctx, codec, NULL);
+    ret = avcodec_open2(s->jpeg_avctx, NULL, NULL);
     if (ret < 0)
         return ret;
 
diff --git a/libavcodec/tdsc.c b/libavcodec/tdsc.c
index ab0a70859b..225ddf3701 100644
--- a/libavcodec/tdsc.c
+++ b/libavcodec/tdsc.c
@@ -36,6 +36,7 @@
 #include <stdint.h>
 #include <zlib.h>
 
+#include "libavutil/attributes_internal.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/mem.h"
 
@@ -95,7 +96,6 @@ static av_cold int tdsc_close(AVCodecContext *avctx)
 static av_cold int tdsc_init(AVCodecContext *avctx)
 {
     TDSCContext *ctx = avctx->priv_data;
-    const AVCodec *codec;
     int ret;
 
     avctx->pix_fmt = AV_PIX_FMT_BGR24;
@@ -120,16 +120,14 @@ static av_cold int tdsc_init(AVCodecContext *avctx)
         return AVERROR(ENOMEM);
 
     /* Prepare everything needed for JPEG decoding */
-    codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
-    if (!codec)
-        return AVERROR_BUG;
-    ctx->jpeg_avctx = avcodec_alloc_context3(codec);
+    EXTERN const FFCodec ff_mjpeg_decoder;
+    ctx->jpeg_avctx = avcodec_alloc_context3(&ff_mjpeg_decoder.p);
     if (!ctx->jpeg_avctx)
         return AVERROR(ENOMEM);
     ctx->jpeg_avctx->flags = avctx->flags;
     ctx->jpeg_avctx->flags2 = avctx->flags2;
     ctx->jpeg_avctx->idct_algo = avctx->idct_algo;
-    ret = avcodec_open2(ctx->jpeg_avctx, codec, NULL);
+    ret = avcodec_open2(ctx->jpeg_avctx, NULL, NULL);
     if (ret < 0)
         return ret;
 
diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c
index 37b56e9757..e515845a83 100644
--- a/libavcodec/tiff.c
+++ b/libavcodec/tiff.c
@@ -36,6 +36,7 @@
 #include <float.h>
 
 #include "libavutil/attributes.h"
+#include "libavutil/attributes_internal.h"
 #include "libavutil/avstring.h"
 #include "libavutil/error.h"
 #include "libavutil/intreadwrite.h"
@@ -2409,7 +2410,6 @@ again:
 static av_cold int tiff_init(AVCodecContext *avctx)
 {
     TiffContext *s = avctx->priv_data;
-    const AVCodec *codec;
     int ret;
 
     s->width  = 0;
@@ -2429,17 +2429,15 @@ static av_cold int tiff_init(AVCodecContext *avctx)
         return AVERROR(ENOMEM);
 
     /* Prepare everything needed for JPEG decoding */
-    codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
-    if (!codec)
-        return AVERROR_BUG;
-    s->avctx_mjpeg = avcodec_alloc_context3(codec);
+    EXTERN const FFCodec ff_mjpeg_decoder;
+    s->avctx_mjpeg = avcodec_alloc_context3(&ff_mjpeg_decoder.p);
     if (!s->avctx_mjpeg)
         return AVERROR(ENOMEM);
     s->avctx_mjpeg->flags = avctx->flags;
     s->avctx_mjpeg->flags2 = avctx->flags2;
     s->avctx_mjpeg->idct_algo = avctx->idct_algo;
     s->avctx_mjpeg->max_pixels = avctx->max_pixels;
-    ret = avcodec_open2(s->avctx_mjpeg, codec, NULL);
+    ret = avcodec_open2(s->avctx_mjpeg, NULL, NULL);
     if (ret < 0) {
         return ret;
     }
-- 
2.45.2

From c2dff2428f10d8521f37923f728686483176870b Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Mon, 21 Apr 2025 19:01:57 +0200
Subject: [PATCH 2/5] tools/target_dec_fuzzer: Remove mjpeg hack

ff_mjpeg_decoder is now referenced directly by the relevant
decoders, so that the linker sees the dependency and
just does the desired thing. So remove the hack.

(Btw: The preprocessor does not do string comparisons, instead
undefined tokens in #if checks evaluate to 0, making the check
true regardless of the actual codec fuzzed (and leading to
linker errors if the mjpeg decoder is disabled).)

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 tools/target_dec_fuzzer.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/tools/target_dec_fuzzer.c b/tools/target_dec_fuzzer.c
index b3be69f94d..2a8f39cb34 100644
--- a/tools/target_dec_fuzzer.c
+++ b/tools/target_dec_fuzzer.c
@@ -193,11 +193,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         extern FFCodec DECODER_SYMBOL(FFMPEG_DECODER);
         codec_list[0] = &DECODER_SYMBOL(FFMPEG_DECODER);
 
-#if FFMPEG_DECODER == tiff || FFMPEG_DECODER == tdsc
-        extern FFCodec DECODER_SYMBOL(mjpeg);
-        codec_list[1] = &DECODER_SYMBOL(mjpeg);
-#endif
-
         c = &DECODER_SYMBOL(FFMPEG_DECODER);
 #else
         c = AVCodecInitialize(FFMPEG_CODEC);  // Done once.
-- 
2.45.2

From 3c3e84447f1e775c3e8caed4f8a22e8ae254967b Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Mon, 21 Apr 2025 19:13:07 +0200
Subject: [PATCH 3/5] avcodec/imm5: Reference H.264/HEVC decoders directly

This is simpler and allows to fuzz them -- up until now,
the linker did not see the dependency and fuzzing them
returned AVERROR_BUG during init.
It took just a few seconds here to run into an assert
due to a return value of AVERROR(EAGAIN) in the decode
callback...

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/imm5.c | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/libavcodec/imm5.c b/libavcodec/imm5.c
index 2535e7726c..4b9f3f6b75 100644
--- a/libavcodec/imm5.c
+++ b/libavcodec/imm5.c
@@ -18,6 +18,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/attributes_internal.h"
 #include "libavutil/intreadwrite.h"
 
 #include "avcodec.h"
@@ -51,32 +52,27 @@ static const struct IMM5_unit {
 static av_cold int imm5_init(AVCodecContext *avctx)
 {
     IMM5Context *ctx = avctx->priv_data;
-    const AVCodec *codec;
     int ret;
 
-    codec = avcodec_find_decoder(AV_CODEC_ID_H264);
-    if (!codec)
-        return AVERROR_BUG;
-    ctx->h264_avctx = avcodec_alloc_context3(codec);
+    EXTERN const FFCodec ff_h264_decoder;
+    ctx->h264_avctx = avcodec_alloc_context3(&ff_h264_decoder.p);
     if (!ctx->h264_avctx)
         return AVERROR(ENOMEM);
     ctx->h264_avctx->thread_count = 1;
     ctx->h264_avctx->flags        = avctx->flags;
     ctx->h264_avctx->flags2       = avctx->flags2;
-    ret = avcodec_open2(ctx->h264_avctx, codec, NULL);
+    ret = avcodec_open2(ctx->h264_avctx, NULL, NULL);
     if (ret < 0)
         return ret;
 
-    codec = avcodec_find_decoder(AV_CODEC_ID_HEVC);
-    if (!codec)
-        return AVERROR_BUG;
-    ctx->hevc_avctx = avcodec_alloc_context3(codec);
+    EXTERN const FFCodec ff_hevc_decoder;
+    ctx->hevc_avctx = avcodec_alloc_context3(&ff_hevc_decoder.p);
     if (!ctx->hevc_avctx)
         return AVERROR(ENOMEM);
     ctx->hevc_avctx->thread_count = 1;
     ctx->hevc_avctx->flags        = avctx->flags;
     ctx->hevc_avctx->flags2       = avctx->flags2;
-    ret = avcodec_open2(ctx->hevc_avctx, codec, NULL);
+    ret = avcodec_open2(ctx->hevc_avctx, NULL, NULL);
     if (ret < 0)
         return ret;
 
-- 
2.45.2

From c68f31c624f561ca5dffaa694de6608256b0d03f Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Mon, 21 Apr 2025 19:16:31 +0200
Subject: [PATCH 4/5] avcodec/ftr: Replace AVERROR_BUG that can be triggered

Return AVERROR_DECODER_NOT_FOUND.
(This can be triggered because this decoder tries to be
generic and work with multiple underlying AAC decoders,
so that there is no configure dependency for any decoder.)

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/ftr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/ftr.c b/libavcodec/ftr.c
index 3e7ab92887..06241fdca3 100644
--- a/libavcodec/ftr.c
+++ b/libavcodec/ftr.c
@@ -51,7 +51,7 @@ static av_cold int ftr_init(AVCodecContext *avctx)
 
     codec = avcodec_find_decoder(AV_CODEC_ID_AAC);
     if (!codec)
-        return AVERROR_BUG;
+        return AVERROR_DECODER_NOT_FOUND;
 
     for (int i = 0; i < s->nb_context; i++) {
         s->aac_avctx[i] = avcodec_alloc_context3(codec);
-- 
2.45.2

From 3f176ef2e65e63a46e29c4d1fc3306b8d8550c8b Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Mon, 21 Apr 2025 20:01:50 +0200
Subject: [PATCH 5/5] tools/target_dec_fuzzer: Assert on AVERROR_BUG

This will bring these bugs to our attention.

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 tools/target_dec_fuzzer.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/tools/target_dec_fuzzer.c b/tools/target_dec_fuzzer.c
index 2a8f39cb34..d99bfb91d6 100644
--- a/tools/target_dec_fuzzer.c
+++ b/tools/target_dec_fuzzer.c
@@ -87,6 +87,7 @@ static int subtitle_handler(AVCodecContext *avctx, AVFrame *unused,
 {
     AVSubtitle sub;
     int ret = avcodec_decode_subtitle2(avctx, &sub, got_sub_ptr, avpkt);
+    av_assert0(ret != AVERROR_BUG);
     if (ret >= 0 && *got_sub_ptr)
         avsubtitle_free(&sub);
     return ret;
@@ -96,6 +97,7 @@ static int audio_video_handler(AVCodecContext *avctx, AVFrame *frame,
                                int *got_frame, const AVPacket *dummy)
 {
     int ret = avcodec_receive_frame(avctx, frame);
+    av_assert0(ret != AVERROR_BUG);
     *got_frame = ret >= 0;
     return ret;
 }
@@ -469,6 +471,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
 
     int res = avcodec_open2(ctx, &c->p, &opts);
     if (res < 0) {
+        av_assert0(res != AVERROR_BUG);
         avcodec_free_context(&ctx);
         av_free(parser_avctx);
         av_parser_close(parser);
@@ -542,6 +545,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
 
           if (ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
               int ret = avcodec_send_packet(ctx, avpkt);
+              av_assert0(ret != AVERROR_BUG);
               decode_more = ret >= 0;
               if(!decode_more) {
                     ec_pixels += (ctx->width + 32LL) * (ctx->height + 32LL);
@@ -595,8 +599,10 @@ maximums_reached:
 
     av_packet_unref(avpkt);
 
-    if (ctx->codec_type != AVMEDIA_TYPE_SUBTITLE)
-        avcodec_send_packet(ctx, NULL);
+    if (ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+        int ret = avcodec_send_packet(ctx, NULL);
+        av_assert0(ret != AVERROR_BUG);
+    }
 
     do {
         got_frame = 0;
-- 
2.45.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to