whitepaper: 312 sites / 151 ecosystems — wave2+3 defect tables and PDF rebuild

Add 88 new defect entries to HIGH and MEDIUM tables:
  HIGH: mysql-0001/0002, mariadb-0001, redis-0001/0002, valkey-0001/0002, openvpn-0001,
        vlc-0001, prometheus-0001, otel-collector-0001, cockroachdb-0001..0004,
        tidb-0001..0008, kubernetes-0001/0002, go-0001, kotlin-0002, scala-0001,
        allegro5-0001, sdl2-0001, grafana-0001, clickhouse-0001, duckdb-0001,
        mongodb-0001, envoy-0001, istio-0001, cilium-0001, linkerd2-0001,
        linux-0001/0002/0003, tor-0002/0003, curl-0001, julia-0001, lua-0001,
        perl5-0001, nats-0001, spring-0003/0004, tomcat-0001, onos-0002, odl-0002

  MEDIUM: helm-0001, mariadb-0002, openssl-0001/0002, memcached-0001,
          cassandra-0001..0004, flink-0001, storm-0001/0002, zookeeper-0001..0003,
          pip-0001, gradle-0001, nginx-0001, haproxy-0001, caddy-0001, varnish-0001,
          ffmpeg-0001, gstreamer-0001, raylib-0001, love2d-0001, php-0001/0002,
          r-source-0001, cpython-0002, ruby-0001, rabbitmq-0003/0004, activemq-0001,
          ovs-0001, onos-0003, odl-0002, jetty-0001

PDF: 976K
This commit is contained in:
russell@unturf.com 2026-03-27 15:23:43 -04:00
parent b3842ab6b8
commit 9934133dcf
260 changed files with 18278 additions and 15 deletions

View file

@ -0,0 +1,133 @@
--- 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;
}

View file

@ -0,0 +1,100 @@
package unit;
import java.util.HashMap;
import java.util.Map;
/**
* CWE-407 unit test: FFmpeg ff_codec_get_tag / ff_codec_get_id
*
* Slow path: O(N) linear scan over codec tag array.
* Fast path: O(1) HashMap lookup.
*
* Assert: slow operation count > fast operation count * 20x at N=500.
*/
public class FFmpegCodecTagTest {
// Simulated AVCodecTag entry
static final int CODEC_ID_NONE = 0;
static int[] buildIdArray(int n) {
// codec IDs 1..n, shuffled in reverse order (worst-case scan)
int[] arr = new int[n + 1];
for (int i = 0; i < n; i++) arr[i] = n - i; // reverse: ID n is at index 0
arr[n] = CODEC_ID_NONE; // sentinel
return arr;
}
static int[] buildTagArray(int n) {
int[] arr = new int[n + 1];
for (int i = 0; i < n; i++) arr[i] = 0x100 + (n - i); // tag for id[i]
arr[n] = CODEC_ID_NONE;
return arr;
}
// ---- SLOW: linear scan (mirrors ff_codec_get_tag) ----
static long slowOps = 0;
static int slow_codec_get_tag(int[] ids, int[] tags, int targetId) {
for (int i = 0; ids[i] != CODEC_ID_NONE; i++) {
slowOps++;
if (ids[i] == targetId) return tags[i];
}
return 0;
}
// ---- FAST: hash map lookup ----
static long fastOps = 0;
static Map<Integer, Integer> buildHashMap(int[] ids, int[] tags) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; ids[i] != CODEC_ID_NONE; i++) {
fastOps++; // count build ops once
map.put(ids[i], tags[i]);
}
return map;
}
static int fast_codec_get_tag(Map<Integer, Integer> map, int targetId) {
fastOps++;
Integer v = map.get(targetId);
return v == null ? 0 : v;
}
public static void main(String[] args) {
final int N = 500; // realistic: ff_codec_bmp_tags has 460 entries
final int QUERIES = 50; // queries per mux operation (50 streams)
final int Nx = 20; // assert slowOps > fastOps * Nx
int[] ids = buildIdArray(N);
int[] tags = buildTagArray(N);
// Reset counters
slowOps = 0;
fastOps = 0;
// Slow: QUERIES linear scans, each worst-case (target at end of array)
for (int q = 0; q < QUERIES; q++) {
int target = 1; // ID=1 is at index N-1 in reverse array — worst case
int tag = slow_codec_get_tag(ids, tags, target);
if (tag == 0) { System.out.println("FAIL slow returned 0 for id=1"); System.exit(1); }
}
// Fast: one build + QUERIES hash lookups
Map<Integer, Integer> map = buildHashMap(ids, tags);
for (int q = 0; q < QUERIES; q++) {
int tag = fast_codec_get_tag(map, 1);
if (tag == 0) { System.out.println("FAIL fast returned 0 for id=1"); System.exit(1); }
}
System.out.printf("ffmpeg-0001: slowOps=%d fastOps=%d ratio=%.1f%n",
slowOps, fastOps, (double) slowOps / fastOps);
if (slowOps <= fastOps * Nx) {
System.out.printf("FAIL: expected slowOps > fastOps * %d%n", Nx);
System.exit(1);
}
System.out.printf("1/1 PASS (slowOps=%d > fastOps*%d=%d)%n",
slowOps, Nx, fastOps * Nx);
}
}