diff mbox series

[FFmpeg-devel,2/3] avutil/dict: Improve appending values

Message ID GV1P250MB07379DE5E17C55AF6A45A05C8F479@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM
State Accepted
Commit e867a29ec1eb71a5841e452a4f2bf946c096282a
Headers show
Series [FFmpeg-devel,1/3] avutil/dict: Fix memleak when using AV_DICT_APPEND | expand

Checks

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

Commit Message

Andreas Rheinhardt Sept. 13, 2022, 7:46 p.m. UTC
When appending two values (due to AV_DICT_APPEND), the earlier code
would first zero-allocate a buffer of the required size and then
copy both parts into it via av_strlcat(). This is problematic,
as it leads to quadratic performance in case of frequent enlargements.
Fix this by using av_realloc() (which is hopefully designed to handle
such cases in a better way than simply throwing the buffer we already
have away) and by copying the string via memcpy() (after all, we already
calculated the strlen of both strings).

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavutil/dict.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

Comments

Paul B Mahol Sept. 14, 2022, 12:32 p.m. UTC | #1
On 9/13/22, Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
> When appending two values (due to AV_DICT_APPEND), the earlier code
> would first zero-allocate a buffer of the required size and then
> copy both parts into it via av_strlcat(). This is problematic,
> as it leads to quadratic performance in case of frequent enlargements.
> Fix this by using av_realloc() (which is hopefully designed to handle
> such cases in a better way than simply throwing the buffer we already
> have away) and by copying the string via memcpy() (after all, we already
> calculated the strlen of both strings).
>
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
>  libavutil/dict.c | 13 +++++++------
>  1 file changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/libavutil/dict.c b/libavutil/dict.c
> index c01165634e..1968063b0b 100644
> --- a/libavutil/dict.c
> +++ b/libavutil/dict.c
> @@ -98,16 +98,17 @@ int av_dict_set(AVDictionary **pm, const char *key,
> const char *value,
>              return 0;
>          }
>          if (copy_value && flags & AV_DICT_APPEND) {
> -            size_t len = strlen(tag->value) + strlen(copy_value) + 1;
> -            char *newval = av_mallocz(len);
> +            size_t oldlen = strlen(tag->value);
> +            size_t new_part_len = strlen(copy_value);
> +            size_t len = oldlen + new_part_len + 1;
> +            char *newval = av_realloc(tag->value, len);
>              if (!newval)
>                  goto err_out;
> -            av_strlcat(newval, tag->value, len);
> -            av_strlcat(newval, copy_value, len);
> +            memcpy(newval + oldlen, copy_value, new_part_len + 1);
>              av_freep(&copy_value);
>              copy_value = newval;
> -        }
> -        av_free(tag->value);
> +        } else
> +            av_free(tag->value);
>          av_free(tag->key);
>          *tag = m->elems[--m->count];
>      } else if (copy_value) {
> --
> 2.34.1
>


LGTM

> _______________________________________________
> 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 mbox series

Patch

diff --git a/libavutil/dict.c b/libavutil/dict.c
index c01165634e..1968063b0b 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -98,16 +98,17 @@  int av_dict_set(AVDictionary **pm, const char *key, const char *value,
             return 0;
         }
         if (copy_value && flags & AV_DICT_APPEND) {
-            size_t len = strlen(tag->value) + strlen(copy_value) + 1;
-            char *newval = av_mallocz(len);
+            size_t oldlen = strlen(tag->value);
+            size_t new_part_len = strlen(copy_value);
+            size_t len = oldlen + new_part_len + 1;
+            char *newval = av_realloc(tag->value, len);
             if (!newval)
                 goto err_out;
-            av_strlcat(newval, tag->value, len);
-            av_strlcat(newval, copy_value, len);
+            memcpy(newval + oldlen, copy_value, new_part_len + 1);
             av_freep(&copy_value);
             copy_value = newval;
-        }
-        av_free(tag->value);
+        } else
+            av_free(tag->value);
         av_free(tag->key);
         *tag = m->elems[--m->count];
     } else if (copy_value) {