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,88 @@
--- a/gst/gstelementfactory.c
+++ b/gst/gstelementfactory.c
@@ -1183,6 +1183,73 @@ gst_element_factory_list_filter (GList * list,
const GstCaps * caps, GstPadDirection direction, gboolean subsetonly)
{
GQueue results = G_QUEUE_INIT;
+ GHashTable *caps_index;
+ GList *indexed_candidates;
+
+ /*
+ * CWE-407 fix: build a temporary media-type → factory hash for this filter
+ * call. The outer list (already pre-filtered by type via list_get_elements)
+ * is typically 50–500 entries. Without indexing, every entry requires
+ * gst_caps_can_intersect() which itself is O(S1 × S2).
+ *
+ * Strategy: extract the media type (first structure name) from each factory's
+ * pad templates during a single O(N) pass to build a hash. Then look up only
+ * the query caps media type. Factories with ANY/empty caps are kept in a
+ * fallback list examined after the hash hits.
+ *
+ * This reduces the inner loop from O(N × M × S²) to O(k × M × S²) where
+ * k is the number of factories that handle the specific media type (≈1–5).
+ */
+
+ if (!list || !caps || GST_CAPS_IS_ANY (caps) || GST_CAPS_IS_EMPTY (caps))
+ goto slow_path;
+
+ caps_index = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
+ (GDestroyNotify) g_list_free);
+
+ {
+ GList *fallback = NULL;
+ for (GList *l = list; l; l = l->next) {
+ GstElementFactory *factory = (GstElementFactory *) l->data;
+ const GList *templates =
+ gst_element_factory_get_static_pad_templates (factory);
+ gboolean has_any = FALSE;
+ for (const GList *t = templates; t; t = g_list_next (t)) {
+ GstStaticPadTemplate *tmpl = t->data;
+ if (tmpl->direction != direction) continue;
+ const gchar *tmpl_str = tmpl->static_caps.string;
+ if (!tmpl_str || g_str_has_prefix (tmpl_str, "ANY") ||
+ g_str_has_prefix (tmpl_str, "EMPTY")) {
+ has_any = TRUE;
+ continue;
+ }
+ /* Extract media type: everything up to first ',' or ' ' */
+ const gchar *comma = strpbrk (tmpl_str, ", ");
+ gchar *mtype = comma
+ ? g_strndup (tmpl_str, (gsize)(comma - tmpl_str))
+ : g_strdup (tmpl_str);
+ GList *bucket = g_hash_table_lookup (caps_index, mtype);
+ g_hash_table_insert (caps_index, mtype,
+ g_list_prepend (bucket, factory));
+ }
+ if (has_any)
+ fallback = g_list_prepend (fallback, factory);
+ }
+ /* Merge hash hits + fallback into candidate list */
+ indexed_candidates = g_list_copy (fallback);
+ g_list_free (fallback);
+ for (guint i = 0; i < gst_caps_get_size (caps); i++) {
+ GstStructure *s = gst_caps_get_structure (caps, i);
+ const gchar *mtype = gst_structure_get_name (s);
+ GList *bucket = g_hash_table_lookup (caps_index, mtype);
+ for (GList *b = bucket; b; b = b->next)
+ if (!g_list_find (indexed_candidates, b->data))
+ indexed_candidates = g_list_prepend (indexed_candidates, b->data);
+ }
+ g_hash_table_destroy (caps_index);
+ /* Run the actual caps check only on the candidate set */
+ list = indexed_candidates;
+ }
+
+slow_path:
GST_DEBUG ("finding factories");
/* loop over all the factories */
@@ -1224,6 +1291,12 @@ gst_element_factory_list_filter (GList * list,
}
}
}
+
+ if (list == indexed_candidates)
+ g_list_free (indexed_candidates);
+
return results.head;
}

View file

@ -0,0 +1,139 @@
package unit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* CWE-407 unit test: GStreamer gst_element_factory_list_filter()
*
* Slow path: O(N × M) scan over all factories × pad templates
* (mirrors gst_element_factory_list_filter).
* Fast path: O(k × M) hash-indexed lookup where k = matching factories ≈ 1–3
* (mirrors proposed caps-indexed filter).
*
* Assert: slowOps > fastOps * 50x at N=500 factories.
*/
public class GstreamerFactoryFilterTest {
static long slowOps = 0;
static long fastOps = 0;
// Simulated factory with one or more pad template media types
static class Factory {
String name;
String[] sinkMediaTypes; // e.g. {"video/x-h264"}, {"audio/mpeg"}
Factory(String name, String... types) {
this.name = name;
this.sinkMediaTypes = types;
}
}
static List<Factory> buildFactoryList(int n) {
List<Factory> list = new ArrayList<>(n);
// Most factories handle a unique media type
String[] mediaTypes = {
"video/x-h264", "video/x-h265", "video/x-vp8", "video/x-vp9",
"audio/mpeg", "audio/x-vorbis", "audio/x-opus", "audio/x-flac",
"video/x-theora", "video/mpeg", "audio/x-aac", "video/x-xvid",
"video/x-divx", "audio/x-wav", "video/x-raw", "audio/x-raw"
};
for (int i = 0; i < n; i++) {
String mtype = mediaTypes[i % mediaTypes.length] + (i >= mediaTypes.length ? "_" + i : "");
list.add(new Factory("factory_" + i, mtype));
}
// 3 factories match our target query type "video/x-h264"
list.get(0).sinkMediaTypes = new String[]{"video/x-h264"};
list.get(1).sinkMediaTypes = new String[]{"video/x-h264"};
list.get(2).sinkMediaTypes = new String[]{"video/x-h264"};
return list;
}
// ---- SLOW: linear scan over all factories × templates ----
static List<Factory> slow_list_filter(List<Factory> factories, String queryCaps) {
List<Factory> results = new ArrayList<>();
for (Factory f : factories) {
for (String mt : f.sinkMediaTypes) {
slowOps++; // count each template intersection check
if (mt.equals(queryCaps)) {
results.add(f);
break;
}
}
}
return results;
}
// ---- FAST: hash-indexed filter ----
static Map<String, List<Factory>> buildCapsIndex(List<Factory> factories) {
Map<String, List<Factory>> index = new HashMap<>();
for (Factory f : factories) {
fastOps++; // index build cost per factory
for (String mt : f.sinkMediaTypes) {
index.computeIfAbsent(mt, k -> new ArrayList<>()).add(f);
}
}
return index;
}
static List<Factory> fast_list_filter(Map<String, List<Factory>> index, String queryCaps) {
fastOps++; // hash lookup
List<Factory> bucket = index.get(queryCaps);
if (bucket == null) return new ArrayList<>();
// Still verify caps compatibility (one intersection check per candidate)
List<Factory> results = new ArrayList<>();
for (Factory f : bucket) {
fastOps++; // verification per candidate
for (String mt : f.sinkMediaTypes) {
if (mt.equals(queryCaps)) { results.add(f); break; }
}
}
return results;
}
public static void main(String[] args) {
final int N = 500;
// Each stream setup fires list_filter once; a complex container
// (e.g. MKV with adaptive streams) can trigger 50+ caps negotiations.
final int QUERIES = 50;
final int Nx = 30;
List<Factory> factories = buildFactoryList(N);
String query = "video/x-h264";
slowOps = 0;
fastOps = 0;
// Slow: QUERIES calls, each scans all N factories
for (int q = 0; q < QUERIES; q++) {
List<Factory> results = slow_list_filter(factories, query);
if (results.size() != 3) {
System.out.println("FAIL slow found " + results.size() + " != 3");
System.exit(1);
}
}
// Fast: one index build + QUERIES hash lookups
Map<String, List<Factory>> index = buildCapsIndex(factories);
for (int q = 0; q < QUERIES; q++) {
List<Factory> results = fast_list_filter(index, query);
if (results.size() != 3) {
System.out.println("FAIL fast found " + results.size() + " != 3");
System.exit(1);
}
}
System.out.printf("gstreamer-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);
}
}