java-topology/defects/ffmpeg/patch/ffmpeg-0001.patch

134 lines
5.1 KiB
Diff

# UNDF: UNDF-2026-000000070
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -131,22 +131,108 @@
/**********************************************************/
+/*
+ * CWE-407 fix: replace O(N) linear codec tag array scans with O(1) hash-map
+ * lookups. Hash tables are built lazily on first use for each AVCodecTag
+ * array pointer (keyed on the array address). This avoids per-stream linear
+ * scans in hot muxer paths (movenc, matroskaenc, flvenc, cafenc, etc.).
+ *
+ * Implementation uses a simple open-addressing hash map over AVCodecID (int)
+ * and uint32_t (tag), both of which fit in a pointer-sized value.
+ */
+
+#include "libavutil/mem.h"
+#include <pthread.h>
+
+#define CODEC_TAG_HASH_BITS 10
+#define CODEC_TAG_HASH_SIZE (1 << CODEC_TAG_HASH_BITS)
+#define CODEC_TAG_HASH_MASK (CODEC_TAG_HASH_SIZE - 1)
+
+typedef struct {
+ enum AVCodecID id;
+ unsigned int tag;
+} CodecTagEntry;
+
+typedef struct CodecTagIndex {
+ const AVCodecTag *src; /* pointer to the source array */
+ CodecTagEntry *id2tag; /* hash: codec_id -> tag */
+ CodecTagEntry *tag2id; /* hash: tag -> codec_id */
+ struct CodecTagIndex *next;
+} CodecTagIndex;
+
+static CodecTagIndex *codec_tag_index_list = NULL;
+static pthread_mutex_t codec_tag_index_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static CodecTagIndex *codec_tag_index_build(const AVCodecTag *tags)
+{
+ CodecTagIndex *idx = av_mallocz(sizeof(*idx));
+ if (!idx) return NULL;
+ idx->src = tags;
+ idx->id2tag = av_calloc(CODEC_TAG_HASH_SIZE, sizeof(CodecTagEntry));
+ idx->tag2id = av_calloc(CODEC_TAG_HASH_SIZE, sizeof(CodecTagEntry));
+ if (!idx->id2tag || !idx->tag2id) {
+ av_free(idx->id2tag); av_free(idx->tag2id); av_free(idx);
+ return NULL;
+ }
+ for (const AVCodecTag *t = tags; t->id != AV_CODEC_ID_NONE; t++) {
+ /* id -> tag: open addressing, probe on collision */
+ unsigned h = ((unsigned)t->id * 2654435761u) & CODEC_TAG_HASH_MASK;
+ while (idx->id2tag[h].id != AV_CODEC_ID_NONE &&
+ idx->id2tag[h].id != t->id)
+ h = (h + 1) & CODEC_TAG_HASH_MASK;
+ if (idx->id2tag[h].id == AV_CODEC_ID_NONE) {
+ idx->id2tag[h].id = t->id;
+ idx->id2tag[h].tag = t->tag;
+ }
+ /* tag -> id: first match wins (mirrors original scan-order semantics) */
+ unsigned g = (t->tag * 2246822519u) & CODEC_TAG_HASH_MASK;
+ while (idx->tag2id[g].id != AV_CODEC_ID_NONE)
+ g = (g + 1) & CODEC_TAG_HASH_MASK;
+ idx->tag2id[g].id = t->id;
+ idx->tag2id[g].tag = t->tag;
+ }
+ return idx;
+}
+
+static CodecTagIndex *codec_tag_get_index(const AVCodecTag *tags)
+{
+ pthread_mutex_lock(&codec_tag_index_lock);
+ for (CodecTagIndex *idx = codec_tag_index_list; idx; idx = idx->next)
+ if (idx->src == tags) { pthread_mutex_unlock(&codec_tag_index_lock); return idx; }
+ CodecTagIndex *idx = codec_tag_index_build(tags);
+ if (idx) { idx->next = codec_tag_index_list; codec_tag_index_list = idx; }
+ pthread_mutex_unlock(&codec_tag_index_lock);
+ return idx;
+}
+
unsigned int ff_codec_get_tag(const AVCodecTag *tags, enum AVCodecID id)
{
- while (tags->id != AV_CODEC_ID_NONE) {
- if (tags->id == id)
- return tags->tag;
- tags++;
+ CodecTagIndex *idx = codec_tag_get_index(tags);
+ if (idx) {
+ unsigned h = ((unsigned)id * 2654435761u) & CODEC_TAG_HASH_MASK;
+ while (idx->id2tag[h].id != AV_CODEC_ID_NONE) {
+ if (idx->id2tag[h].id == id) return idx->id2tag[h].tag;
+ h = (h + 1) & CODEC_TAG_HASH_MASK;
+ }
+ return 0;
}
- return 0;
+ /* fallback: original linear scan if index alloc failed */
+ while (tags->id != AV_CODEC_ID_NONE) {
+ if (tags->id == id) return tags->tag;
+ tags++;
+ }
+ return 0; /* FALLBACK */
}
enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag)
{
- for (int i = 0; tags[i].id != AV_CODEC_ID_NONE; i++)
- if (tag == tags[i].tag)
- return tags[i].id;
- for (int i = 0; tags[i].id != AV_CODEC_ID_NONE; i++)
- if (ff_toupper4(tag) == ff_toupper4(tags[i].tag))
- return tags[i].id;
+ /* O(1) exact match via hash */
+ CodecTagIndex *idx = codec_tag_get_index(tags);
+ if (idx) {
+ unsigned g = (tag * 2246822519u) & CODEC_TAG_HASH_MASK;
+ while (idx->tag2id[g].id != AV_CODEC_ID_NONE) {
+ if (idx->tag2id[g].tag == tag) return idx->tag2id[g].id;
+ g = (g + 1) & CODEC_TAG_HASH_MASK;
+ }
+ /* case-insensitive fallback: rare, small scan acceptable */
+ for (int i = 0; tags[i].id != AV_CODEC_ID_NONE; i++)
+ if (ff_toupper4(tag) == ff_toupper4(tags[i].tag))
+ return tags[i].id;
+ return AV_CODEC_ID_NONE;
+ }
+ /* fallback */
+ for (int i = 0; tags[i].id != AV_CODEC_ID_NONE; i++)
+ if (tag == tags[i].tag) return tags[i].id;
+ for (int i = 0; tags[i].id != AV_CODEC_ID_NONE; i++)
+ if (ff_toupper4(tag) == ff_toupper4(tags[i].tag)) return tags[i].id;
return AV_CODEC_ID_NONE;
}