[FFmpeg-devel] [PATCH 1/4] fftools/cmdutils: Atomically add elements to list of pointers, fix crash

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Sun Dec 5 13:35:21 EET 2021


Andreas Rheinhardt:
> Currently, adding a (separately allocated) element to a list of pointers
> works by first reallocating the array of pointers and (on success)
> incrementing its size and only then allocating the new element.
> If the latter allocation fails, the size is inconsistent, i.e.
> array[nb_array_elems - 1] is NULL. Our cleanup code crashes in such
> scenarios.
> 
> Fix this by adding an auxiliary function that atomically allocates
> and adds a new element to a list of pointers.
> 
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>
> ---
>  fftools/cmdutils.c      | 16 ++++++++++++++++
>  fftools/cmdutils.h      | 17 +++++++++++++++++
>  fftools/ffmpeg_filter.c | 17 ++++-------------
>  fftools/ffmpeg_opt.c    | 22 ++++++----------------
>  4 files changed, 43 insertions(+), 29 deletions(-)
> 
> diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
> index 45322f8c71..1464b122df 100644
> --- a/fftools/cmdutils.c
> +++ b/fftools/cmdutils.c
> @@ -2214,6 +2214,22 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
>      return array;
>  }
>  
> +void *allocate_array_elem(void *ptr, size_t elem_size, int *nb_elems)
> +{
> +    void *new_elem, **array = (void**)ptr;
> +
> +    if (*nb_elems == INT_MAX) {
> +        av_log(NULL, AV_LOG_ERROR, "Array too big.\n");
> +        exit_program(1);
> +    }
> +    new_elem = av_mallocz(elem_size);
> +    if (!new_elem)
> +        exit_program(1);
> +    GROW_ARRAY(array, *nb_elems);
> +    array[*nb_elems - 1] = new_elem;
> +    return array;
> +}
> +
>  double get_rotation(int32_t *displaymatrix)
>  {
>      double theta = 0;
> diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h
> index 64dd7266bc..ae78e60f4c 100644
> --- a/fftools/cmdutils.h
> +++ b/fftools/cmdutils.h
> @@ -628,11 +628,28 @@ FILE *get_preset_file(char *filename, size_t filename_size,
>   */
>  void *grow_array(void *array, int elem_size, int *size, int new_size);
>  
> +/**
> + * Atomically add a new element to an array of pointers, i.e. allocate
> + * a new entry, reallocate the array of pointers and make the new last
> + * member of this array point to the newly allocated buffer.
> + * Calls exit() on failure.
> + *
> + * @param array     array of pointers to reallocate
> + * @param elem_size size of the new element to allocate
> + * @param nb_elems  pointer to the number of elements of the array array;
> + *                  *nb_elems will be incremented by one by this function.
> + * @return reallocated array
> + */
> +void *allocate_array_elem(void *array, size_t elem_size, int *nb_elems);
> +
>  #define media_type_string av_get_media_type_string
>  
>  #define GROW_ARRAY(array, nb_elems)\
>      array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1)
>  
> +#define ALLOC_ARRAY_ELEM(array, nb_elems)\
> +    array = allocate_array_elem(array, sizeof(*array[0]), &nb_elems)
> +
>  #define GET_PIX_FMT_NAME(pix_fmt)\
>      const char *name = av_get_pix_fmt_name(pix_fmt);
>  
> diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
> index dab0f28819..75194fe66e 100644
> --- a/fftools/ffmpeg_filter.c
> +++ b/fftools/ffmpeg_filter.c
> @@ -164,18 +164,14 @@ int init_simple_filtergraph(InputStream *ist, OutputStream *ost)
>          exit_program(1);
>      fg->index = nb_filtergraphs;
>  
> -    GROW_ARRAY(fg->outputs, fg->nb_outputs);
> -    if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0]))))
> -        exit_program(1);
> +    ALLOC_ARRAY_ELEM(fg->outputs, fg->nb_outputs);
>      fg->outputs[0]->ost   = ost;
>      fg->outputs[0]->graph = fg;
>      fg->outputs[0]->format = -1;
>  
>      ost->filter = fg->outputs[0];
>  
> -    GROW_ARRAY(fg->inputs, fg->nb_inputs);
> -    if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
> -        exit_program(1);
> +    ALLOC_ARRAY_ELEM(fg->inputs, fg->nb_inputs);
>      fg->inputs[0]->ist   = ist;
>      fg->inputs[0]->graph = fg;
>      fg->inputs[0]->format = -1;
> @@ -280,9 +276,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
>      ist->decoding_needed |= DECODING_FOR_FILTER;
>      ist->st->discard = AVDISCARD_NONE;
>  
> -    GROW_ARRAY(fg->inputs, fg->nb_inputs);
> -    if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0]))))
> -        exit_program(1);
> +    ALLOC_ARRAY_ELEM(fg->inputs, fg->nb_inputs);
>      fg->inputs[fg->nb_inputs - 1]->ist   = ist;
>      fg->inputs[fg->nb_inputs - 1]->graph = fg;
>      fg->inputs[fg->nb_inputs - 1]->format = -1;
> @@ -318,10 +312,7 @@ int init_complex_filtergraph(FilterGraph *fg)
>          init_input_filter(fg, cur);
>  
>      for (cur = outputs; cur;) {
> -        GROW_ARRAY(fg->outputs, fg->nb_outputs);
> -        fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0]));
> -        if (!fg->outputs[fg->nb_outputs - 1])
> -            exit_program(1);
> +        ALLOC_ARRAY_ELEM(fg->outputs, fg->nb_outputs);
>  
>          fg->outputs[fg->nb_outputs - 1]->graph   = fg;
>          fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
> diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
> index a27263b879..ffba7010e3 100644
> --- a/fftools/ffmpeg_opt.c
> +++ b/fftools/ffmpeg_opt.c
> @@ -1265,11 +1265,8 @@ static int open_input_file(OptionsContext *o, const char *filename)
>      /* dump the file content */
>      av_dump_format(ic, nb_input_files, filename, 0);
>  
> -    GROW_ARRAY(input_files, nb_input_files);
> -    f = av_mallocz(sizeof(*f));
> -    if (!f)
> -        exit_program(1);
> -    input_files[nb_input_files - 1] = f;
> +    ALLOC_ARRAY_ELEM(input_files, nb_input_files);
> +    f = input_files[nb_input_files - 1];
>  
>      f->ctx        = ic;
>      f->ist_index  = nb_input_streams - ic->nb_streams;
> @@ -2261,11 +2258,8 @@ static int open_output_file(OptionsContext *o, const char *filename)
>          }
>      }
>  
> -    GROW_ARRAY(output_files, nb_output_files);
> -    of = av_mallocz(sizeof(*of));
> -    if (!of)
> -        exit_program(1);
> -    output_files[nb_output_files - 1] = of;
> +    ALLOC_ARRAY_ELEM(output_files, nb_output_files);
> +    of = output_files[nb_output_files - 1];
>  
>      of->ost_index      = nb_output_streams;
>      of->recording_time = o->recording_time;
> @@ -3262,9 +3256,7 @@ static int opt_audio_qscale(void *optctx, const char *opt, const char *arg)
>  
>  static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
>  {
> -    GROW_ARRAY(filtergraphs, nb_filtergraphs);
> -    if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
> -        return AVERROR(ENOMEM);
> +    ALLOC_ARRAY_ELEM(filtergraphs, nb_filtergraphs);
>      filtergraphs[nb_filtergraphs - 1]->index      = nb_filtergraphs - 1;
>      filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg);
>      if (!filtergraphs[nb_filtergraphs - 1]->graph_desc)
> @@ -3281,9 +3273,7 @@ static int opt_filter_complex_script(void *optctx, const char *opt, const char *
>      if (!graph_desc)
>          return AVERROR(EINVAL);
>  
> -    GROW_ARRAY(filtergraphs, nb_filtergraphs);
> -    if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
> -        return AVERROR(ENOMEM);
> +    ALLOC_ARRAY_ELEM(filtergraphs, nb_filtergraphs);
>      filtergraphs[nb_filtergraphs - 1]->index      = nb_filtergraphs - 1;
>      filtergraphs[nb_filtergraphs - 1]->graph_desc = graph_desc;
>  
> 

Will apply this patchset tonight unless there are objections.

- Andreas


More information about the ffmpeg-devel mailing list