Message ID | TYSPR06MB6433019CEB35172181653C0DAA132@TYSPR06MB6433.apcprd06.prod.outlook.com |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel] avcodec/vvcdec: ff_vvc_frame_submit, avoid initializing task twice. | expand |
Context | Check | Description |
---|---|---|
yinshiyou/make_loongarch64 | success | Make finished |
yinshiyou/make_fate_loongarch64 | success | Make fate finished |
andriy/make_x86 | success | Make finished |
andriy/make_fate_x86 | success | Make fate finished |
On 21/04/2024 15:52, Nuo Mi wrote: > For some error bitstreams, a CTU belongs to two slices/entry points. > If the decoder initializes and submmits the CTU task twice, it may crash the program > or cause it to enter an infinite loop. > > Reported-by: Frank Plowman <post@frankplowman.com> > --- > libavcodec/vvc/dec.c | 7 +++++-- > libavcodec/vvc/thread.c | 43 ++++++++++++++++++++++++++++------------- > libavcodec/vvc/thread.h | 2 +- > 3 files changed, 36 insertions(+), 16 deletions(-) > > diff --git a/libavcodec/vvc/dec.c b/libavcodec/vvc/dec.c > index 6aeec27eaf..4f7d184e43 100644 > --- a/libavcodec/vvc/dec.c > +++ b/libavcodec/vvc/dec.c > @@ -893,10 +893,13 @@ static int wait_delayed_frame(VVCContext *s, AVFrame *output, int *got_output) > > static int submit_frame(VVCContext *s, VVCFrameContext *fc, AVFrame *output, int *got_output) > { > - int ret; > + int ret = ff_vvc_frame_submit(s, fc); > + if (ret < 0) > + return ret; > + > s->nb_frames++; > s->nb_delayed++; > - ff_vvc_frame_submit(s, fc); > + > if (s->nb_delayed >= s->nb_fcs) { > if ((ret = wait_delayed_frame(s, output, got_output)) < 0) > return ret; > diff --git a/libavcodec/vvc/thread.c b/libavcodec/vvc/thread.c > index 01c3ff75b1..3b27811db2 100644 > --- a/libavcodec/vvc/thread.c > +++ b/libavcodec/vvc/thread.c > @@ -124,11 +124,17 @@ static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const > atomic_store(&t->target_inter_score, 0); > } > > -static void task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx) > +static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx) > { > + if (t->sc) { > + // the task already inited, error bitstream > + return AVERROR_INVALIDDATA; > + } > t->sc = sc; > t->ep = ep; > t->ctu_idx = ctu_idx; > + > + return 0; > } > > static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage) > @@ -758,24 +764,35 @@ static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext * > frame_thread_add_score(s, ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE); > } > > -void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) > +int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) > { > VVCFrameThread *ft = fc->ft; > > - for (int i = 0; i < fc->nb_slices; i++) { > - SliceContext *sc = fc->slices[i]; > - for (int j = 0; j < sc->nb_eps; j++) { > - EntryPoint *ep = sc->eps + j; > - for (int k = ep->ctu_start; k < ep->ctu_end; k++) { > - const int rs = sc->sh.ctb_addr_in_curr_slice[k]; > - VVCTask *t = ft->tasks + rs; > - > - task_init_parse(t, sc, ep, k); > - check_colocation(s, t); > + // We'll handle this in two passes: > + // Pass 0 to initialize tasks with parser, this will help detect bit stream error > + // Pass 1 to shedule location check and submit the entry point > + for (int pass = 0; pass < 2; pass++) { > + for (int i = 0; i < fc->nb_slices; i++) { > + SliceContext *sc = fc->slices[i]; > + for (int j = 0; j < sc->nb_eps; j++) { > + EntryPoint *ep = sc->eps + j; > + for (int k = ep->ctu_start; k < ep->ctu_end; k++) { > + const int rs = sc->sh.ctb_addr_in_curr_slice[k]; > + VVCTask *t = ft->tasks + rs; > + if (pass) { > + check_colocation(s, t); > + } else { > + const int ret = task_init_parse(t, sc, ep, k); > + if (ret < 0) > + return ret; > + } > + } > + if (pass) > + submit_entry_point(s, ft, sc, ep); > } > - submit_entry_point(s, ft, sc, ep); > } > } > + return 0; > } > > int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc) > diff --git a/libavcodec/vvc/thread.h b/libavcodec/vvc/thread.h > index 55bb4ea244..8ac59b2ecf 100644 > --- a/libavcodec/vvc/thread.h > +++ b/libavcodec/vvc/thread.h > @@ -30,7 +30,7 @@ void ff_vvc_executor_free(struct AVExecutor **e); > > int ff_vvc_frame_thread_init(VVCFrameContext *fc); > void ff_vvc_frame_thread_free(VVCFrameContext *fc); > -void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc); > +int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc); > int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc); > > #endif // AVCODEC_VVC_THREAD_H This patch fixes most of the fuzz bitstreams I have which enter infinite loops, but also introduces a regression, turning some other bitstreams which were okay before into infinite loops.
Thank you, Frank Fixed by v2 On Mon, Apr 22, 2024 at 12:34 AM Frank Plowman <post@frankplowman.com> wrote: > On 21/04/2024 15:52, Nuo Mi wrote: > > For some error bitstreams, a CTU belongs to two slices/entry points. > > If the decoder initializes and submmits the CTU task twice, it may crash > the program > > or cause it to enter an infinite loop. > > > > Reported-by: Frank Plowman <post@frankplowman.com> > > --- > > libavcodec/vvc/dec.c | 7 +++++-- > > libavcodec/vvc/thread.c | 43 ++++++++++++++++++++++++++++------------- > > libavcodec/vvc/thread.h | 2 +- > > 3 files changed, 36 insertions(+), 16 deletions(-) > > > > diff --git a/libavcodec/vvc/dec.c b/libavcodec/vvc/dec.c > > index 6aeec27eaf..4f7d184e43 100644 > > --- a/libavcodec/vvc/dec.c > > +++ b/libavcodec/vvc/dec.c > > @@ -893,10 +893,13 @@ static int wait_delayed_frame(VVCContext *s, > AVFrame *output, int *got_output) > > > > static int submit_frame(VVCContext *s, VVCFrameContext *fc, AVFrame > *output, int *got_output) > > { > > - int ret; > > + int ret = ff_vvc_frame_submit(s, fc); > > + if (ret < 0) > > + return ret; > > + > > s->nb_frames++; > > s->nb_delayed++; > > - ff_vvc_frame_submit(s, fc); > > + > > if (s->nb_delayed >= s->nb_fcs) { > > if ((ret = wait_delayed_frame(s, output, got_output)) < 0) > > return ret; > > diff --git a/libavcodec/vvc/thread.c b/libavcodec/vvc/thread.c > > index 01c3ff75b1..3b27811db2 100644 > > --- a/libavcodec/vvc/thread.c > > +++ b/libavcodec/vvc/thread.c > > @@ -124,11 +124,17 @@ static void task_init(VVCTask *t, VVCTaskStage > stage, VVCFrameContext *fc, const > > atomic_store(&t->target_inter_score, 0); > > } > > > > -static void task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint > *ep, const int ctu_idx) > > +static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint > *ep, const int ctu_idx) > > { > > + if (t->sc) { > > + // the task already inited, error bitstream > > + return AVERROR_INVALIDDATA; > > + } > > t->sc = sc; > > t->ep = ep; > > t->ctu_idx = ctu_idx; > > + > > + return 0; > > } > > > > static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage) > > @@ -758,24 +764,35 @@ static void submit_entry_point(VVCContext *s, > VVCFrameThread *ft, SliceContext * > > frame_thread_add_score(s, ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE); > > } > > > > -void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) > > +int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) > > { > > VVCFrameThread *ft = fc->ft; > > > > - for (int i = 0; i < fc->nb_slices; i++) { > > - SliceContext *sc = fc->slices[i]; > > - for (int j = 0; j < sc->nb_eps; j++) { > > - EntryPoint *ep = sc->eps + j; > > - for (int k = ep->ctu_start; k < ep->ctu_end; k++) { > > - const int rs = sc->sh.ctb_addr_in_curr_slice[k]; > > - VVCTask *t = ft->tasks + rs; > > - > > - task_init_parse(t, sc, ep, k); > > - check_colocation(s, t); > > + // We'll handle this in two passes: > > + // Pass 0 to initialize tasks with parser, this will help detect > bit stream error > > + // Pass 1 to shedule location check and submit the entry point > > + for (int pass = 0; pass < 2; pass++) { > > + for (int i = 0; i < fc->nb_slices; i++) { > > + SliceContext *sc = fc->slices[i]; > > + for (int j = 0; j < sc->nb_eps; j++) { > > + EntryPoint *ep = sc->eps + j; > > + for (int k = ep->ctu_start; k < ep->ctu_end; k++) { > > + const int rs = sc->sh.ctb_addr_in_curr_slice[k]; > > + VVCTask *t = ft->tasks + rs; > > + if (pass) { > > + check_colocation(s, t); > > + } else { > > + const int ret = task_init_parse(t, sc, ep, k); > > + if (ret < 0) > > + return ret; > > + } > > + } > > + if (pass) > > + submit_entry_point(s, ft, sc, ep); > > } > > - submit_entry_point(s, ft, sc, ep); > > } > > } > > + return 0; > > } > > > > int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc) > > diff --git a/libavcodec/vvc/thread.h b/libavcodec/vvc/thread.h > > index 55bb4ea244..8ac59b2ecf 100644 > > --- a/libavcodec/vvc/thread.h > > +++ b/libavcodec/vvc/thread.h > > @@ -30,7 +30,7 @@ void ff_vvc_executor_free(struct AVExecutor **e); > > > > int ff_vvc_frame_thread_init(VVCFrameContext *fc); > > void ff_vvc_frame_thread_free(VVCFrameContext *fc); > > -void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc); > > +int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc); > > int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc); > > > > #endif // AVCODEC_VVC_THREAD_H > > This patch fixes most of the fuzz bitstreams I have which enter infinite > loops, but also introduces a regression, turning some other bitstreams > which were okay before into infinite loops. > > -- > Frank > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". >
diff --git a/libavcodec/vvc/dec.c b/libavcodec/vvc/dec.c index 6aeec27eaf..4f7d184e43 100644 --- a/libavcodec/vvc/dec.c +++ b/libavcodec/vvc/dec.c @@ -893,10 +893,13 @@ static int wait_delayed_frame(VVCContext *s, AVFrame *output, int *got_output) static int submit_frame(VVCContext *s, VVCFrameContext *fc, AVFrame *output, int *got_output) { - int ret; + int ret = ff_vvc_frame_submit(s, fc); + if (ret < 0) + return ret; + s->nb_frames++; s->nb_delayed++; - ff_vvc_frame_submit(s, fc); + if (s->nb_delayed >= s->nb_fcs) { if ((ret = wait_delayed_frame(s, output, got_output)) < 0) return ret; diff --git a/libavcodec/vvc/thread.c b/libavcodec/vvc/thread.c index 01c3ff75b1..3b27811db2 100644 --- a/libavcodec/vvc/thread.c +++ b/libavcodec/vvc/thread.c @@ -124,11 +124,17 @@ static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const atomic_store(&t->target_inter_score, 0); } -static void task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx) +static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx) { + if (t->sc) { + // the task already inited, error bitstream + return AVERROR_INVALIDDATA; + } t->sc = sc; t->ep = ep; t->ctu_idx = ctu_idx; + + return 0; } static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage) @@ -758,24 +764,35 @@ static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext * frame_thread_add_score(s, ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE); } -void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) +int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) { VVCFrameThread *ft = fc->ft; - for (int i = 0; i < fc->nb_slices; i++) { - SliceContext *sc = fc->slices[i]; - for (int j = 0; j < sc->nb_eps; j++) { - EntryPoint *ep = sc->eps + j; - for (int k = ep->ctu_start; k < ep->ctu_end; k++) { - const int rs = sc->sh.ctb_addr_in_curr_slice[k]; - VVCTask *t = ft->tasks + rs; - - task_init_parse(t, sc, ep, k); - check_colocation(s, t); + // We'll handle this in two passes: + // Pass 0 to initialize tasks with parser, this will help detect bit stream error + // Pass 1 to shedule location check and submit the entry point + for (int pass = 0; pass < 2; pass++) { + for (int i = 0; i < fc->nb_slices; i++) { + SliceContext *sc = fc->slices[i]; + for (int j = 0; j < sc->nb_eps; j++) { + EntryPoint *ep = sc->eps + j; + for (int k = ep->ctu_start; k < ep->ctu_end; k++) { + const int rs = sc->sh.ctb_addr_in_curr_slice[k]; + VVCTask *t = ft->tasks + rs; + if (pass) { + check_colocation(s, t); + } else { + const int ret = task_init_parse(t, sc, ep, k); + if (ret < 0) + return ret; + } + } + if (pass) + submit_entry_point(s, ft, sc, ep); } - submit_entry_point(s, ft, sc, ep); } } + return 0; } int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc) diff --git a/libavcodec/vvc/thread.h b/libavcodec/vvc/thread.h index 55bb4ea244..8ac59b2ecf 100644 --- a/libavcodec/vvc/thread.h +++ b/libavcodec/vvc/thread.h @@ -30,7 +30,7 @@ void ff_vvc_executor_free(struct AVExecutor **e); int ff_vvc_frame_thread_init(VVCFrameContext *fc); void ff_vvc_frame_thread_free(VVCFrameContext *fc); -void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc); +int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc); int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc); #endif // AVCODEC_VVC_THREAD_H