[FFmpeg-devel] [PATCH v2 2/2] lavc/vvc: Add max parameter to kth_order_egk_decode
Nuo Mi
nuomi2021 at gmail.com
Thu Jul 17 13:10:08 EEST 2025
Hi Frank,
Thank you for v2.
On Wed, Jul 16, 2025 at 2:50 AM Frank Plowman <post at frankplowman.com> wrote:
> Prior to this patch, kth_order_egk_decode could read arbitrarily
> large values which then overflowed and caused various issues.
> Patch fixes this by making kth_order_egk_decode falliable,
> requiring the caller to specify an upper bound and returning an
> error if the read value would exceed that bound.
>
> This patch resolves the same issue as
> eb52251c0ab025b6b40b28994bc9dc616813b190, but I think this is the proper
> fix as it also addresses issues with syntax elements besides
> ff_vvc_num_signalled_palette_entries.
>
> Patch also includes a minor fix in hls_palette_coding, where the
> error code returned by palette_subblock_data was previously unchecked.
>
> Signed-off-by: Frank Plowman <post at frankplowman.com>
> ---
> Changes since v1:
> * Split change to hls_palette_coding to its own commit.
> * Return values from syntax functions in return val, rather than by
> modifying pointer parameter.
> ---
> libavcodec/vvc/cabac.c | 19 ++++++++++++-------
> libavcodec/vvc/cabac.h | 6 +++---
> libavcodec/vvc/ctu.c | 30 ++++++++++++++++++------------
> 3 files changed, 33 insertions(+), 22 deletions(-)
>
> diff --git a/libavcodec/vvc/cabac.c b/libavcodec/vvc/cabac.c
> index 6847ce59af..c2dbd46709 100644
> --- a/libavcodec/vvc/cabac.c
> +++ b/libavcodec/vvc/cabac.c
> @@ -929,7 +929,7 @@ static int truncated_binary_decode(VVCLocalContext
> *lc, const int c_max)
> }
>
> // 9.3.3.5 k-th order Exp - Golomb binarization process
> -static int kth_order_egk_decode(CABACContext *c, int k)
> +static int kth_order_egk_decode(CABACContext *c, int k, const int max)
> {
> int bit = 1;
> int value = 0;
> @@ -937,6 +937,8 @@ static int kth_order_egk_decode(CABACContext *c, int k)
>
> while (bit) {
> bit = get_cabac_bypass(c);
> + if (max - value < (bit << k))
> + return AVERROR_INVALIDDATA;
> value += bit << k++;
> }
>
> @@ -946,6 +948,9 @@ static int kth_order_egk_decode(CABACContext *c, int k)
> value += symbol;
> }
>
> + if (value > max)
> + return AVERROR_INVALIDDATA;
> +
> return value;
> }
>
> @@ -1377,14 +1382,14 @@ int ff_vvc_intra_chroma_pred_mode(VVCLocalContext
> *lc)
> return (get_cabac_bypass(&lc->ep->cc) << 1) |
> get_cabac_bypass(&lc->ep->cc);
> }
>
> -int ff_vvc_palette_predictor_run(VVCLocalContext *lc)
> +int ff_vvc_palette_predictor_run(VVCLocalContext *lc, const int max)
> {
> - return kth_order_egk_decode(&lc->ep->cc, 0);
> + return kth_order_egk_decode(&lc->ep->cc, 0, max);
> }
>
> -int ff_vvc_num_signalled_palette_entries(VVCLocalContext *lc)
> +int ff_vvc_num_signalled_palette_entries(VVCLocalContext *lc, const int
> max)
> {
> - return kth_order_egk_decode(&lc->ep->cc, 0);
> + return kth_order_egk_decode(&lc->ep->cc, 0, max);
> }
>
> int ff_vvc_new_palette_entries(VVCLocalContext *lc, const int bit_depth)
> @@ -1424,9 +1429,9 @@ int ff_vvc_palette_idx_idc(VVCLocalContext *lc,
> const int max_palette_index, con
> return truncated_binary_decode(lc, max_palette_index - adjust);
> }
>
> -int ff_vvc_palette_escape_val(VVCLocalContext *lc)
> +int ff_vvc_palette_escape_val(VVCLocalContext *lc, const int max)
> {
> - return kth_order_egk_decode(&lc->ep->cc, 5);
> + return kth_order_egk_decode(&lc->ep->cc, 5, max);
> }
>
> int ff_vvc_general_merge_flag(VVCLocalContext *lc)
> diff --git a/libavcodec/vvc/cabac.h b/libavcodec/vvc/cabac.h
> index 972890317e..6a0e713d19 100644
> --- a/libavcodec/vvc/cabac.h
> +++ b/libavcodec/vvc/cabac.h
> @@ -81,15 +81,15 @@ int ff_vvc_intra_luma_mpm_remainder(VVCLocalContext
> *lc);
> int ff_vvc_cclm_mode_flag(VVCLocalContext *lc);
> int ff_vvc_cclm_mode_idx(VVCLocalContext *lc);
> int ff_vvc_intra_chroma_pred_mode(VVCLocalContext *lc);
> -int ff_vvc_palette_predictor_run(VVCLocalContext *lc);
> -int ff_vvc_num_signalled_palette_entries(VVCLocalContext *lc);
> +int ff_vvc_palette_predictor_run(VVCLocalContext *lc, const int max);
> +int ff_vvc_num_signalled_palette_entries(VVCLocalContext *lc, const int
> max);
> int ff_vvc_new_palette_entries(VVCLocalContext *lc, int bit_dpeth);
> bool ff_vvc_palette_escape_val_present_flag(VVCLocalContext *lc);
> bool ff_vvc_palette_transpose_flag(VVCLocalContext *lc);
> bool ff_vvc_run_copy_flag(VVCLocalContext *lc, int prev_run_type, int
> prev_run_position, int cur_pos);
> bool ff_vvc_copy_above_palette_indices_flag(VVCLocalContext *lc);
> int ff_vvc_palette_idx_idc(VVCLocalContext *lc, int max_palette_index,
> bool adjust);
> -int ff_vvc_palette_escape_val(VVCLocalContext *lc);
> +int ff_vvc_palette_escape_val(VVCLocalContext *lc, const int max);
>
> //inter
> int ff_vvc_general_merge_flag(VVCLocalContext *lc);
> diff --git a/libavcodec/vvc/ctu.c b/libavcodec/vvc/ctu.c
> index 35c18e78f6..9f875d0a20 100644
> --- a/libavcodec/vvc/ctu.c
> +++ b/libavcodec/vvc/ctu.c
> @@ -1857,16 +1857,16 @@ static int palette_predicted(VVCLocalContext *lc,
> const bool local_dual_tree, in
> }
>
> for (int i = 0; i < predictor_size && nb_predicted < max_entries;
> i++) {
> - const int run = ff_vvc_palette_predictor_run(lc);
> + const int run = ff_vvc_palette_predictor_run(lc, predictor_size -
> i);
> + if (run < 0)
> + return run;
> +
> if (run == 1)
> break;
>
> if (run > 1)
> i += run - 1;
>
> - if (i >= predictor_size)
> - return AVERROR_INVALIDDATA;
> -
> predictor_reused[i] = true;
> for (int c = start; c < end; c++)
> cu->plt[c].entries[nb_predicted] = lc->ep->pp[c].entries[i];
> @@ -1885,12 +1885,17 @@ static int palette_signaled(VVCLocalContext *lc,
> const bool local_dual_tree,
> const VVCSPS *sps = lc->fc->ps.sps;
> CodingUnit *cu = lc->cu;
> const int nb_predicted = cu->plt[start].size;
> - const int nb_signaled = nb_predicted < max_entries ?
> ff_vvc_num_signalled_palette_entries(lc) : 0;
> - const int size = nb_predicted + nb_signaled;
> const bool dual_tree_luma = local_dual_tree && cu->tree_type ==
> DUAL_TREE_LUMA;
> + int nb_signaled, size;
>
> - if (size > max_entries || nb_signaled < 0)
> - return AVERROR_INVALIDDATA;
> + if (nb_predicted < max_entries) {
> + nb_signaled = ff_vvc_num_signalled_palette_entries(lc,
> max_entries - nb_predicted);
> + if (nb_signaled < 0)
> + return nb_signaled;
> + } else
> + nb_signaled = 0;
> +
> + size = nb_predicted + nb_signaled;
Most changes are not needed.
We only need to change one line:
const int nb_signaled = nb_predicted < max_entries ?
ff_vvc_num_signalled_palette_entries(lc, max_entries - nb_predicted) : 0;
>
> for (int c = start; c < end; c++) {
> Palette *plt = cu->plt + c;
> @@ -2052,10 +2057,11 @@ static int palette_subblock_data(VVCLocalContext
> *lc,
> if (!(xc & hs) && !(yc & vs)) {
> const int v = PALETTE_INDEX(xc, yc);
> if (v == esc) {
> - const int coeff = ff_vvc_palette_escape_val(lc);
> - if (coeff >= (1U << sps->bit_depth))
> - return AVERROR_INVALIDDATA;
> - const int pixel = av_clip_intp2(RSHIFT(coeff * scale,
> 6), sps->bit_depth);
> + int pixel;
> + const int coeff = ff_vvc_palette_escape_val(lc, (1 <<
> sps->bit_depth) - 1);
> + if (coeff < 0)
> + return coeff;
> + pixel = av_clip_intp2(RSHIFT(coeff * scale, 6),
> sps->bit_depth);
>
We only need to change two lines:
ff_vvc_palette_escape_val(lc, (1 << sps->bit_depth) - 1)
and check coeff < 0
> PALETTE_SET_PIXEL(xc, yc, pixel);
> } else {
> PALETTE_SET_PIXEL(xc, yc, plt->entries[v]);
> --
> 2.47.0
>
>
More information about the ffmpeg-devel
mailing list