Patches attached.

- Andreas
From 7cc1c15bb30c47edb354512fffb1f4148e7e0a9f Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Tue, 3 Jun 2025 21:38:41 +0200
Subject: [PATCH 1/9] avcodec/Makefile: Only compile hashtable.o when needed

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/Makefile | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index fb3fb7f7f7..4d0b9c2773 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -42,7 +42,6 @@ OBJS = ac3_parser.o                                                     \
        dv_profile.o                                                     \
        encode.o                                                         \
        get_buffer.o                                                     \
-       hashtable.o                                                      \
        imgconvert.o                                                     \
        jni.o                                                            \
        lcevcdec.o                                                       \
@@ -352,7 +351,7 @@ OBJS-$(CONFIG_DVVIDEO_ENCODER)         += dvenc.o dv.o dvdata.o
 OBJS-$(CONFIG_DXA_DECODER)             += dxa.o
 OBJS-$(CONFIG_DXTORY_DECODER)          += dxtory.o
 OBJS-$(CONFIG_DXV_DECODER)             += dxv.o
-OBJS-$(CONFIG_DXV_ENCODER)             += dxvenc.o
+OBJS-$(CONFIG_DXV_ENCODER)             += dxvenc.o hashtable.o
 OBJS-$(CONFIG_EAC3_DECODER)            += eac3_data.o
 OBJS-$(CONFIG_EAC3_ENCODER)            += eac3enc.o eac3_data.o
 OBJS-$(CONFIG_EACMV_DECODER)           += eacmv.o
@@ -1327,7 +1326,6 @@ TESTPROGS = avcodec                                                     \
             bitstream_le                                                \
             celp_math                                                   \
             codec_desc                                                  \
-            hashtable                                                   \
             htmlsubtitles                                               \
             jpeg2000dwt                                                 \
             mathops                                                    \
@@ -1337,6 +1335,7 @@ TESTPROGS-$(CONFIG_AV1_VAAPI_ENCODER)     += av1_levels
 TESTPROGS-$(CONFIG_CABAC)                 += cabac
 TESTPROGS-$(CONFIG_GOLOMB)                += golomb
 TESTPROGS-$(CONFIG_IDCTDSP)               += dct
+TESTPROGS-$(CONFIG_DXV_ENCODER)           += hashtable
 TESTPROGS-$(CONFIG_IIRFILTER)             += iirfilter
 TESTPROGS-$(CONFIG_MJPEG_ENCODER)         += mjpegenc_huffman
 TESTPROGS-$(HAVE_MMX)                     += motion
-- 
2.45.2

From 16164aa30b3ae3dd4e4cb79895431f86bb049c06 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Tue, 3 Jun 2025 21:42:24 +0200
Subject: [PATCH 2/9] avcodec/hashtable: Zero-initialize hashtable

Otherwise ff_hashtable_freep() would try to free uninitialized
pointers upon allocation error (which happens in the corresponding
test tool).

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/hashtable.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/hashtable.c b/libavcodec/hashtable.c
index 151476176b..4c7d3e18ba 100644
--- a/libavcodec/hashtable.c
+++ b/libavcodec/hashtable.c
@@ -58,7 +58,7 @@ struct FFHashtableContext {
 
 int ff_hashtable_alloc(struct FFHashtableContext **ctx, size_t key_size, size_t val_size, size_t max_entries)
 {
-    struct FFHashtableContext *res = av_malloc(sizeof(struct FFHashtableContext));
+    FFHashtableContext *res = av_mallocz(sizeof(*res));
     if (!res)
         return AVERROR(ENOMEM);
     res->key_size = key_size;
-- 
2.45.2

From aa330af12635009a05e9ff300ca4f7850ca531be Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Tue, 3 Jun 2025 21:58:58 +0200
Subject: [PATCH 3/9] tests/fate/libavcodec: Run hashtable test

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 tests/fate/libavcodec.mak | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak
index b69ad53f7c..361571aaee 100644
--- a/tests/fate/libavcodec.mak
+++ b/tests/fate/libavcodec.mak
@@ -43,6 +43,11 @@ fate-golomb: libavcodec/tests/golomb$(EXESUF)
 fate-golomb: CMD = run libavcodec/tests/golomb$(EXESUF)
 fate-golomb: CMP = null
 
+FATE_LIBAVCODEC-$(CONFIG_DXV_ENCODER) += fate-hashtable
+fate-hashtable: libavcodec/tests/hashtable$(EXESUF)
+fate-hashtable: CMD = run libavcodec/tests/hashtable$(EXESUF)
+fate-hashtable: CMP = null
+
 FATE_LIBAVCODEC-$(CONFIG_IDCTDSP) += fate-idct8x8-0 fate-idct8x8-1 fate-idct8x8-2 fate-idct248
 
 fate-idct8x8-0: libavcodec/tests/dct$(EXESUF)
-- 
2.45.2

From be43be1f8cdb18f54690da2bfbc050ab9af1614c Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Tue, 3 Jun 2025 22:08:46 +0200
Subject: [PATCH 4/9] avcodec/hashtable: Only align complete entries

It is unnecessary to align both key and val, as they are only accessed
via memcpy()/memcmp(), which has no alignment requirements.
We only need to ensure that that the entries as a whole
are suitable aligned for the probe sequence length.

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/hashtable.c | 24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)

diff --git a/libavcodec/hashtable.c b/libavcodec/hashtable.c
index 4c7d3e18ba..fa79330603 100644
--- a/libavcodec/hashtable.c
+++ b/libavcodec/hashtable.c
@@ -31,9 +31,7 @@
 
 struct FFHashtableContext {
     size_t key_size;
-    size_t key_size_aligned;
     size_t val_size;
-    size_t val_size_aligned;
     size_t entry_size;
     size_t max_entries;
     size_t nb_entries;
@@ -51,8 +49,8 @@ struct FFHashtableContext {
  */
 
 #define ENTRY_PSL_VAL(entry) (*(size_t*)(entry))
-#define ENTRY_KEY_PTR(entry) ((entry) + FFALIGN(sizeof(size_t), ALIGN))
-#define ENTRY_VAL_PTR(entry) (ENTRY_KEY_PTR(entry) + ctx->key_size_aligned)
+#define ENTRY_KEY_PTR(entry) ((entry) + sizeof(size_t))
+#define ENTRY_VAL_PTR(entry) (ENTRY_KEY_PTR(entry) + ctx->key_size)
 
 #define KEYS_EQUAL(k1, k2) (!memcmp((k1), (k2), ctx->key_size))
 
@@ -62,12 +60,8 @@ int ff_hashtable_alloc(struct FFHashtableContext **ctx, size_t key_size, size_t
     if (!res)
         return AVERROR(ENOMEM);
     res->key_size = key_size;
-    res->key_size_aligned = FFALIGN(key_size, ALIGN);
     res->val_size = val_size;
-    res->val_size_aligned = FFALIGN(val_size, ALIGN);
-    res->entry_size = FFALIGN(sizeof(size_t), ALIGN)
-                    + res->key_size_aligned
-                    + res->val_size_aligned;
+    res->entry_size = FFALIGN(sizeof(size_t) + key_size + val_size, ALIGN);
     res->max_entries = max_entries;
     res->nb_entries = 0;
     res->crc = av_crc_get_table(AV_CRC_32_IEEE);
@@ -81,7 +75,7 @@ int ff_hashtable_alloc(struct FFHashtableContext **ctx, size_t key_size, size_t
         return AVERROR(ENOMEM);
     }
 
-    res->swapbuf = av_calloc(2, res->key_size_aligned + res->val_size_aligned);
+    res->swapbuf = av_calloc(2, res->key_size + res->val_size);
     if (!res->swapbuf) {
         ff_hashtable_freep(&res);
         return AVERROR(ENOMEM);
@@ -124,10 +118,10 @@ int ff_hashtable_set(struct FFHashtableContext *ctx, const void *key, const void
     size_t hash = hash_key(ctx, key);
     size_t wrapped_index = hash % ctx->max_entries;
     uint8_t *set = ctx->swapbuf;
-    uint8_t *tmp = ctx->swapbuf + ctx->key_size_aligned + ctx->val_size_aligned;
+    uint8_t *tmp = ctx->swapbuf + ctx->key_size + ctx->val_size;
 
     memcpy(set, key, ctx->key_size);
-    memcpy(set + ctx->key_size_aligned, val, ctx->val_size);
+    memcpy(set + ctx->key_size, val, ctx->val_size);
 
     for (size_t i = 0; i < ctx->max_entries; i++) {
         if (++wrapped_index == ctx->max_entries)
@@ -137,7 +131,7 @@ int ff_hashtable_set(struct FFHashtableContext *ctx, const void *key, const void
             if (!ENTRY_PSL_VAL(entry))
                 ctx->nb_entries++;
             ENTRY_PSL_VAL(entry) = psl;
-            memcpy(ENTRY_KEY_PTR(entry), set, ctx->key_size_aligned + ctx->val_size);
+            memcpy(ENTRY_KEY_PTR(entry), set, ctx->key_size + ctx->val_size);
             return 1;
         }
         if (ENTRY_PSL_VAL(entry) < psl) {
@@ -151,8 +145,8 @@ int ff_hashtable_set(struct FFHashtableContext *ctx, const void *key, const void
             // PSL of the inserted entry.
             swapping = 1;
             // set needs to swap with entry
-            memcpy(tmp, ENTRY_KEY_PTR(entry), ctx->key_size_aligned + ctx->val_size_aligned);
-            memcpy(ENTRY_KEY_PTR(entry), set, ctx->key_size_aligned + ctx->val_size_aligned);
+            memcpy(tmp, ENTRY_KEY_PTR(entry), ctx->key_size + ctx->val_size);
+            memcpy(ENTRY_KEY_PTR(entry), set, ctx->key_size + ctx->val_size);
             FFSWAP(uint8_t*, set, tmp);
             FFSWAP(size_t, psl, ENTRY_PSL_VAL(entry));
         }
-- 
2.45.2

From 3407a2d3aa03360af4c7ad5037908946843ed3dc Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Tue, 3 Jun 2025 22:35:03 +0200
Subject: [PATCH 5/9] avcodec/hashtable: Check for overflow

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/hashtable.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libavcodec/hashtable.c b/libavcodec/hashtable.c
index fa79330603..ec8eca471f 100644
--- a/libavcodec/hashtable.c
+++ b/libavcodec/hashtable.c
@@ -56,12 +56,18 @@ struct FFHashtableContext {
 
 int ff_hashtable_alloc(struct FFHashtableContext **ctx, size_t key_size, size_t val_size, size_t max_entries)
 {
+    const size_t keyval_size = key_size + val_size;
+
+    if (keyval_size < key_size || // did (unsigned,defined) wraparound happen?
+        keyval_size > SIZE_MAX - sizeof(size_t) - (ALIGN - 1))
+        return AVERROR(ERANGE);
+
     FFHashtableContext *res = av_mallocz(sizeof(*res));
     if (!res)
         return AVERROR(ENOMEM);
     res->key_size = key_size;
     res->val_size = val_size;
-    res->entry_size = FFALIGN(sizeof(size_t) + key_size + val_size, ALIGN);
+    res->entry_size = FFALIGN(sizeof(size_t) + keyval_size, ALIGN);
     res->max_entries = max_entries;
     res->nb_entries = 0;
     res->crc = av_crc_get_table(AV_CRC_32_IEEE);
-- 
2.45.2

From 5437b460944bd27da9026b3a0edc0db69dea5275 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Tue, 3 Jun 2025 22:44:41 +0200
Subject: [PATCH 6/9] avcodec/hashtable: Combine allocations

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/hashtable.c | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/libavcodec/hashtable.c b/libavcodec/hashtable.c
index ec8eca471f..9b37ce3d69 100644
--- a/libavcodec/hashtable.c
+++ b/libavcodec/hashtable.c
@@ -37,7 +37,7 @@ struct FFHashtableContext {
     size_t nb_entries;
     const AVCRC *crc;
     uint8_t *table;
-    uint8_t *swapbuf;
+    uint8_t swapbuf[];
 };
 
 /*
@@ -59,10 +59,11 @@ int ff_hashtable_alloc(struct FFHashtableContext **ctx, size_t key_size, size_t
     const size_t keyval_size = key_size + val_size;
 
     if (keyval_size < key_size || // did (unsigned,defined) wraparound happen?
-        keyval_size > SIZE_MAX - sizeof(size_t) - (ALIGN - 1))
+        keyval_size > FFMIN(SIZE_MAX - sizeof(size_t) - (ALIGN - 1),
+                            (SIZE_MAX - sizeof(FFHashtableContext)) / 2))
         return AVERROR(ERANGE);
 
-    FFHashtableContext *res = av_mallocz(sizeof(*res));
+    FFHashtableContext *res = av_mallocz(sizeof(*res) + 2 * keyval_size);
     if (!res)
         return AVERROR(ENOMEM);
     res->key_size = key_size;
@@ -81,11 +82,6 @@ int ff_hashtable_alloc(struct FFHashtableContext **ctx, size_t key_size, size_t
         return AVERROR(ENOMEM);
     }
 
-    res->swapbuf = av_calloc(2, res->key_size + res->val_size);
-    if (!res->swapbuf) {
-        ff_hashtable_freep(&res);
-        return AVERROR(ENOMEM);
-    }
     *ctx = res;
     return 0;
 }
@@ -208,7 +204,6 @@ void ff_hashtable_freep(struct FFHashtableContext **ctx)
 {
     if (*ctx) {
         av_freep(&(*ctx)->table);
-        av_freep(&(*ctx)->swapbuf);
     }
     av_freep(ctx);
 }
-- 
2.45.2

From 1ad8db9dcd8c0e153477d87111af079fbe344f39 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Tue, 3 Jun 2025 22:47:26 +0200
Subject: [PATCH 7/9] avcodec/hashtable: Mark alloc,free functions as av_cold

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/hashtable.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libavcodec/hashtable.c b/libavcodec/hashtable.c
index 9b37ce3d69..0e9b3d88c2 100644
--- a/libavcodec/hashtable.c
+++ b/libavcodec/hashtable.c
@@ -22,8 +22,10 @@
 #include <stdint.h>
 #include <string.h>
 
+#include "libavutil/attributes.h"
 #include "libavutil/crc.h"
 #include "libavutil/error.h"
+#include "libavutil/macros.h"
 #include "libavutil/mem.h"
 #include "hashtable.h"
 
@@ -54,7 +56,8 @@ struct FFHashtableContext {
 
 #define KEYS_EQUAL(k1, k2) (!memcmp((k1), (k2), ctx->key_size))
 
-int ff_hashtable_alloc(struct FFHashtableContext **ctx, size_t key_size, size_t val_size, size_t max_entries)
+av_cold int ff_hashtable_alloc(FFHashtableContext **ctx, size_t key_size,
+                               size_t val_size, size_t max_entries)
 {
     const size_t keyval_size = key_size + val_size;
 
@@ -200,7 +203,7 @@ void ff_hashtable_clear(struct FFHashtableContext *ctx)
     memset(ctx->table, 0, ctx->entry_size * ctx->max_entries);
 }
 
-void ff_hashtable_freep(struct FFHashtableContext **ctx)
+av_cold void ff_hashtable_freep(FFHashtableContext **ctx)
 {
     if (*ctx) {
         av_freep(&(*ctx)->table);
-- 
2.45.2

From 5aca3c9d1c7e981006205c7d74bff7a4707a81e7 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Tue, 3 Jun 2025 22:50:32 +0200
Subject: [PATCH 8/9] avcodec/hashtable: Only free buffer if there is buffer to
 free

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/hashtable.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/hashtable.c b/libavcodec/hashtable.c
index 0e9b3d88c2..0d5c816cd7 100644
--- a/libavcodec/hashtable.c
+++ b/libavcodec/hashtable.c
@@ -207,6 +207,6 @@ av_cold void ff_hashtable_freep(FFHashtableContext **ctx)
 {
     if (*ctx) {
         av_freep(&(*ctx)->table);
+        av_freep(ctx);
     }
-    av_freep(ctx);
 }
-- 
2.45.2

From ca0cfc25b57a097221334316bc09384476840a6c Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
Date: Tue, 3 Jun 2025 23:18:21 +0200
Subject: [PATCH 9/9] avcodec/hashtable: Remove null statement

Signed-off-by: Andreas Rheinhardt <andreas.rheinha...@outlook.com>
---
 libavcodec/hashtable.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/hashtable.c b/libavcodec/hashtable.c
index 0d5c816cd7..d18e872f4f 100644
--- a/libavcodec/hashtable.c
+++ b/libavcodec/hashtable.c
@@ -194,7 +194,7 @@ int ff_hashtable_delete(struct FFHashtableContext *ctx, const void *key)
                 entry = next_entry;
             }
         }
-    };
+    }
     return 0;
 }
 
-- 
2.45.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to