diff mbox

[FFmpeg-devel] pthread_frame: don't return stale error codes after flush

Message ID 20170406153643.647-1-nfxjfg@googlemail.com
State Accepted
Commit 15a23a83326d70e470a6b5c8d71e55257bffd97b
Headers show

Commit Message

wm4 April 6, 2017, 3:36 p.m. UTC
Consider the following sequence of events:

- open a codec without AV_CODEC_CAP_DELAY
- decode call fails with an error
- ff_thread_flush() is called
- drain packet is sent

Then the last step would make ff_thread_decode_frame() return an error,
because p->result can still be set to an error value. This is because
submit_packet returns immediately if AV_CODEC_CAP_DELAY is not set, and
no worker thread gets the chance to reset p->result, yet its value is
trusted by ff_thread_decode_frame().

Fix this by clearing the error fields on flush.
---
 libavcodec/pthread_frame.c | 1 +
 1 file changed, 1 insertion(+)

Comments

Ronald S. Bultje April 6, 2017, 3:38 p.m. UTC | #1
Hi,

On Thu, Apr 6, 2017 at 11:36 AM, wm4 <nfxjfg@googlemail.com> wrote:

> Consider the following sequence of events:
>
> - open a codec without AV_CODEC_CAP_DELAY
> - decode call fails with an error
> - ff_thread_flush() is called
> - drain packet is sent
>
> Then the last step would make ff_thread_decode_frame() return an error,
> because p->result can still be set to an error value. This is because
> submit_packet returns immediately if AV_CODEC_CAP_DELAY is not set, and
> no worker thread gets the chance to reset p->result, yet its value is
> trusted by ff_thread_decode_frame().
>
> Fix this by clearing the error fields on flush.
> ---
>  libavcodec/pthread_frame.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
> index 9a6b83ac45..7586f00bec 100644
> --- a/libavcodec/pthread_frame.c
> +++ b/libavcodec/pthread_frame.c
> @@ -859,6 +859,7 @@ void ff_thread_flush(AVCodecContext *avctx)
>          // Make sure decode flush calls with size=0 won't return old
> frames
>          p->got_frame = 0;
>          av_frame_unref(p->frame);
> +        p->result = 0;
>
>          release_delayed_buffers(p);
>
> --
> 2.11.0


Nice catch - I think that looks good.

Ronald
wm4 April 6, 2017, 4:18 p.m. UTC | #2
On Thu, 6 Apr 2017 11:38:55 -0400
"Ronald S. Bultje" <rsbultje@gmail.com> wrote:

> Hi,
> 
> On Thu, Apr 6, 2017 at 11:36 AM, wm4 <nfxjfg@googlemail.com> wrote:
> 
> > Consider the following sequence of events:
> >
> > - open a codec without AV_CODEC_CAP_DELAY
> > - decode call fails with an error
> > - ff_thread_flush() is called
> > - drain packet is sent
> >
> > Then the last step would make ff_thread_decode_frame() return an error,
> > because p->result can still be set to an error value. This is because
> > submit_packet returns immediately if AV_CODEC_CAP_DELAY is not set, and
> > no worker thread gets the chance to reset p->result, yet its value is
> > trusted by ff_thread_decode_frame().
> >
> > Fix this by clearing the error fields on flush.
> > ---
> >  libavcodec/pthread_frame.c | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
> > index 9a6b83ac45..7586f00bec 100644
> > --- a/libavcodec/pthread_frame.c
> > +++ b/libavcodec/pthread_frame.c
> > @@ -859,6 +859,7 @@ void ff_thread_flush(AVCodecContext *avctx)
> >          // Make sure decode flush calls with size=0 won't return old
> > frames
> >          p->got_frame = 0;
> >          av_frame_unref(p->frame);
> > +        p->result = 0;
> >
> >          release_delayed_buffers(p);
> >
> > --
> > 2.11.0  
> 
> 
> Nice catch - I think that looks good.
> 
> Ronald

Pushed.
Uoti Urpala April 6, 2017, 8:09 p.m. UTC | #3
On Thu, 2017-04-06 at 18:18 +0200, wm4 wrote:
> > >          p->got_frame = 0;
> > >          av_frame_unref(p->frame);
> > > +        p->result = 0;

Shouldn't p->result be similarly reset together with p->got_frame also
in ff_thread_decode_frame()? A similar problem seems possible:
- a normal decode call returns an error due to p->result being negative
- drain packet is sent before cycling through all threads
- the loop in ff_thread_decode_frame hits "if (p->result < 0)"
Thus incorrectly returning the same error again from the drain packet.
wm4 April 7, 2017, 6:34 a.m. UTC | #4
On Thu, 06 Apr 2017 23:09:41 +0300
Uoti Urpala <uoti.urpala@pp1.inet.fi> wrote:

> On Thu, 2017-04-06 at 18:18 +0200, wm4 wrote:
> > > >          p->got_frame = 0;
> > > >          av_frame_unref(p->frame);
> > > > +        p->result = 0;  
> 
> Shouldn't p->result be similarly reset together with p->got_frame also
> in ff_thread_decode_frame()? A similar problem seems possible:
> - a normal decode call returns an error due to p->result being negative
> - drain packet is sent before cycling through all threads
> - the loop in ff_thread_decode_frame hits "if (p->result < 0)"
> Thus incorrectly returning the same error again from the drain packet.

Please send a patch.
diff mbox

Patch

diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 9a6b83ac45..7586f00bec 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -859,6 +859,7 @@  void ff_thread_flush(AVCodecContext *avctx)
         // Make sure decode flush calls with size=0 won't return old frames
         p->got_frame = 0;
         av_frame_unref(p->frame);
+        p->result = 0;
 
         release_delayed_buffers(p);