[FFmpeg-devel] [PATCH] avcodec/cbs: Allocate more CodedBitstreamUnit at once in cbs_insert_unit()

James Almer jamrial at gmail.com
Sat Apr 11 06:29:37 EEST 2020


On 4/10/2020 11:49 PM, James Almer wrote:
> On 4/10/2020 9:00 PM, James Almer wrote:
>> On 4/10/2020 8:53 PM, Michael Niedermayer wrote:
>>> On Fri, Apr 10, 2020 at 05:44:25PM -0300, James Almer wrote:
>>>> On 4/10/2020 5:23 PM, Michael Niedermayer wrote:
>>>>> Fixes: Timeout (85sec -> 0.5sec)
>>>>> Fixes: 20791/clusterfuzz-testcase-minimized-ffmpeg_BSF_AV1_FRAME_SPLIT_fuzzer-5659537719951360
>>>>> Fixes: 21214/clusterfuzz-testcase-minimized-ffmpeg_BSF_MPEG2_METADATA_fuzzer-5165560875974656
>>>>> Fixes: 21247/clusterfuzz-testcase-minimized-ffmpeg_BSF_H264_METADATA_fuzzer-5715175257931776
>>>>>
>>>>> Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
>>>>> Signed-off-by: Michael Niedermayer <michael at niedermayer.cc>
>>>>> ---
>>>>>  libavcodec/cbs.c | 4 ++--
>>>>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
>>>>> index 0bd5e1ac5d..42cb9711fa 100644
>>>>> --- a/libavcodec/cbs.c
>>>>> +++ b/libavcodec/cbs.c
>>>>> @@ -693,11 +693,11 @@ static int cbs_insert_unit(CodedBitstreamContext *ctx,
>>>>>              memmove(units + position + 1, units + position,
>>>>>                      (frag->nb_units - position) * sizeof(*units));
>>>>>      } else {
>>>>> -        units = av_malloc_array(frag->nb_units + 1, sizeof(*units));
>>>>> +        units = av_malloc_array(frag->nb_units*2 + 1, sizeof(*units));
>>>>>          if (!units)
>>>>>              return AVERROR(ENOMEM);
>>>>>  
>>>>> -        ++frag->nb_units_allocated;
>>>>> +        frag->nb_units_allocated = 2*frag->nb_units_allocated + 1;
>>>>
>>>> Use ff_fast_malloc(), please. This is quite ugly and the *2 undocumented
>>>> and not obvious.
>>>
>>> not sure i understood your suggestion correctly but 
>>> ff_fast_malloc() deallocates its buffer and clears the size on error, 
>>> which cbs_insert_unit() does not do.
>>> so using ff_fast_malloc() feels a bit like fitting a square peg in a round
>>> hole. But it works too
>>> is that what you had in mind ? (your comment sounded like something simpler ...)
>>> so maybe iam missing something
>>
>> No, after thinking about it i realized it was not the best option and i
>> sent a follow up reply about it, but i guess it was too late. If you
>> have to change the implementation of ff_fast_malloc() then it's clearly
>> not what should be used here. I didn't intend you to do this much work.
>>
>> av_fast_realloc() could work instead as i mentioned in the follow up
>> reply, i think. Or porting this to AVTreeNode instead of a flat array,
>> but that's also quite a bit of work and will still allocate one node per
>> call, so your fuzzer cases may still timeout. So if av_fast_realloc() is
>> also not an option then maybe increase the buffer by a
>> small-but-bigger-than-1 amount of units instead of duplicating its size
>> each call, which can get quite big pretty fast.
> 
> Here's a version using av_fast_realloc(). FATE passes. Does it solve the
> timeout?
> 
> diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
> index 0bd5e1ac5d..d6cb94589f 100644
> --- a/libavcodec/cbs.c
> +++ b/libavcodec/cbs.c
> @@ -161,6 +161,7 @@ void ff_cbs_fragment_free(CodedBitstreamContext *ctx,
> 
>      av_freep(&frag->units);
>      frag->nb_units_allocated = 0;
> +    frag->unit_buffer_size = 0;
>  }
> 
>  static int cbs_read_fragment_content(CodedBitstreamContext *ctx,
> @@ -684,35 +685,29 @@ static int cbs_insert_unit(CodedBitstreamContext *ctx,
>                             CodedBitstreamFragment *frag,
>                             int position)
>  {
> -    CodedBitstreamUnit *units;
> +    CodedBitstreamUnit *units = frag->units;
> 
> -    if (frag->nb_units < frag->nb_units_allocated) {
> -        units = frag->units;
> +    if (frag->nb_units >= frag->nb_units_allocated) {
> +        size_t new_size;
> +        void *tmp;
> 
> -        if (position < frag->nb_units)
> -            memmove(units + position + 1, units + position,
> -                    (frag->nb_units - position) * sizeof(*units));
> -    } else {
> -        units = av_malloc_array(frag->nb_units + 1, sizeof(*units));
> -        if (!units)
> +        if (av_size_mult(frag->nb_units + 1, sizeof(*units), &new_size))
>              return AVERROR(ENOMEM);
> 
> -        ++frag->nb_units_allocated;
> -
> -        if (position > 0)
> -            memcpy(units, frag->units, position * sizeof(*units));
> +        tmp = av_fast_realloc(units, &frag->unit_buffer_size,
> +                              new_size * sizeof(*units));

Should be new_size alone, sorry. av_size_mult() already stored the
result of this calculation in there.

Also, if you can't apply this diff because my mail client mangled it, i
can re-send it as a proper patch.

> +        if (!tmp)
> +            return AVERROR(ENOMEM);
> 
> -        if (position < frag->nb_units)
> -            memcpy(units + position + 1, frag->units + position,
> -                   (frag->nb_units - position) * sizeof(*units));
> +        frag->units = units = tmp;
> +        ++frag->nb_units_allocated;
>      }
> 
> -    memset(units + position, 0, sizeof(*units));
> +    if (position < frag->nb_units)
> +        memmove(units + position + 1, units + position,
> +                (frag->nb_units - position) * sizeof(*units));
> 
> -    if (units != frag->units) {
> -        av_free(frag->units);
> -        frag->units = units;
> -    }
> +    memset(units + position, 0, sizeof(*units));
> 
>      ++frag->nb_units;
> 
> diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h
> index 9ca1fbd609..4833a8a3db 100644
> --- a/libavcodec/cbs.h
> +++ b/libavcodec/cbs.h
> @@ -153,6 +153,13 @@ typedef struct CodedBitstreamFragment {
>       */
>       int             nb_units_allocated;
> 
> +    /**
> +     * Size of allocated unit buffer.
> +     *
> +     * Must always be >= nb_units_allocated; designed for internal use
> by cbs.
> +     */
> +     unsigned int    unit_buffer_size;
> +
>      /**
>       * Pointer to an array of units of length nb_units_allocated.
>       * Only the first nb_units are valid.
> 



More information about the ffmpeg-devel mailing list