diff mbox series

[FFmpeg-devel,12/12] avutil/opt: Don't cast when the result might be misaligned

Message ID GV1P250MB0737DD6DF8B0DF2F3FB6C58D8F362@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM
State Accepted
Commit c85477f78d7916b663bd09169c7ce8d4d345bca3
Headers show
Series [FFmpeg-devel,01/10] doc/examples: Always use <> includes | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished

Commit Message

Andreas Rheinhardt March 25, 2024, 3:11 p.m. UTC
A pointer conversion is UB if the resulting pointer is not
correctly aligned for the resultant type, even if no
load/store is ever performed through that pointer (C11 6.3.2.3 (7)).

This may happen in opt_copy_elem(), because the pointers are
converted even when they belong to a type that does not guarantee
sufficient alignment.

Fix this by deferring the cast after having checked the type.
Also make the casts -Wcast-qual safe and avoid an indirection
for src.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavutil/opt.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)
diff mbox series

Patch

diff --git a/libavutil/opt.c b/libavutil/opt.c
index 3130606337..5fa8870707 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -2028,18 +2028,19 @@  void *av_opt_ptr(const AVClass *class, void *obj, const char *name)
 static int opt_copy_elem(void *logctx, enum AVOptionType type,
                          void *dst, const void *src)
 {
-    uint8_t       **dst8 =       (uint8_t **)dst;
-    const uint8_t **src8 = (const uint8_t **)src;
-
     if (type == AV_OPT_TYPE_STRING) {
-        if (*dst8 != *src8)
-            av_freep(dst8);
-        if (*src8) {
-            *dst8 = av_strdup(*src8);
-            if (!*dst8)
+        const char *src_str = *(const char *const *)src;
+        char         **dstp =  (char **)dst;
+        if (*dstp != src_str)
+            av_freep(dstp);
+        if (src_str) {
+            *dstp = av_strdup(src_str);
+            if (!*dstp)
                 return AVERROR(ENOMEM);
         }
     } else if (type == AV_OPT_TYPE_BINARY) {
+        const uint8_t *const *src8 = (const uint8_t *const *)src;
+        uint8_t             **dst8 = (uint8_t **)dst;
         int len = *(const int *)(src8 + 1);
         if (*dst8 != *src8)
             av_freep(dst8);
@@ -2052,12 +2053,12 @@  static int opt_copy_elem(void *logctx, enum AVOptionType type,
     } else if (type == AV_OPT_TYPE_CONST) {
         // do nothing
     } else if (type == AV_OPT_TYPE_DICT) {
-        AVDictionary **sdict = (AVDictionary **)src;
-        AVDictionary **ddict = (AVDictionary **)dst;
-        if (*sdict != *ddict)
-            av_dict_free(ddict);
-        *ddict = NULL;
-        return av_dict_copy(ddict, *sdict, 0);
+        const AVDictionary *sdict = *(const AVDictionary * const *)src;
+        AVDictionary     **ddictp = (AVDictionary **)dst;
+        if (sdict != *ddictp)
+            av_dict_free(ddictp);
+        *ddictp = NULL;
+        return av_dict_copy(ddictp, sdict, 0);
     } else if (type == AV_OPT_TYPE_CHLAYOUT) {
         if (dst != src)
             return av_channel_layout_copy(dst, src);