java-topology/defects/ruby/unit/RubyTest.java

112 lines
3.7 KiB
Java

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<Integer> 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<Integer> superChain = new ArrayList<>();
Set<Integer> 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");
}
}