import java.util.*; /** * CWE-407 simulation tests for Ardour defects. * * ardour-0001: PluginManager blacklist/rescan PluginInfoList O(I * N) * * PluginManager::blacklist() and ::rescan_plugin() in plugin_manager.cc * iterate over I entries from the scan log for the path being processed and * call std::find on pil (the master PluginInfoList with N entries) for each. * std::find on std::list is O(N) per call, giving O(I * N) total. * * In a studio with 500 VST3 plugins, blacklisting a bundle with I=10 entries * costs 5000 pointer comparisons instead of 510 (O(N+I) for the fixed version). * * Fix: build an unordered_set of the I entries to remove, then do one * remove_if pass over pil — O(N + I) total. * * Both blacklist() and rescan_plugin() share the same pattern and both * need the same fix. */ public class ArdourTest { // --------------------------------------------------------------- // ardour-0001: PluginInfoList std::find inside scan-log loop // --------------------------------------------------------------- /** * Simulate defective removal: for each of I entries to remove, * std::find scans all N entries in pil = O(I * N). * * @param pil total number of plugins in master PluginInfoList * @param toRemove number of plugins to remove from this scan log entry * @return total comparison operations */ static long blacklistDefective(int pil, int toRemove) { long ops = 0; // Simulate worst case: each to-remove entry is found at end of pil for (int i = 0; i < toRemove; i++) { // std::find scans from begin() to the found element (worst case: N) for (int k = 0; k < pil; k++) { ops++; } pil--; // list shrinks after erase } return ops; } /** * Simulate fixed removal: build unordered_set of I entries (O(I)), * then single remove_if pass over pil (O(N)) = O(N + I) total. * * @param pil total number of plugins in master PluginInfoList * @param toRemove number of plugins to remove from this scan log entry * @return total comparison operations */ static long blacklistFixed(int pil, int toRemove) { long ops = 0; // Build unordered_set: O(I) inserts ops += toRemove; // remove_if pass: O(N) hash lookups (O(1) each) ops += pil; return ops; } static void testBlacklistSmallBundle() { // Typical: 500 VST3 plugins, blacklisting a bundle with 5 variants int N = 500; int I = 5; long defectOps = blacklistDefective(N, I); long fixedOps = blacklistFixed(N, I); double ratio = (double) defectOps / fixedOps; System.out.printf("ardour-0001 blacklist small bundle (N=%d plugins, I=%d entries):%n", N, I); System.out.printf(" defect_ops=%d fixed_ops=%d ratio=%.1fx%n", defectOps, fixedOps, ratio); assert ratio > 2.0 : "Expected overhead, got " + ratio; System.out.println(" PASS"); } static void testBlacklistLargeScan() { // Stress case: 1000 plugins, rescan of bundle with 20 entries int N = 1000; int I = 20; long defectOps = blacklistDefective(N, I); long fixedOps = blacklistFixed(N, I); double ratio = (double) defectOps / fixedOps; System.out.printf("ardour-0001 blacklist large scan (N=%d plugins, I=%d entries):%n", N, I); System.out.printf(" defect_ops=%d fixed_ops=%d ratio=%.1fx%n", defectOps, fixedOps, ratio); assert ratio > 5.0 : "Expected significant overhead, got " + ratio; System.out.println(" PASS"); } static void testRescanPlugin() { // rescan_plugin() same pattern as blacklist() // 800 LADSPA plugins, rescan with I=15 entries int N = 800; int I = 15; long defectOps = blacklistDefective(N, I); long fixedOps = blacklistFixed(N, I); double ratio = (double) defectOps / fixedOps; System.out.printf("ardour-0001 rescan_plugin (N=%d plugins, I=%d entries):%n", N, I); System.out.printf(" defect_ops=%d fixed_ops=%d ratio=%.1fx%n", defectOps, fixedOps, ratio); assert ratio > 5.0 : "Expected significant overhead, got " + ratio; System.out.println(" PASS"); } // --------------------------------------------------------------- // Main // --------------------------------------------------------------- public static void main(String[] args) { testBlacklistSmallBundle(); testBlacklistLargeScan(); testRescanPlugin(); System.out.println("\nAll Ardour CWE-407 tests PASS"); } }