import java.util.*; /** * Java simulation of Ruby MRI CWE-407 defect. * * ruby-0001: class.c do_include_modules_at super chain linear scan O(M*S) * For each module to include, walks entire super chain to check if * module's method table is already present. O(M * S) total. * Fix: st_table (hash set) of method table pointers for O(1) lookup. */ public class RubyTest { /** * Simulate module include with linear super chain scan. * DEFECTIVE: O(M * S) — for each of M modules, scan S super entries. */ static long includeModulesDefective(int numModules, int superChainLen) { // Simulate super chain as list of "method table pointers" (ints) List superChain = new ArrayList<>(); for (int i = 0; i < superChainLen; i++) { superChain.add(i); // existing iclass method tables } long ops = 0; // Include M new modules for (int m = 0; m < numModules; m++) { int moduleMTbl = superChainLen + m; // new module's method table boolean found = false; // Linear scan of super chain — O(S) for (int s = 0; s < superChain.size(); s++) { ops++; if (superChain.get(s) == moduleMTbl) { found = true; break; } } if (!found) { superChain.add(moduleMTbl); // Insert new iclass } } return ops; } /** * FIXED: O(M) — hash set for method table membership check. */ static long includeModulesFixed(int numModules, int superChainLen) { List superChain = new ArrayList<>(); Set mtblSet = new HashSet<>(); for (int i = 0; i < superChainLen; i++) { superChain.add(i); mtblSet.add(i); } long ops = 0; for (int m = 0; m < numModules; m++) { int moduleMTbl = superChainLen + m; ops++; // O(1) hash lookup boolean found = mtblSet.contains(moduleMTbl); if (!found) { superChain.add(moduleMTbl); mtblSet.add(moduleMTbl); } } return ops; } static void test0001() { System.out.println("=== ruby-0001: do_include_modules_at super chain scan ==="); int[][] params = { {10, 20}, // M=10 modules, S=20 super chain {20, 50}, // M=20, S=50 (typical Rails) {30, 80}, // M=30, S=80 (heavy Rails) {50, 100}, // M=50, S=100 (extreme) }; for (int[] p : params) { int M = p[0], S = p[1]; long defOps = includeModulesDefective(M, S); long fixOps = includeModulesFixed(M, S); double ratio = (double) defOps / fixOps; System.out.printf(" M=%2d S=%3d: defective=%6d fixed=%3d ratio=%.1fx%n", M, S, defOps, fixOps, ratio); if (M >= 20 && ratio < 5.0) { throw new AssertionError("Expected ratio >= 5x at M=" + M + " S=" + S + ", got " + ratio); } } // Verify growth is proportional to M*S long ops_20_50 = includeModulesDefective(20, 50); long ops_50_100 = includeModulesDefective(50, 100); double growth = (double) ops_50_100 / ops_20_50; System.out.printf(" Growth (20,50)->(50,100): %.1fx (expect ~5x for O(M*S))%n", growth); if (growth < 3.0) { throw new AssertionError("Expected M*S growth, got " + growth + "x"); } System.out.println(" PASS"); } public static void main(String[] args) { test0001(); System.out.println("\nAll Ruby CWE-407 tests PASSED"); } }