import java.util.*; /** * CWE-407 simulation: FreeSWITCH switch_loadable_module_get_codecs_sorted * O(N²) codec preference deduplication. * * Defect: switch_loadable_module_get_codecs_sorted() iterates prefs[0..preflen) * and for each entry x, re-parses prefs[0..x-1] via switch_parse_codec_buf * to check for duplicates — O(N²) with N = number of codec preferences. * * This function is called on every SIP call setup (switch_core_media_prepare_codecs). * With N=SWITCH_MAX_CODECS=50 and high call volumes, this becomes a hot inner loop. * * Fix: pre-parse all prefs into a struct array in one O(N) pass, then check * against the pre-parsed array — eliminates redundant string parsing from O(N²) * to O(N) parsing + O(N²) comparison (but compare is just strcmp not full parse). */ public class FreeSWITCHTest { // Simulate a parsed codec preference entry (simplified) static class CodecPref { final String name; final int interval; final int rate; final int channels; final String fmtp; CodecPref(String spec) { // Simulate switch_parse_codec_buf: "PCMU@20i@8000h" → name=PCMU, interval=20, rate=8000 String[] parts = spec.split("@"); this.name = parts[0]; int iv = 0, r = 0, ch = 1; String fmt = ""; for (int i = 1; i < parts.length; i++) { String p = parts[i]; if (p.endsWith("i")) iv = Integer.parseInt(p.substring(0, p.length()-1)); else if (p.endsWith("h")) r = Integer.parseInt(p.substring(0, p.length()-1)); else if (p.endsWith("c")) ch = Integer.parseInt(p.substring(0, p.length()-1)); else fmt = p; } this.interval = iv == 0 ? defaultPtime(name) : iv; this.rate = r == 0 ? defaultRate(name) : r; this.channels = ch; this.fmtp = fmt; } static int defaultPtime(String name) { return 20; } static int defaultRate(String name) { return 8000; } boolean matches(CodecPref o) { return this.name.equalsIgnoreCase(o.name) && this.interval == o.interval && this.rate == o.rate && this.channels == o.channels && this.fmtp.equalsIgnoreCase(o.fmtp); } } // --- Defect: re-parse each prefs[j] for every x (O(N²) parsing) --- static List deduplicateDefect(String[] prefs) { List result = new ArrayList<>(); for (int x = 0; x < prefs.length; x++) { CodecPref cur = new CodecPref(prefs[x]); // parse prefs[x] boolean dup = false; for (int j = 0; j < x; j++) { CodecPref prev = new CodecPref(prefs[j]); // re-parse prefs[j] every time! if (cur.matches(prev)) { dup = true; break; } } if (!dup) result.add(prefs[x]); } return result; } // --- Fix: pre-parse all prefs once, then O(N²) compare only --- static List deduplicateFix(String[] prefs) { // Pre-pass: parse once CodecPref[] parsed = new CodecPref[prefs.length]; for (int i = 0; i < prefs.length; i++) { parsed[i] = new CodecPref(prefs[i]); } // Dedup using pre-parsed structs List result = new ArrayList<>(); outer: for (int x = 0; x < prefs.length; x++) { for (int j = 0; j < x; j++) { if (parsed[x].matches(parsed[j])) continue outer; } result.add(prefs[x]); } return result; } static String[] buildPrefs(int n, int dupRate) { // Build N codec prefs; dupRate% are duplicates String[] base = {"PCMU@20i@8000h", "PCMA@20i@8000h", "G729@20i@8000h", "G722@20i@16000h", "OPUS@20i@48000h", "G723@30i@8000h", "G726@20i@8000h", "GSM@20i@8000h", "ILBC@30i@8000h", "G728@20i@8000h"}; String[] prefs = new String[n]; Random rng = new Random(42); for (int i = 0; i < n; i++) { if (i > 0 && rng.nextInt(100) < dupRate) { prefs[i] = prefs[rng.nextInt(i)]; // duplicate } else { prefs[i] = base[i % base.length] + (i >= base.length ? "@v" + i : ""); } } return prefs; } static long timeDefect(String[] prefs, int iterations) { long start = System.nanoTime(); for (int i = 0; i < iterations; i++) deduplicateDefect(prefs); return System.nanoTime() - start; } static long timeFix(String[] prefs, int iterations) { long start = System.nanoTime(); for (int i = 0; i < iterations; i++) deduplicateFix(prefs); return System.nanoTime() - start; } public static void main(String[] args) { System.out.println("=== CWE-407: FreeSWITCH get_codecs_sorted O(N²) re-parse dedup ==="); System.out.println(); // --- Correctness: both produce same dedup result --- int N = 50; // SWITCH_MAX_CODECS String[] prefs50 = buildPrefs(N, 20); List defectResult = deduplicateDefect(prefs50); List fixResult = deduplicateFix(prefs50); assert defectResult.equals(fixResult) : "Dedup results differ: " + defectResult + " vs " + fixResult; System.out.printf("PASS: defect and fix produce identical dedup (%d → %d unique)%n", N, defectResult.size()); // --- Performance: warm up --- int ITER = 20_000; for (int w = 0; w < 3; w++) { timeDefect(prefs50, ITER); timeFix(prefs50, ITER); } long defectNs = timeDefect(prefs50, ITER); long fixNs = timeFix(prefs50, ITER); double ratio = (double) defectNs / fixNs; System.out.printf("Defect (re-parse O(N²)): %,d ns over %,d iterations%n", defectNs, ITER); System.out.printf("Fix (pre-parse O(N)): %,d ns over %,d iterations%n", fixNs, ITER); System.out.printf("Speedup ratio: %.1fx%n", ratio); System.out.println(); // --- Complexity demo: varies N --- System.out.println("Complexity scaling (20% duplicates):"); System.out.printf(" %-6s %-14s %-14s %-8s%n", "N", "Defect(ns)", "Fix(ns)", "Ratio"); for (int n : new int[]{5, 10, 20, 30, 50}) { String[] p = buildPrefs(n, 20); // warm for (int w = 0; w < 2; w++) { timeDefect(p, ITER); timeFix(p, ITER); } long d = timeDefect(p, ITER); long f = timeFix(p, ITER); System.out.printf(" %-6d %-14d %-14d %-8.1f%n", n, d, f, (double) d / f); } assert ratio >= 1.5 : String.format("Expected speedup >= 1.5x, got %.1fx", ratio); System.out.println(); System.out.println("PASS: all assertions satisfied"); } }