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:
parent
b3842ab6b8
commit
9934133dcf
260 changed files with 18278 additions and 15 deletions
88
defects/gstreamer/patch/gstreamer-0001.patch
Normal file
88
defects/gstreamer/patch/gstreamer-0001.patch
Normal 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;
|
||||
}
|
||||
139
defects/gstreamer/unit/GstreamerFactoryFilterTest.java
Normal file
139
defects/gstreamer/unit/GstreamerFactoryFilterTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue