java-topology/defects/ffmpeg/unit/Ffmpeg0003MpegtsProgramDiscardTest.java
russell@unturf.com ba818693db nmap-0002 + haproxy-0004 + nginx-0004 + weechat-0003 + zeek-0002 + curl-0004: 6 new CWE-407 defects in network tools; count 693→699
nmap-0002:     nmap.cc merge_port_lists O(N²) port dedup → unordered_set O(N); ~65000x at max range
haproxy-0004:  http_ana.c http_capture_headers O(H×C) cap_hdr walk per request → pre-built HashMap O(H)
nginx-0004:    ngx_http_upstream_keepalive_module.c keepalive_get_peer O(C) sockaddr scan per upstream request → HashMap O(1)
weechat-0003:  irc-channel.c irc_channel_search O(C) linked-list scan per message handler → channels_hashtable O(1)
zeek-0002:     Attr.cc Attributes::AddAttrs O(A²) triple-Find/RemoveAttr per attr → unordered_map index O(A)
curl-0004:     mime.c search_header O(P×H) 3x per part per mime_add_headers → pre-indexed header name set O(P)
2026-03-29 22:22:11 -04:00

169 lines
6.6 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package unit;
import java.util.Arrays;
/**
* Ffmpeg0003MpegtsProgramDiscardTest — CWE-407 ffmpeg-0003
*
* Models discard_pid() in libavformat/mpegts.c:
* slow() = O(P × J × K) inner linear program-id scan (current defect)
* fast() = O(P × J × log K) using sorted arrays + bsearch (patch)
*
* Parameters: K programs, P internal program entries, J pids per entry.
* Assert: slowOps > fastOps * Nx at K=50 programs, P=50, J=10.
*/
public class Ffmpeg0003MpegtsProgramDiscardTest {
static long slowOps;
static long fastOps;
/**
* Slow: O(P × J × K) — models original discard_pid inner loop.
* For each (program, pid) match, linearly scans all K AVPrograms by id.
*/
static int discardPidSlow(int[] prg_ids, int[] prg_pids, boolean[] prg_disc_flag,
int[] avprg_ids, boolean[] avprg_discard,
int target_pid, int nb_prg, int pids_per_prg, int nb_avprg)
{
// Early exit: any discarded?
boolean any_disc = false;
for (int k = 0; k < nb_avprg; k++) {
slowOps++;
if (avprg_discard[k]) { any_disc = true; break; }
}
if (!any_disc) return 0;
int used = 0, discarded = 0;
for (int i = 0; i < nb_prg; i++) {
for (int j = 0; j < pids_per_prg; j++) {
int idx = i * pids_per_prg + j;
if (prg_pids[idx] != target_pid) continue;
// Inner O(K) scan — the defect
for (int k = 0; k < nb_avprg; k++) {
slowOps++;
if (avprg_ids[k] == prg_ids[i]) {
if (avprg_discard[k]) discarded++;
else used++;
}
}
}
}
return (used == 0 && discarded > 0) ? 1 : 0;
}
/**
* Fast: O(K log K + P × J × log K) — models bsearch fix.
* Pre-sorts discarded and used id arrays, then uses binary search.
*/
static int discardPidFast(int[] prg_ids, int[] prg_pids, boolean[] prg_disc_flag,
int[] avprg_ids, boolean[] avprg_discard,
int target_pid, int nb_prg, int pids_per_prg, int nb_avprg)
{
// Build sorted disc_ids and used_ids in O(K)
int[] disc_ids = new int[nb_avprg];
int[] used_ids = new int[nb_avprg];
int nb_disc = 0, nb_used = 0;
for (int k = 0; k < nb_avprg; k++) {
fastOps++;
if (avprg_discard[k]) disc_ids[nb_disc++] = avprg_ids[k];
else used_ids[nb_used++] = avprg_ids[k];
}
if (nb_disc == 0) return 0; // no programs discarded
// Sort O(K log K)
int[] disc_sorted = Arrays.copyOf(disc_ids, nb_disc);
int[] used_sorted = Arrays.copyOf(used_ids, nb_used);
Arrays.sort(disc_sorted);
Arrays.sort(used_sorted);
int used = 0, discarded = 0;
for (int i = 0; i < nb_prg; i++) {
for (int j = 0; j < pids_per_prg; j++) {
int idx = i * pids_per_prg + j;
if (prg_pids[idx] != target_pid) continue;
// O(log K) binary search
fastOps++;
if (nb_disc > 0 && Arrays.binarySearch(disc_sorted, 0, nb_disc, prg_ids[i]) >= 0)
discarded++;
if (nb_used > 0 && Arrays.binarySearch(used_sorted, 0, nb_used, prg_ids[i]) >= 0)
used++;
}
}
return (used == 0 && discarded > 0) ? 1 : 0;
}
public static void main(String[] args) {
final int NX = 5;
// Simulate: K=50 AVPrograms, some discarded
final int K = 50; // nb_programs (AVProgram count)
final int P = 50; // nb_prg (internal Program count)
final int J = 10; // pids_per_program
final int TARGET_PID = 42;
int[] avprg_ids = new int[K];
boolean[] avprg_disc = new boolean[K];
int[] prg_ids = new int[P];
int[] prg_pids = new int[P * J];
// Set up: AVPrograms 0..K-1, mark last 10 as discarded
for (int k = 0; k < K; k++) {
avprg_ids[k] = k + 1000; // IDs 1000..1049
avprg_disc[k] = (k >= K - 10); // last 10 discarded
}
// Internal programs map to AVProgram IDs
for (int i = 0; i < P; i++) {
prg_ids[i] = i + 1000; // matches avprg_ids
for (int j = 0; j < J; j++) {
prg_pids[i * J + j] = (i == 5 && j == 2) ? TARGET_PID : (i * J + j + 1);
}
}
boolean[] dummy_flag = new boolean[P];
// Warm up
slowOps = 0; fastOps = 0;
discardPidSlow(prg_ids, prg_pids, dummy_flag, avprg_ids, avprg_disc,
TARGET_PID, P, J, K);
discardPidFast(prg_ids, prg_pids, dummy_flag, avprg_ids, avprg_disc,
TARGET_PID, P, J, K);
// Measure
slowOps = 0; fastOps = 0;
final int CALLS = 200;
int slowResult = 0, fastResult = 0;
for (int c = 0; c < CALLS; c++) {
slowResult = discardPidSlow(prg_ids, prg_pids, dummy_flag, avprg_ids, avprg_disc,
TARGET_PID, P, J, K);
fastResult = discardPidFast(prg_ids, prg_pids, dummy_flag, avprg_ids, avprg_disc,
TARGET_PID, P, J, K);
}
boolean correctnessOk = (slowResult == fastResult);
boolean speedupOk = slowOps > fastOps * NX;
System.out.printf("K=%d programs, P=%d internal prg, J=%d pids, CALLS=%d%n", K, P, J, CALLS);
System.out.printf("slow (linear scan) ops: %d%n", slowOps);
System.out.printf("fast (bsearch) ops: %d%n", fastOps);
System.out.printf("speedup ratio: %.1fx (required >%dx)%n",
(double) slowOps / fastOps, NX);
System.out.printf("result: slow=%d fast=%d%n", slowResult, fastResult);
int passed = 0, total = 2;
if (correctnessOk) {
System.out.println("1/2 PASS correctness: both return same discard decision");
passed++;
} else {
System.out.printf("1/2 FAIL correctness: slow=%d fast=%d%n", slowResult, fastResult);
}
if (speedupOk) {
System.out.printf("2/2 PASS speedup: %d > %d * %d%n", slowOps, fastOps, NX);
passed++;
} else {
System.out.printf("2/2 FAIL speedup: %d not > %d * %d%n", slowOps, fastOps, NX);
}
System.out.printf("%d/%d PASS%n", passed, total);
if (passed < total) System.exit(1);
}
}