Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: mkver via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: mkver <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PATCH] ohdec error handling (PR #20587)
Date: Tue, 23 Sep 2025 14:29:09 -0000
Message-ID: <175863774958.25.12766302684032426517@463a07221176> (raw)

PR #20587 opened by mkver
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20587
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20587.patch

While looking at ohdec.c for other stuff, I noticed that the error handling seems suspicious in several error paths:
1. When the dec_ref buffer can't be created, oh_decode_release() would never be called. (Fixed in the first patch.)
2. oh_decode_close() always calls OH_VideoDecoder_Stop() if s->dec is set, but what happens if an error happens in between its creation and OH_VideoDecoder_Start()? Is it really safe to call?
3. What actually happens if the OH_VideoDecoder_Start() call in oh_decode_flush() fails?
4. If oh_decode_output_frame() fails, what happens with output->buffer? It seems to leak.
5. It also does not check mutex/condition variables initialization.

This patchset is entirely untested; I don't even know whether it compiles.


>From 556ce80ff21c0a459d163721e066990583af6e31 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Tue, 23 Sep 2025 15:03:40 +0200
Subject: [PATCH 1/3] avcodec/ohdec: Release decoder on allocation failure

Normally, the OH_AVCodec is wrapped inside an AVBuffer
to be freed in its free callback; yet when creating
the AVBuffer fails, the decoder is never destroyed.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/ohdec.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libavcodec/ohdec.c b/libavcodec/ohdec.c
index cf1177afcd..08b03a7e7b 100644
--- a/libavcodec/ohdec.c
+++ b/libavcodec/ohdec.c
@@ -124,8 +124,11 @@ static int oh_decode_create(OHCodecDecContext *s, AVCodecContext *avctx)
 
     s->dec_ref = av_buffer_create((uint8_t *)s->dec, 0, oh_decode_release,
                                   NULL, 0);
-    if (!s->dec_ref)
+    if (!s->dec_ref) {
+        oh_decode_release(NULL, (uint8_t*)s->dec);
+        s->dec = NULL;
         return AVERROR(ENOMEM);
+    }
 
     return 0;
 }
-- 
2.49.1


>From bd3f5c4e7f0afbb81c68f3d79423e0d41c8581d2 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Tue, 23 Sep 2025 15:52:09 +0200
Subject: [PATCH 2/3] avcodec/ohdec: Switch to RefStruct API for internal
 refcounting

It avoids allocations and corresponding error conditions.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/ohdec.c | 36 ++++++++++++++----------------------
 1 file changed, 14 insertions(+), 22 deletions(-)

diff --git a/libavcodec/ohdec.c b/libavcodec/ohdec.c
index 08b03a7e7b..86f3c84279 100644
--- a/libavcodec/ohdec.c
+++ b/libavcodec/ohdec.c
@@ -29,6 +29,7 @@
 #include "libavutil/imgutils.h"
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
+#include "libavutil/refstruct.h"
 #include "libavutil/thread.h"
 
 #include "avcodec.h"
@@ -40,11 +41,11 @@
 typedef struct OHCodecDecContext {
     AVClass *avclass;
     OH_AVCodec *dec;
-    /* A reference count to dec. Each hardware frame has a reference count to
+    /* A RefStruct reference backing dec. Each hardware frame has a reference count to
      * dec. dec will be destroyed only after oh_decode_close and all hardware
      * frames have been released.
      */
-    AVBufferRef *dec_ref;
+    OH_AVCodec **dec_ref;
 
     AVMutex input_mutex;
     AVCond input_cond;
@@ -74,13 +75,13 @@ typedef struct OHCodecDecContext {
 typedef struct OHCodecBuffer {
     uint32_t index;
     OH_AVBuffer *buffer;
-    AVBufferRef *dec_ref;
+    OH_AVCodec **dec_ref;  ///< RefStruct reference
 } OHCodecBuffer;
 
-static void oh_decode_release(void *opaque, uint8_t *data)
+static void oh_decode_release(AVRefStructOpaque unused, void *obj)
 {
-    OH_AVCodec *dec = (OH_AVCodec *)data;
-    OH_AVErrCode err = OH_VideoDecoder_Destroy(dec);
+    OH_AVCodec **decp = obj;
+    OH_AVErrCode err = OH_VideoDecoder_Destroy(*decp);
     if (err == AV_ERR_OK)
         av_log(NULL, AV_LOG_DEBUG, "Destroy decoder success\n");
     else
@@ -122,13 +123,13 @@ static int oh_decode_create(OHCodecDecContext *s, AVCodecContext *avctx)
     }
     av_log(avctx, AV_LOG_DEBUG, "Create decoder %s success\n", name);
 
-    s->dec_ref = av_buffer_create((uint8_t *)s->dec, 0, oh_decode_release,
-                                  NULL, 0);
+    s->dec_ref = av_refstruct_alloc_ext(sizeof(*s->dec_ref), 0, NULL, oh_decode_release);
     if (!s->dec_ref) {
-        oh_decode_release(NULL, (uint8_t*)s->dec);
+        oh_decode_release((AVRefStructOpaque){.nc = NULL }, &s->dec);
         s->dec = NULL;
         return AVERROR(ENOMEM);
     }
+    *s->dec_ref = s->dec;
 
     return 0;
 }
@@ -408,7 +409,7 @@ static av_cold int oh_decode_close(AVCodecContext *avctx)
             av_log(avctx, AV_LOG_ERROR, "Stop decoder failed, %d, %s\n",
                    err, av_err2str(ff_oh_err_to_ff_err(err)));
         s->dec = NULL;
-        av_buffer_unref(&s->dec_ref);
+        av_refstruct_unref(&s->dec_ref);
     }
 
     av_packet_unref(&s->pkt);
@@ -431,13 +432,8 @@ static void oh_buffer_release(void *opaque, uint8_t *data)
 
     OHCodecBuffer *buffer = opaque;
 
-    if (!buffer->dec_ref) {
-        av_free(buffer);
-        return;
-    }
-
     if (buffer->buffer) {
-        OH_AVCodec *dec = (OH_AVCodec *)buffer->dec_ref->data;
+        OH_AVCodec *dec = *buffer->dec_ref;
         OH_AVCodecBufferAttr attr;
         OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(buffer->buffer, &attr);
         if (err == AV_ERR_OK && !(attr.flags & AVCODEC_BUFFER_FLAGS_DISCARD))
@@ -446,7 +442,7 @@ static void oh_buffer_release(void *opaque, uint8_t *data)
             OH_VideoDecoder_FreeOutputBuffer(dec, buffer->index);
     }
 
-    av_buffer_unref(&buffer->dec_ref);
+    av_refstruct_unref(&buffer->dec_ref);
     av_free(buffer);
 }
 
@@ -467,11 +463,7 @@ static int oh_decode_wrap_hw_buffer(AVCodecContext *avctx, AVFrame *frame,
     if (!buffer)
         return AVERROR(ENOMEM);
 
-    buffer->dec_ref = av_buffer_ref(s->dec_ref);
-    if (!buffer->dec_ref) {
-        oh_buffer_release(buffer, NULL);
-        return AVERROR(ENOMEM);
-    }
+    buffer->dec_ref = av_refstruct_ref(s->dec_ref);
 
     buffer->index = output->index;
     buffer->buffer = output->buffer;
-- 
2.49.1


>From 753569a014613b69a0ecb257210b6cd02da739ee Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Tue, 23 Sep 2025 16:05:30 +0200
Subject: [PATCH 3/3] avcodec/ohdec: Check mutex/conditions initialization

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/ohdec.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/libavcodec/ohdec.c b/libavcodec/ohdec.c
index 86f3c84279..3a1887ade5 100644
--- a/libavcodec/ohdec.c
+++ b/libavcodec/ohdec.c
@@ -37,6 +37,7 @@
 #include "decode.h"
 #include "hwconfig.h"
 #include "ohcodec.h"
+#include "pthread_internal.h"
 
 typedef struct OHCodecDecContext {
     AVClass *avclass;
@@ -70,8 +71,14 @@ typedef struct OHCodecDecContext {
 
     char *name;
     int allow_sw;
+    unsigned mutex_cond_cnt;
 } OHCodecDecContext;
 
+#define OFFSET(x) offsetof(OHCodecDecContext, x)
+DEFINE_OFFSET_ARRAY(OHCodecDecContext, mutex_cond, mutex_cond_cnt,
+                    (OFFSET(input_mutex), OFFSET(output_mutex)),
+                    (OFFSET(input_cond), OFFSET(output_cond)));
+
 typedef struct OHCodecBuffer {
     uint32_t index;
     OH_AVBuffer *buffer;
@@ -367,12 +374,11 @@ static av_cold int oh_decode_init(AVCodecContext *avctx)
     OHCodecDecContext *s = avctx->priv_data;
 
     // Initialize these fields first, so oh_decode_close can destroy them safely
-    ff_mutex_init(&s->input_mutex, NULL);
-    ff_cond_init(&s->input_cond, NULL);
-    ff_mutex_init(&s->output_mutex, NULL);
-    ff_cond_init(&s->output_cond, NULL);
+    int ret = ff_pthread_init(s, mutex_cond_offsets);
+    if (ret < 0)
+        return ret;
 
-    int ret = oh_decode_create(s, avctx);
+    ret = oh_decode_create(s, avctx);
     if (ret < 0)
         return ret;
     ret = oh_decode_set_format(s, avctx);
@@ -414,14 +420,12 @@ static av_cold int oh_decode_close(AVCodecContext *avctx)
 
     av_packet_unref(&s->pkt);
 
-    ff_mutex_destroy(&s->input_mutex);
-    ff_cond_destroy(&s->input_cond);
     av_fifo_freep2(&s->input_queue);
 
-    ff_mutex_destroy(&s->output_mutex);
-    ff_cond_destroy(&s->output_cond);
     av_fifo_freep2(&s->output_queue);
 
+    ff_thread_free(s, mutex_cond_offsets);
+
     return 0;
 }
 
@@ -718,7 +722,6 @@ static const AVCodecHWConfigInternal *const oh_hw_configs[] = {
     NULL
 };
 
-#define OFFSET(x) offsetof(OHCodecDecContext, x)
 #define VD (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM)
 static const AVOption ohcodec_vdec_options[] = {
     {"codec_name", "Select codec by name",
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

                 reply	other threads:[~2025-09-23 14:29 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=175863774958.25.12766302684032426517@463a07221176 \
    --to=ffmpeg-devel@ffmpeg.org \
    --cc=code@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror http://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ http://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git