/** * CWE-407 simulation: OBS Studio push_audio_tree da_find O(N²) per audio frame. * * Simulates the defect in libobs/obs-audio.c where push_audio_tree() * and push_audio_tree2() use da_find(audio->render_order, &source, 0) * — a linear scan — to check if a source is already in the render order. * Called once per source during audio tree traversal, this is O(N²) per * audio frame (~47 Hz). With complex scenes (many sources), this causes * measurable audio processing overhead. * * Fix: use a HashSet alongside the render_order list for O(1) membership. */ import java.util.*; public class ObsStudioTest { /* --- Defective path: linear scan per source (da_find) --- */ static int buildRenderOrderDefective(Object[] sources) { int ops = 0; List renderOrder = new ArrayList<>(); for (Object source : sources) { // da_find: linear scan of render_order boolean found = false; for (int i = 0; i < renderOrder.size(); i++) { ops++; if (renderOrder.get(i) == source) { found = true; break; } } if (!found) { renderOrder.add(source); } } return ops; } /* --- Fixed path: hash set for O(1) membership --- */ static int buildRenderOrderFixed(Object[] sources) { int ops = 0; List renderOrder = new ArrayList<>(); Set seen = new HashSet<>(); for (Object source : sources) { ops++; // HashSet.contains is O(1) if (seen.add(source)) { renderOrder.add(source); } } return ops; } public static void main(String[] args) { int[] sizes = {100, 500, 1000}; boolean allPass = true; System.out.println("=== OBS Studio push_audio_tree CWE-407 Test ==="); System.out.printf("%-8s %-12s %-12s %-8s %-6s%n", "N", "Defective", "Fixed", "Ratio", "Pass"); for (int N : sizes) { // Simulate N unique sources being added to render order Object[] sources = new Object[N]; for (int i = 0; i < N; i++) sources[i] = new Object(); int opsDefective = buildRenderOrderDefective(sources); int opsFixed = buildRenderOrderFixed(sources); double ratio = (double) opsDefective / opsFixed; boolean pass = ratio > 2.0; if (!pass) allPass = false; System.out.printf("%-8d %-12d %-12d %-8.1fx %-6s%n", N, opsDefective, opsFixed, ratio, pass ? "PASS" : "FAIL"); } // Simulate repeated frames (the defect runs every audio frame) System.out.println("\n--- Per-second overhead at 47 frames/sec ---"); int N = 200; // realistic complex scene Object[] sources = new Object[N]; for (int i = 0; i < N; i++) sources[i] = new Object(); int perFrameDefective = buildRenderOrderDefective(sources); int perFrameFixed = buildRenderOrderFixed(sources); System.out.printf("N=%d: defective=%d ops/frame × 47 = %d ops/sec%n", N, perFrameDefective, perFrameDefective * 47); System.out.printf("N=%d: fixed=%d ops/frame × 47 = %d ops/sec%n", N, perFrameFixed, perFrameFixed * 47); System.out.println(); if (allPass) { System.out.println("ALL PASS — defective path is quadratic, fixed path is linear"); } else { System.out.println("FAIL — ratio not demonstrated"); System.exit(1); } } }